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