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