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
DSAU_ConvertUnsignedToSigned(SECItem * dest,SECItem * src)36 DSAU_ConvertUnsignedToSigned(SECItem *dest, SECItem *src)
37 {
38     unsigned char *pSrc = src->data;
39     unsigned char *pDst = dest->data;
40     unsigned int cntSrc = src->len;
41 
42     /* skip any leading zeros. */
43     while (cntSrc && !(*pSrc)) {
44         pSrc++;
45         cntSrc--;
46     }
47     if (!cntSrc) {
48         *pDst = 0;
49         dest->len = 1;
50         return;
51     }
52 
53     if (*pSrc & 0x80)
54         *pDst++ = 0;
55 
56     PORT_Memcpy(pDst, pSrc, cntSrc);
57     dest->len = (pDst - dest->data) + cntSrc;
58 }
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
DSAU_ConvertSignedToFixedUnsigned(SECItem * dest,SECItem * src)70 DSAU_ConvertSignedToFixedUnsigned(SECItem *dest, SECItem *src)
71 {
72     unsigned char *pSrc = src->data;
73     unsigned char *pDst = dest->data;
74     unsigned int cntSrc = src->len;
75     unsigned int cntDst = dest->len;
76     int zCount = cntDst - cntSrc;
77 
78     if (zCount > 0) {
79         PORT_Memset(pDst, 0, zCount);
80         PORT_Memcpy(pDst + zCount, pSrc, cntSrc);
81         return SECSuccess;
82     }
83     if (zCount <= 0) {
84         /* Source is longer than destination.  Check for leading zeros. */
85         while (zCount++ < 0) {
86             if (*pSrc++ != 0)
87                 goto loser;
88         }
89     }
90     PORT_Memcpy(pDst, pSrc, cntDst);
91     return SECSuccess;
92 
93 loser:
94     PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
95     return SECFailure;
96 }
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
common_EncodeDerSig(SECItem * dest,SECItem * src)102 common_EncodeDerSig(SECItem *dest, SECItem *src)
103 {
104     SECItem *item;
105     SECItem srcItem;
106     DSA_ASN1Signature sig;
107     unsigned char *signedR;
108     unsigned char *signedS;
109     unsigned int len;
110 
111     /* Allocate memory with room for an extra byte that
112      * may be required if the top bit in the first byte
113      * is already set.
114      */
115     len = src->len / 2;
116     signedR = (unsigned char *)PORT_Alloc(len + 1);
117     if (!signedR)
118         return SECFailure;
119     signedS = (unsigned char *)PORT_ZAlloc(len + 1);
120     if (!signedS) {
121         if (signedR)
122             PORT_Free(signedR);
123         return SECFailure;
124     }
125 
126     PORT_Memset(&sig, 0, sizeof(sig));
127 
128     /* Must convert r and s from "unsigned" integers to "signed" integers.
129     ** If the high order bit of the first byte (MSB) is 1, then must
130     ** prepend with leading zero.
131     ** Must remove all but one leading zero byte from numbers.
132     */
133     sig.r.type = siUnsignedInteger;
134     sig.r.data = signedR;
135     sig.r.len = sizeof signedR;
136     sig.s.type = siUnsignedInteger;
137     sig.s.data = signedS;
138     sig.s.len = sizeof signedR;
139 
140     srcItem.data = src->data;
141     srcItem.len = len;
142 
143     DSAU_ConvertUnsignedToSigned(&sig.r, &srcItem);
144     srcItem.data += len;
145     DSAU_ConvertUnsignedToSigned(&sig.s, &srcItem);
146 
147     item = SEC_ASN1EncodeItem(NULL, dest, &sig, DSA_SignatureTemplate);
148     if (signedR)
149         PORT_Free(signedR);
150     if (signedS)
151         PORT_Free(signedS);
152     if (item == NULL)
153         return SECFailure;
154 
155     /* XXX leak item? */
156     return SECSuccess;
157 }
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 *
common_DecodeDerSig(const SECItem * item,unsigned int len)166 common_DecodeDerSig(const SECItem *item, unsigned int len)
167 {
168     SECItem *result = NULL;
169     PORTCheapArenaPool arena;
170     SECStatus status;
171     DSA_ASN1Signature sig;
172     SECItem dst;
173 
174     PORT_Memset(&sig, 0, sizeof(sig));
175 
176     /* Make enough room for r + s. */
177     PORT_InitCheapArena(&arena, PR_MAX(2 * MAX_ECKEY_LEN, DSA_MAX_SIGNATURE_LEN));
178 
179     result = PORT_ZNew(SECItem);
180     if (result == NULL)
181         goto loser;
182 
183     result->len = 2 * len;
184     result->data = (unsigned char *)PORT_Alloc(2 * len);
185     if (result->data == NULL)
186         goto loser;
187 
188     sig.r.type = siUnsignedInteger;
189     sig.s.type = siUnsignedInteger;
190     status = SEC_QuickDERDecodeItem(&arena.arena, &sig, DSA_SignatureTemplate, item);
191     if (status != SECSuccess)
192         goto loser;
193 
194     /* Convert sig.r and sig.s from variable  length signed integers to
195     ** fixed length unsigned integers.
196     */
197     dst.data = result->data;
198     dst.len = len;
199     status = DSAU_ConvertSignedToFixedUnsigned(&dst, &sig.r);
200     if (status != SECSuccess)
201         goto loser;
202 
203     dst.data += len;
204     status = DSAU_ConvertSignedToFixedUnsigned(&dst, &sig.s);
205     if (status != SECSuccess)
206         goto loser;
207 
208 done:
209     PORT_DestroyCheapArena(&arena);
210 
211     return result;
212 
213 loser:
214     if (result != NULL) {
215         SECITEM_FreeItem(result, PR_TRUE);
216         result = NULL;
217     }
218     goto done;
219 }
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
DSAU_EncodeDerSig(SECItem * dest,SECItem * src)225 DSAU_EncodeDerSig(SECItem *dest, SECItem *src)
226 {
227     PORT_Assert(src->len == 2 * DSA1_SUBPRIME_LEN);
228     if (src->len != 2 * DSA1_SUBPRIME_LEN) {
229         PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
230         return SECFailure;
231     }
232 
233     return common_EncodeDerSig(dest, src);
234 }
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
DSAU_EncodeDerSigWithLen(SECItem * dest,SECItem * src,unsigned int len)240 DSAU_EncodeDerSigWithLen(SECItem *dest, SECItem *src, unsigned int len)
241 {
242 
243     PORT_Assert((src->len == len) && (len % 2 == 0));
244     if ((src->len != len) || (src->len % 2 != 0)) {
245         PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
246         return SECFailure;
247     }
248 
249     return common_EncodeDerSig(dest, src);
250 }
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 *
DSAU_DecodeDerSig(const SECItem * item)258 DSAU_DecodeDerSig(const SECItem *item)
259 {
260     return common_DecodeDerSig(item, DSA1_SUBPRIME_LEN);
261 }
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 *
DSAU_DecodeDerSigToLen(const SECItem * item,unsigned int len)269 DSAU_DecodeDerSigToLen(const SECItem *item, unsigned int len)
270 {
271     return common_DecodeDerSig(item, len / 2);
272 }
273