Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/security/nss/lib/cryptohi/dsautil.c
Line
Count
Source (jump to first uncovered line)
1
/* This Source Code Form is subject to the terms of the Mozilla Public
2
 * License, v. 2.0. If a copy of the MPL was not distributed with this
3
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
#include "cryptohi.h"
5
#include "secasn1.h"
6
#include "secitem.h"
7
#include "prerr.h"
8
9
#ifndef DSA1_SUBPRIME_LEN
10
#define DSA1_SUBPRIME_LEN 20 /* bytes */
11
#endif
12
13
typedef struct {
14
    SECItem r;
15
    SECItem s;
16
} DSA_ASN1Signature;
17
18
const SEC_ASN1Template DSA_SignatureTemplate[] =
19
    {
20
      { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(DSA_ASN1Signature) },
21
      { SEC_ASN1_INTEGER, offsetof(DSA_ASN1Signature, r) },
22
      { SEC_ASN1_INTEGER, offsetof(DSA_ASN1Signature, s) },
23
      { 0 }
24
    };
25
26
/* Input is variable length multi-byte integer, MSB first (big endian).
27
** Most signficant bit of first byte is NOT treated as a sign bit.
28
** May be one or more leading bytes of zeros.
29
** Output is variable length multi-byte integer, MSB first (big endian).
30
** Most significant bit of first byte will be zero (positive sign bit)
31
** No more than one leading zero byte.
32
** Caller supplies dest buffer, and assures that it is long enough,
33
** e.g. at least one byte longer that src's buffer.
34
*/
35
void
36
DSAU_ConvertUnsignedToSigned(SECItem *dest, SECItem *src)
37
0
{
38
0
    unsigned char *pSrc = src->data;
39
0
    unsigned char *pDst = dest->data;
40
0
    unsigned int cntSrc = src->len;
41
0
42
0
    /* skip any leading zeros. */
43
0
    while (cntSrc && !(*pSrc)) {
44
0
        pSrc++;
45
0
        cntSrc--;
46
0
    }
47
0
    if (!cntSrc) {
48
0
        *pDst = 0;
49
0
        dest->len = 1;
50
0
        return;
51
0
    }
52
0
53
0
    if (*pSrc & 0x80)
54
0
        *pDst++ = 0;
55
0
56
0
    PORT_Memcpy(pDst, pSrc, cntSrc);
57
0
    dest->len = (pDst - dest->data) + cntSrc;
58
0
}
59
60
/*
61
** src is a buffer holding a signed variable length integer.
62
** dest is a buffer which will be filled with an unsigned integer,
63
** MSB first (big endian) with leading zeros, so that the last byte
64
** of src will be the LSB of the integer.  The result will be exactly
65
** the length specified by the caller in dest->len.
66
** src can be shorter than dest.  src can be longer than dst, but only
67
** if the extra leading bytes are zeros.
68
*/
69
SECStatus
70
DSAU_ConvertSignedToFixedUnsigned(SECItem *dest, SECItem *src)
71
0
{
72
0
    unsigned char *pSrc = src->data;
73
0
    unsigned char *pDst = dest->data;
74
0
    unsigned int cntSrc = src->len;
75
0
    unsigned int cntDst = dest->len;
76
0
    int zCount = cntDst - cntSrc;
77
0
78
0
    if (zCount > 0) {
79
0
        PORT_Memset(pDst, 0, zCount);
80
0
        PORT_Memcpy(pDst + zCount, pSrc, cntSrc);
81
0
        return SECSuccess;
82
0
    }
83
0
    if (zCount <= 0) {
84
0
        /* Source is longer than destination.  Check for leading zeros. */
85
0
        while (zCount++ < 0) {
86
0
            if (*pSrc++ != 0)
87
0
                goto loser;
88
0
        }
89
0
    }
90
0
    PORT_Memcpy(pDst, pSrc, cntDst);
91
0
    return SECSuccess;
92
0
93
0
loser:
94
0
    PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
95
0
    return SECFailure;
96
0
}
97
98
/* src is a "raw" ECDSA or DSA signature, the first half contains r
99
 * and the second half contains s. dest is the DER encoded signature.
100
*/
101
static SECStatus
102
common_EncodeDerSig(SECItem *dest, SECItem *src)
103
0
{
104
0
    SECItem *item;
105
0
    SECItem srcItem;
106
0
    DSA_ASN1Signature sig;
107
0
    unsigned char *signedR;
108
0
    unsigned char *signedS;
109
0
    unsigned int len;
110
0
111
0
    /* Allocate memory with room for an extra byte that
112
0
     * may be required if the top bit in the first byte
113
0
     * is already set.
114
0
     */
115
0
    len = src->len / 2;
116
0
    signedR = (unsigned char *)PORT_Alloc(len + 1);
117
0
    if (!signedR)
118
0
        return SECFailure;
119
0
    signedS = (unsigned char *)PORT_ZAlloc(len + 1);
120
0
    if (!signedS) {
121
0
        if (signedR)
122
0
            PORT_Free(signedR);
123
0
        return SECFailure;
124
0
    }
125
0
126
0
    PORT_Memset(&sig, 0, sizeof(sig));
127
0
128
0
    /* Must convert r and s from "unsigned" integers to "signed" integers.
129
0
    ** If the high order bit of the first byte (MSB) is 1, then must
130
0
    ** prepend with leading zero.
131
0
    ** Must remove all but one leading zero byte from numbers.
132
0
    */
133
0
    sig.r.type = siUnsignedInteger;
134
0
    sig.r.data = signedR;
135
0
    sig.r.len = sizeof signedR;
136
0
    sig.s.type = siUnsignedInteger;
137
0
    sig.s.data = signedS;
138
0
    sig.s.len = sizeof signedR;
139
0
140
0
    srcItem.data = src->data;
141
0
    srcItem.len = len;
142
0
143
0
    DSAU_ConvertUnsignedToSigned(&sig.r, &srcItem);
144
0
    srcItem.data += len;
145
0
    DSAU_ConvertUnsignedToSigned(&sig.s, &srcItem);
146
0
147
0
    item = SEC_ASN1EncodeItem(NULL, dest, &sig, DSA_SignatureTemplate);
148
0
    if (signedR)
149
0
        PORT_Free(signedR);
150
0
    if (signedS)
151
0
        PORT_Free(signedS);
152
0
    if (item == NULL)
153
0
        return SECFailure;
154
0
155
0
    /* XXX leak item? */
156
0
    return SECSuccess;
157
0
}
158
159
/* src is a DER-encoded ECDSA or DSA signature.
160
** Returns a newly-allocated SECItem structure, pointing at a newly allocated
161
** buffer containing the "raw" signature, which is len bytes of r,
162
** followed by len bytes of s. For DSA, len is the length of q.
163
** For ECDSA, len depends on the key size used to create the signature.
164
*/
165
static SECItem *
166
common_DecodeDerSig(const SECItem *item, unsigned int len)
167
0
{
168
0
    SECItem *result = NULL;
169
0
    PORTCheapArenaPool arena;
170
0
    SECStatus status;
171
0
    DSA_ASN1Signature sig;
172
0
    SECItem dst;
173
0
174
0
    PORT_Memset(&sig, 0, sizeof(sig));
175
0
176
0
    /* Make enough room for r + s. */
177
0
    PORT_InitCheapArena(&arena, PR_MAX(2 * MAX_ECKEY_LEN, DSA_MAX_SIGNATURE_LEN));
178
0
179
0
    result = PORT_ZNew(SECItem);
180
0
    if (result == NULL)
181
0
        goto loser;
182
0
183
0
    result->len = 2 * len;
184
0
    result->data = (unsigned char *)PORT_Alloc(2 * len);
185
0
    if (result->data == NULL)
186
0
        goto loser;
187
0
188
0
    sig.r.type = siUnsignedInteger;
189
0
    sig.s.type = siUnsignedInteger;
190
0
    status = SEC_QuickDERDecodeItem(&arena.arena, &sig, DSA_SignatureTemplate, item);
191
0
    if (status != SECSuccess)
192
0
        goto loser;
193
0
194
0
    /* Convert sig.r and sig.s from variable  length signed integers to
195
0
    ** fixed length unsigned integers.
196
0
    */
197
0
    dst.data = result->data;
198
0
    dst.len = len;
199
0
    status = DSAU_ConvertSignedToFixedUnsigned(&dst, &sig.r);
200
0
    if (status != SECSuccess)
201
0
        goto loser;
202
0
203
0
    dst.data += len;
204
0
    status = DSAU_ConvertSignedToFixedUnsigned(&dst, &sig.s);
205
0
    if (status != SECSuccess)
206
0
        goto loser;
207
0
208
0
done:
209
0
    PORT_DestroyCheapArena(&arena);
210
0
211
0
    return result;
212
0
213
0
loser:
214
0
    if (result != NULL) {
215
0
        SECITEM_FreeItem(result, PR_TRUE);
216
0
        result = NULL;
217
0
    }
218
0
    goto done;
219
0
}
220
221
/* src is a "raw" DSA1 signature, 20 bytes of r followed by 20 bytes of s.
222
** dest is the signature DER encoded. ?
223
*/
224
SECStatus
225
DSAU_EncodeDerSig(SECItem *dest, SECItem *src)
226
0
{
227
0
    PORT_Assert(src->len == 2 * DSA1_SUBPRIME_LEN);
228
0
    if (src->len != 2 * DSA1_SUBPRIME_LEN) {
229
0
        PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
230
0
        return SECFailure;
231
0
    }
232
0
233
0
    return common_EncodeDerSig(dest, src);
234
0
}
235
236
/* src is a "raw" DSA signature of length len (len/2 bytes of r followed
237
** by len/2 bytes of s). dest is the signature DER encoded.
238
*/
239
SECStatus
240
DSAU_EncodeDerSigWithLen(SECItem *dest, SECItem *src, unsigned int len)
241
0
{
242
0
243
0
    PORT_Assert((src->len == len) && (len % 2 == 0));
244
0
    if ((src->len != len) || (src->len % 2 != 0)) {
245
0
        PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
246
0
        return SECFailure;
247
0
    }
248
0
249
0
    return common_EncodeDerSig(dest, src);
250
0
}
251
252
/* src is a DER-encoded DSA signature.
253
** Returns a newly-allocated SECItem structure, pointing at a newly allocated
254
** buffer containing the "raw" DSA1 signature, which is 20 bytes of r,
255
** followed by 20 bytes of s.
256
*/
257
SECItem *
258
DSAU_DecodeDerSig(const SECItem *item)
259
0
{
260
0
    return common_DecodeDerSig(item, DSA1_SUBPRIME_LEN);
261
0
}
262
263
/* src is a DER-encoded ECDSA signature.
264
** Returns a newly-allocated SECItem structure, pointing at a newly allocated
265
** buffer containing the "raw" ECDSA signature of length len containing
266
** r followed by s (both padded to take up exactly len/2 bytes).
267
*/
268
SECItem *
269
DSAU_DecodeDerSigToLen(const SECItem *item, unsigned int len)
270
0
{
271
0
    return common_DecodeDerSig(item, len / 2);
272
0
}