Coverage Report

Created: 2026-02-18 06:59

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
18.9k
{
37
18.9k
    unsigned char *pSrc = src->data;
38
18.9k
    unsigned char *pDst = dest->data;
39
18.9k
    unsigned int cntSrc = src->len;
40
41
    /* skip any leading zeros. */
42
253k
    while (cntSrc && !(*pSrc)) {
43
234k
        pSrc++;
44
234k
        cntSrc--;
45
234k
    }
46
18.9k
    if (!cntSrc) {
47
7.21k
        *pDst = 0;
48
7.21k
        dest->len = 1;
49
7.21k
        return;
50
7.21k
    }
51
52
11.6k
    if (*pSrc & 0x80)
53
8.68k
        *pDst++ = 0;
54
55
11.6k
    PORT_Memcpy(pDst, pSrc, cntSrc);
56
11.6k
    dest->len = (pDst - dest->data) + cntSrc;
57
11.6k
}
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
11.0k
    int zCount = cntDst - cntSrc;
76
77
11.0k
    if (zCount > 0) {
78
8.19k
        PORT_Memset(pDst, 0, zCount);
79
8.19k
        PORT_Memcpy(pDst + zCount, pSrc, cntSrc);
80
8.19k
        return SECSuccess;
81
8.19k
    }
82
2.83k
    if (zCount <= 0) {
83
        /* Source is longer than destination.  Check for leading zeros. */
84
2.83k
        while (zCount++ < 0) {
85
54
            if (*pSrc++ != 0)
86
54
                goto loser;
87
54
        }
88
2.83k
    }
89
2.77k
    PORT_Memcpy(pDst, pSrc, cntDst);
90
2.77k
    return SECSuccess;
91
92
54
loser:
93
54
    PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
94
54
    return SECFailure;
95
2.83k
}
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
9.45k
{
103
9.45k
    SECItem *item;
104
9.45k
    SECItem srcItem;
105
9.45k
    DSA_ASN1Signature sig;
106
9.45k
    unsigned char *signedR;
107
9.45k
    unsigned char *signedS;
108
9.45k
    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
9.45k
    len = src->len / 2;
115
9.45k
    signedR = (unsigned char *)PORT_Alloc(len + 1);
116
9.45k
    if (!signedR)
117
0
        return SECFailure;
118
9.45k
    signedS = (unsigned char *)PORT_ZAlloc(len + 1);
119
9.45k
    if (!signedS) {
120
0
        if (signedR)
121
0
            PORT_Free(signedR);
122
0
        return SECFailure;
123
0
    }
124
125
9.45k
    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
9.45k
    sig.r.type = siUnsignedInteger;
133
9.45k
    sig.r.data = signedR;
134
9.45k
    sig.r.len = sizeof signedR;
135
9.45k
    sig.s.type = siUnsignedInteger;
136
9.45k
    sig.s.data = signedS;
137
9.45k
    sig.s.len = sizeof signedR;
138
139
9.45k
    srcItem.data = src->data;
140
9.45k
    srcItem.len = len;
141
142
9.45k
    DSAU_ConvertUnsignedToSigned(&sig.r, &srcItem);
143
9.45k
    srcItem.data += len;
144
9.45k
    DSAU_ConvertUnsignedToSigned(&sig.s, &srcItem);
145
146
9.45k
    item = SEC_ASN1EncodeItem(NULL, dest, &sig, DSA_SignatureTemplate);
147
9.45k
    if (signedR)
148
9.45k
        PORT_Free(signedR);
149
9.45k
    if (signedS)
150
9.45k
        PORT_Free(signedS);
151
9.45k
    if (item == NULL)
152
0
        return SECFailure;
153
154
    /* XXX leak item? */
155
9.45k
    return SECSuccess;
156
9.45k
}
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
5.83k
{
167
5.83k
    SECItem *result = NULL;
168
5.83k
    PORTCheapArenaPool arena;
169
5.83k
    SECStatus status;
170
5.83k
    DSA_ASN1Signature sig;
171
5.83k
    SECItem dst;
172
173
5.83k
    PORT_Memset(&sig, 0, sizeof(sig));
174
175
    /* Make enough room for r + s. */
176
5.83k
    PORT_InitCheapArena(&arena, PR_MAX(2 * MAX_ECKEY_LEN, DSA_MAX_SIGNATURE_LEN));
177
178
5.83k
    result = PORT_ZNew(SECItem);
179
5.83k
    if (result == NULL)
180
0
        goto loser;
181
182
5.83k
    result->len = 2 * len;
183
5.83k
    result->data = (unsigned char *)PORT_Alloc(2 * len);
184
5.83k
    if (result->data == NULL)
185
0
        goto loser;
186
187
5.83k
    sig.r.type = siUnsignedInteger;
188
5.83k
    sig.s.type = siUnsignedInteger;
189
5.83k
    status = SEC_QuickDERDecodeItem(&arena.arena, &sig, DSA_SignatureTemplate, item);
190
5.83k
    if (status != SECSuccess)
191
299
        goto loser;
192
193
    /* Convert sig.r and sig.s from variable  length signed integers to
194
    ** fixed length unsigned integers.
195
    */
196
5.53k
    dst.data = result->data;
197
5.53k
    dst.len = len;
198
5.53k
    status = DSAU_ConvertSignedToFixedUnsigned(&dst, &sig.r);
199
5.53k
    if (status != SECSuccess)
200
43
        goto loser;
201
202
5.49k
    dst.data += len;
203
5.49k
    status = DSAU_ConvertSignedToFixedUnsigned(&dst, &sig.s);
204
5.49k
    if (status != SECSuccess)
205
11
        goto loser;
206
207
5.83k
done:
208
5.83k
    PORT_DestroyCheapArena(&arena);
209
210
5.83k
    return result;
211
212
353
loser:
213
353
    if (result != NULL) {
214
353
        SECITEM_FreeItem(result, PR_TRUE);
215
353
        result = NULL;
216
353
    }
217
353
    goto done;
218
5.49k
}
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
9.45k
{
241
242
9.45k
    PORT_Assert((src->len == len) && (len % 2 == 0));
243
9.45k
    if ((src->len != len) || (src->len % 2 != 0)) {
244
0
        PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
245
0
        return SECFailure;
246
0
    }
247
248
9.45k
    return common_EncodeDerSig(dest, src);
249
9.45k
}
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
5.83k
{
270
5.83k
    return common_DecodeDerSig(item, len / 2);
271
5.83k
}