Coverage Report

Created: 2026-06-07 07:11

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/nss/lib/cryptohi/dsautil.c
Line
Count
Source
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
16.8k
{
37
16.8k
    unsigned char *pSrc = src->data;
38
16.8k
    unsigned char *pDst = dest->data;
39
16.8k
    unsigned int cntSrc = src->len;
40
41
    /* skip any leading zeros. */
42
250k
    while (cntSrc && !(*pSrc)) {
43
233k
        pSrc++;
44
233k
        cntSrc--;
45
233k
    }
46
16.8k
    if (!cntSrc) {
47
7.24k
        *pDst = 0;
48
7.24k
        dest->len = 1;
49
7.24k
        return;
50
7.24k
    }
51
52
9.63k
    if (*pSrc & 0x80)
53
4.35k
        *pDst++ = 0;
54
55
9.63k
    PORT_Memcpy(pDst, pSrc, cntSrc);
56
9.63k
    dest->len = (pDst - dest->data) + cntSrc;
57
9.63k
}
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
11.0k
{
71
11.0k
    unsigned char *pSrc = src->data;
72
11.0k
    unsigned char *pDst = dest->data;
73
11.0k
    unsigned int cntSrc = src->len;
74
11.0k
    unsigned int cntDst = dest->len;
75
76
11.0k
    if (cntSrc <= cntDst) {
77
10.9k
        unsigned int zCount = cntDst - cntSrc;
78
10.9k
        PORT_Memset(pDst, 0, zCount);
79
10.9k
        PORT_Memcpy(pDst + zCount, pSrc, cntSrc);
80
10.9k
        return SECSuccess;
81
10.9k
    }
82
    /* Source is longer than destination: extra leading bytes must be zero. */
83
25
    unsigned int extra = cntSrc - cntDst;
84
25
    while (extra--) {
85
25
        if (*pSrc++ != 0)
86
25
            goto loser;
87
25
    }
88
0
    PORT_Memcpy(pDst, pSrc, cntDst);
89
0
    return SECSuccess;
90
91
25
loser:
92
25
    PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
93
25
    return SECFailure;
94
25
}
95
96
/* src is a "raw" ECDSA or DSA signature, the first half contains r
97
 * and the second half contains s. dest is the DER encoded signature.
98
 */
99
static SECStatus
100
common_EncodeDerSig(SECItem *dest, SECItem *src)
101
8.43k
{
102
8.43k
    SECItem *item;
103
8.43k
    SECItem srcItem;
104
8.43k
    DSA_ASN1Signature sig;
105
8.43k
    unsigned char *signedR;
106
8.43k
    unsigned char *signedS;
107
8.43k
    unsigned int len;
108
109
    /* Allocate memory with room for an extra byte that
110
     * may be required if the top bit in the first byte
111
     * is already set.
112
     */
113
8.43k
    len = src->len / 2;
114
8.43k
    signedR = (unsigned char *)PORT_Alloc(len + 1);
115
8.43k
    if (!signedR)
116
0
        return SECFailure;
117
8.43k
    signedS = (unsigned char *)PORT_ZAlloc(len + 1);
118
8.43k
    if (!signedS) {
119
0
        if (signedR)
120
0
            PORT_Free(signedR);
121
0
        return SECFailure;
122
0
    }
123
124
8.43k
    PORT_Memset(&sig, 0, sizeof(sig));
125
126
    /* Must convert r and s from "unsigned" integers to "signed" integers.
127
    ** If the high order bit of the first byte (MSB) is 1, then must
128
    ** prepend with leading zero.
129
    ** Must remove all but one leading zero byte from numbers.
130
    */
131
8.43k
    sig.r.type = siUnsignedInteger;
132
8.43k
    sig.r.data = signedR;
133
8.43k
    sig.r.len = sizeof signedR;
134
8.43k
    sig.s.type = siUnsignedInteger;
135
8.43k
    sig.s.data = signedS;
136
8.43k
    sig.s.len = sizeof signedR;
137
138
8.43k
    srcItem.data = src->data;
139
8.43k
    srcItem.len = len;
140
141
8.43k
    DSAU_ConvertUnsignedToSigned(&sig.r, &srcItem);
142
8.43k
    srcItem.data += len;
143
8.43k
    DSAU_ConvertUnsignedToSigned(&sig.s, &srcItem);
144
145
8.43k
    item = SEC_ASN1EncodeItem(NULL, dest, &sig, DSA_SignatureTemplate);
146
8.43k
    if (signedR)
147
8.43k
        PORT_Free(signedR);
148
8.43k
    if (signedS)
149
8.43k
        PORT_Free(signedS);
150
8.43k
    if (item == NULL)
151
0
        return SECFailure;
152
153
    /* XXX leak item? */
154
8.43k
    return SECSuccess;
155
8.43k
}
156
157
/* src is a DER-encoded ECDSA or DSA signature.
158
** Returns a newly-allocated SECItem structure, pointing at a newly allocated
159
** buffer containing the "raw" signature, which is len bytes of r,
160
** followed by len bytes of s. For DSA, len is the length of q.
161
** For ECDSA, len depends on the key size used to create the signature.
162
*/
163
static SECItem *
164
common_DecodeDerSig(const SECItem *item, unsigned int len)
165
5.82k
{
166
5.82k
    SECItem *result = NULL;
167
5.82k
    PORTCheapArenaPool arena;
168
5.82k
    SECStatus status;
169
5.82k
    DSA_ASN1Signature sig;
170
5.82k
    SECItem dst;
171
172
5.82k
    PORT_Memset(&sig, 0, sizeof(sig));
173
174
    /* Make enough room for r + s. */
175
5.82k
    PORT_InitCheapArena(&arena, PR_MAX(2 * MAX_ECKEY_LEN, DSA_MAX_SIGNATURE_LEN));
176
177
5.82k
    result = PORT_ZNew(SECItem);
178
5.82k
    if (result == NULL)
179
0
        goto loser;
180
181
5.82k
    result->len = 2 * len;
182
5.82k
    result->data = (unsigned char *)PORT_Alloc(2 * len);
183
5.82k
    if (result->data == NULL)
184
0
        goto loser;
185
186
5.82k
    sig.r.type = siUnsignedInteger;
187
5.82k
    sig.s.type = siUnsignedInteger;
188
5.82k
    status = SEC_QuickDERDecodeItem(&arena.arena, &sig, DSA_SignatureTemplate, item);
189
5.82k
    if (status != SECSuccess)
190
289
        goto loser;
191
192
    /* A valid DER INTEGER for r or s is at most len+1 bytes (len bytes of
193
    ** magnitude plus at most one leading zero sign byte).  Reject anything
194
    ** larger before attempting the conversion to avoid pathological inputs. */
195
5.53k
    if (sig.r.len > len + 1 || sig.s.len > len + 1)
196
23
        goto loser;
197
198
    /* Convert sig.r and sig.s from variable  length signed integers to
199
    ** fixed length unsigned integers.
200
    */
201
5.51k
    dst.data = result->data;
202
5.51k
    dst.len = len;
203
5.51k
    status = DSAU_ConvertSignedToFixedUnsigned(&dst, &sig.r);
204
5.51k
    if (status != SECSuccess)
205
13
        goto loser;
206
207
5.50k
    dst.data += len;
208
5.50k
    status = DSAU_ConvertSignedToFixedUnsigned(&dst, &sig.s);
209
5.50k
    if (status != SECSuccess)
210
12
        goto loser;
211
212
5.82k
done:
213
5.82k
    PORT_DestroyCheapArena(&arena);
214
215
5.82k
    return result;
216
217
337
loser:
218
337
    if (result != NULL) {
219
337
        SECITEM_FreeItem(result, PR_TRUE);
220
337
        result = NULL;
221
337
    }
222
337
    goto done;
223
5.50k
}
224
225
/* src is a "raw" DSA1 signature, 20 bytes of r followed by 20 bytes of s.
226
** dest is the signature DER encoded. ?
227
*/
228
SECStatus
229
DSAU_EncodeDerSig(SECItem *dest, SECItem *src)
230
0
{
231
0
    PORT_Assert(src->len == 2 * DSA1_SUBPRIME_LEN);
232
0
    if (src->len != 2 * DSA1_SUBPRIME_LEN) {
233
0
        PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
234
0
        return SECFailure;
235
0
    }
236
237
0
    return common_EncodeDerSig(dest, src);
238
0
}
239
240
/* src is a "raw" DSA signature of length len (len/2 bytes of r followed
241
** by len/2 bytes of s). dest is the signature DER encoded.
242
*/
243
SECStatus
244
DSAU_EncodeDerSigWithLen(SECItem *dest, SECItem *src, unsigned int len)
245
8.43k
{
246
247
8.43k
    PORT_Assert((src->len == len) && (len % 2 == 0));
248
8.43k
    if ((src->len != len) || (src->len % 2 != 0)) {
249
0
        PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
250
0
        return SECFailure;
251
0
    }
252
253
8.43k
    return common_EncodeDerSig(dest, src);
254
8.43k
}
255
256
/* src is a DER-encoded DSA signature.
257
** Returns a newly-allocated SECItem structure, pointing at a newly allocated
258
** buffer containing the "raw" DSA1 signature, which is 20 bytes of r,
259
** followed by 20 bytes of s.
260
*/
261
SECItem *
262
DSAU_DecodeDerSig(const SECItem *item)
263
0
{
264
0
    return common_DecodeDerSig(item, DSA1_SUBPRIME_LEN);
265
0
}
266
267
/* src is a DER-encoded ECDSA signature.
268
** Returns a newly-allocated SECItem structure, pointing at a newly allocated
269
** buffer containing the "raw" ECDSA signature of length len containing
270
** r followed by s (both padded to take up exactly len/2 bytes).
271
*/
272
SECItem *
273
DSAU_DecodeDerSigToLen(const SECItem *item, unsigned int len)
274
5.82k
{
275
5.82k
    return common_DecodeDerSig(item, len / 2);
276
5.82k
}