/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 | } |