Coverage Report

Created: 2024-11-21 07:03

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