|
1 /* |
|
2 * Signature stuff. |
|
3 * |
|
4 * This Source Code Form is subject to the terms of the Mozilla Public |
|
5 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
7 |
|
8 #include <stdio.h> |
|
9 #include "cryptohi.h" |
|
10 #include "sechash.h" |
|
11 #include "secder.h" |
|
12 #include "keyhi.h" |
|
13 #include "secoid.h" |
|
14 #include "secdig.h" |
|
15 #include "pk11func.h" |
|
16 #include "secerr.h" |
|
17 #include "keyi.h" |
|
18 |
|
19 struct SGNContextStr { |
|
20 SECOidTag signalg; |
|
21 SECOidTag hashalg; |
|
22 void *hashcx; |
|
23 const SECHashObject *hashobj; |
|
24 SECKEYPrivateKey *key; |
|
25 }; |
|
26 |
|
27 SGNContext * |
|
28 SGN_NewContext(SECOidTag alg, SECKEYPrivateKey *key) |
|
29 { |
|
30 SGNContext *cx; |
|
31 SECOidTag hashalg, signalg; |
|
32 KeyType keyType; |
|
33 SECStatus rv; |
|
34 |
|
35 /* OK, map a PKCS #7 hash and encrypt algorithm into |
|
36 * a standard hashing algorithm. Why did we pass in the whole |
|
37 * PKCS #7 algTag if we were just going to change here you might |
|
38 * ask. Well the answer is for some cards we may have to do the |
|
39 * hashing on card. It may not support CKM_RSA_PKCS sign algorithm, |
|
40 * it may just support CKM_SHA1_RSA_PKCS and/or CKM_MD5_RSA_PKCS. |
|
41 */ |
|
42 /* we have a private key, not a public key, so don't pass it in */ |
|
43 rv = sec_DecodeSigAlg(NULL, alg, NULL, &signalg, &hashalg); |
|
44 if (rv != SECSuccess) { |
|
45 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); |
|
46 return 0; |
|
47 } |
|
48 keyType = seckey_GetKeyType(signalg); |
|
49 |
|
50 /* verify our key type */ |
|
51 if (key->keyType != keyType && |
|
52 !((key->keyType == dsaKey) && (keyType == fortezzaKey)) ) { |
|
53 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); |
|
54 return 0; |
|
55 } |
|
56 |
|
57 cx = (SGNContext*) PORT_ZAlloc(sizeof(SGNContext)); |
|
58 if (cx) { |
|
59 cx->hashalg = hashalg; |
|
60 cx->signalg = signalg; |
|
61 cx->key = key; |
|
62 } |
|
63 return cx; |
|
64 } |
|
65 |
|
66 void |
|
67 SGN_DestroyContext(SGNContext *cx, PRBool freeit) |
|
68 { |
|
69 if (cx) { |
|
70 if (cx->hashcx != NULL) { |
|
71 (*cx->hashobj->destroy)(cx->hashcx, PR_TRUE); |
|
72 cx->hashcx = NULL; |
|
73 } |
|
74 if (freeit) { |
|
75 PORT_ZFree(cx, sizeof(SGNContext)); |
|
76 } |
|
77 } |
|
78 } |
|
79 |
|
80 SECStatus |
|
81 SGN_Begin(SGNContext *cx) |
|
82 { |
|
83 if (cx->hashcx != NULL) { |
|
84 (*cx->hashobj->destroy)(cx->hashcx, PR_TRUE); |
|
85 cx->hashcx = NULL; |
|
86 } |
|
87 |
|
88 cx->hashobj = HASH_GetHashObjectByOidTag(cx->hashalg); |
|
89 if (!cx->hashobj) |
|
90 return SECFailure; /* error code is already set */ |
|
91 |
|
92 cx->hashcx = (*cx->hashobj->create)(); |
|
93 if (cx->hashcx == NULL) |
|
94 return SECFailure; |
|
95 |
|
96 (*cx->hashobj->begin)(cx->hashcx); |
|
97 return SECSuccess; |
|
98 } |
|
99 |
|
100 SECStatus |
|
101 SGN_Update(SGNContext *cx, const unsigned char *input, unsigned int inputLen) |
|
102 { |
|
103 if (cx->hashcx == NULL) { |
|
104 PORT_SetError(SEC_ERROR_INVALID_ARGS); |
|
105 return SECFailure; |
|
106 } |
|
107 (*cx->hashobj->update)(cx->hashcx, input, inputLen); |
|
108 return SECSuccess; |
|
109 } |
|
110 |
|
111 /* XXX Old template; want to expunge it eventually. */ |
|
112 static DERTemplate SECAlgorithmIDTemplate[] = { |
|
113 { DER_SEQUENCE, |
|
114 0, NULL, sizeof(SECAlgorithmID) }, |
|
115 { DER_OBJECT_ID, |
|
116 offsetof(SECAlgorithmID,algorithm), }, |
|
117 { DER_OPTIONAL | DER_ANY, |
|
118 offsetof(SECAlgorithmID,parameters), }, |
|
119 { 0, } |
|
120 }; |
|
121 |
|
122 /* |
|
123 * XXX OLD Template. Once all uses have been switched over to new one, |
|
124 * remove this. |
|
125 */ |
|
126 static DERTemplate SGNDigestInfoTemplate[] = { |
|
127 { DER_SEQUENCE, |
|
128 0, NULL, sizeof(SGNDigestInfo) }, |
|
129 { DER_INLINE, |
|
130 offsetof(SGNDigestInfo,digestAlgorithm), |
|
131 SECAlgorithmIDTemplate, }, |
|
132 { DER_OCTET_STRING, |
|
133 offsetof(SGNDigestInfo,digest), }, |
|
134 { 0, } |
|
135 }; |
|
136 |
|
137 SECStatus |
|
138 SGN_End(SGNContext *cx, SECItem *result) |
|
139 { |
|
140 unsigned char digest[HASH_LENGTH_MAX]; |
|
141 unsigned part1; |
|
142 int signatureLen; |
|
143 SECStatus rv; |
|
144 SECItem digder, sigitem; |
|
145 PLArenaPool *arena = 0; |
|
146 SECKEYPrivateKey *privKey = cx->key; |
|
147 SGNDigestInfo *di = 0; |
|
148 |
|
149 result->data = 0; |
|
150 digder.data = 0; |
|
151 |
|
152 /* Finish up digest function */ |
|
153 if (cx->hashcx == NULL) { |
|
154 PORT_SetError(SEC_ERROR_INVALID_ARGS); |
|
155 return SECFailure; |
|
156 } |
|
157 (*cx->hashobj->end)(cx->hashcx, digest, &part1, sizeof(digest)); |
|
158 |
|
159 |
|
160 if (privKey->keyType == rsaKey) { |
|
161 |
|
162 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); |
|
163 if ( !arena ) { |
|
164 rv = SECFailure; |
|
165 goto loser; |
|
166 } |
|
167 |
|
168 /* Construct digest info */ |
|
169 di = SGN_CreateDigestInfo(cx->hashalg, digest, part1); |
|
170 if (!di) { |
|
171 rv = SECFailure; |
|
172 goto loser; |
|
173 } |
|
174 |
|
175 /* Der encode the digest as a DigestInfo */ |
|
176 rv = DER_Encode(arena, &digder, SGNDigestInfoTemplate, |
|
177 di); |
|
178 if (rv != SECSuccess) { |
|
179 goto loser; |
|
180 } |
|
181 } else { |
|
182 digder.data = digest; |
|
183 digder.len = part1; |
|
184 } |
|
185 |
|
186 /* |
|
187 ** Encrypt signature after constructing appropriate PKCS#1 signature |
|
188 ** block |
|
189 */ |
|
190 signatureLen = PK11_SignatureLen(privKey); |
|
191 if (signatureLen <= 0) { |
|
192 PORT_SetError(SEC_ERROR_INVALID_KEY); |
|
193 rv = SECFailure; |
|
194 goto loser; |
|
195 } |
|
196 sigitem.len = signatureLen; |
|
197 sigitem.data = (unsigned char*) PORT_Alloc(signatureLen); |
|
198 |
|
199 if (sigitem.data == NULL) { |
|
200 rv = SECFailure; |
|
201 goto loser; |
|
202 } |
|
203 |
|
204 rv = PK11_Sign(privKey, &sigitem, &digder); |
|
205 if (rv != SECSuccess) { |
|
206 PORT_Free(sigitem.data); |
|
207 sigitem.data = NULL; |
|
208 goto loser; |
|
209 } |
|
210 |
|
211 if ((cx->signalg == SEC_OID_ANSIX9_DSA_SIGNATURE) || |
|
212 (cx->signalg == SEC_OID_ANSIX962_EC_PUBLIC_KEY)) { |
|
213 /* DSAU_EncodeDerSigWithLen works for DSA and ECDSA */ |
|
214 rv = DSAU_EncodeDerSigWithLen(result, &sigitem, sigitem.len); |
|
215 PORT_Free(sigitem.data); |
|
216 if (rv != SECSuccess) |
|
217 goto loser; |
|
218 } else { |
|
219 result->len = sigitem.len; |
|
220 result->data = sigitem.data; |
|
221 } |
|
222 |
|
223 loser: |
|
224 SGN_DestroyDigestInfo(di); |
|
225 if (arena != NULL) { |
|
226 PORT_FreeArena(arena, PR_FALSE); |
|
227 } |
|
228 return rv; |
|
229 } |
|
230 |
|
231 /************************************************************************/ |
|
232 |
|
233 /* |
|
234 ** Sign a block of data returning in result a bunch of bytes that are the |
|
235 ** signature. Returns zero on success, an error code on failure. |
|
236 */ |
|
237 SECStatus |
|
238 SEC_SignData(SECItem *res, const unsigned char *buf, int len, |
|
239 SECKEYPrivateKey *pk, SECOidTag algid) |
|
240 { |
|
241 SECStatus rv; |
|
242 SGNContext *sgn; |
|
243 |
|
244 |
|
245 sgn = SGN_NewContext(algid, pk); |
|
246 |
|
247 if (sgn == NULL) |
|
248 return SECFailure; |
|
249 |
|
250 rv = SGN_Begin(sgn); |
|
251 if (rv != SECSuccess) |
|
252 goto loser; |
|
253 |
|
254 rv = SGN_Update(sgn, buf, len); |
|
255 if (rv != SECSuccess) |
|
256 goto loser; |
|
257 |
|
258 rv = SGN_End(sgn, res); |
|
259 |
|
260 loser: |
|
261 SGN_DestroyContext(sgn, PR_TRUE); |
|
262 return rv; |
|
263 } |
|
264 |
|
265 /************************************************************************/ |
|
266 |
|
267 DERTemplate CERTSignedDataTemplate[] = |
|
268 { |
|
269 { DER_SEQUENCE, |
|
270 0, NULL, sizeof(CERTSignedData) }, |
|
271 { DER_ANY, |
|
272 offsetof(CERTSignedData,data), }, |
|
273 { DER_INLINE, |
|
274 offsetof(CERTSignedData,signatureAlgorithm), |
|
275 SECAlgorithmIDTemplate, }, |
|
276 { DER_BIT_STRING, |
|
277 offsetof(CERTSignedData,signature), }, |
|
278 { 0, } |
|
279 }; |
|
280 |
|
281 SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate) |
|
282 |
|
283 const SEC_ASN1Template CERT_SignedDataTemplate[] = |
|
284 { |
|
285 { SEC_ASN1_SEQUENCE, |
|
286 0, NULL, sizeof(CERTSignedData) }, |
|
287 { SEC_ASN1_ANY, |
|
288 offsetof(CERTSignedData,data), }, |
|
289 { SEC_ASN1_INLINE | SEC_ASN1_XTRN, |
|
290 offsetof(CERTSignedData,signatureAlgorithm), |
|
291 SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate), }, |
|
292 { SEC_ASN1_BIT_STRING, |
|
293 offsetof(CERTSignedData,signature), }, |
|
294 { 0, } |
|
295 }; |
|
296 |
|
297 SEC_ASN1_CHOOSER_IMPLEMENT(CERT_SignedDataTemplate) |
|
298 |
|
299 |
|
300 SECStatus |
|
301 SEC_DerSignData(PLArenaPool *arena, SECItem *result, |
|
302 const unsigned char *buf, int len, SECKEYPrivateKey *pk, |
|
303 SECOidTag algID) |
|
304 { |
|
305 SECItem it; |
|
306 CERTSignedData sd; |
|
307 SECStatus rv; |
|
308 |
|
309 it.data = 0; |
|
310 |
|
311 /* XXX We should probably have some asserts here to make sure the key type |
|
312 * and algID match |
|
313 */ |
|
314 |
|
315 if (algID == SEC_OID_UNKNOWN) { |
|
316 switch(pk->keyType) { |
|
317 case rsaKey: |
|
318 algID = SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION; |
|
319 break; |
|
320 case dsaKey: |
|
321 /* get Signature length (= q_len*2) and work from there */ |
|
322 switch (PK11_SignatureLen(pk)) { |
|
323 case 448: |
|
324 algID = SEC_OID_NIST_DSA_SIGNATURE_WITH_SHA224_DIGEST; |
|
325 break; |
|
326 case 512: |
|
327 algID = SEC_OID_NIST_DSA_SIGNATURE_WITH_SHA256_DIGEST; |
|
328 break; |
|
329 default: |
|
330 algID = SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST; |
|
331 break; |
|
332 } |
|
333 break; |
|
334 case ecKey: |
|
335 algID = SEC_OID_ANSIX962_ECDSA_SIGNATURE_WITH_SHA1_DIGEST; |
|
336 break; |
|
337 default: |
|
338 PORT_SetError(SEC_ERROR_INVALID_KEY); |
|
339 return SECFailure; |
|
340 } |
|
341 } |
|
342 |
|
343 /* Sign input buffer */ |
|
344 rv = SEC_SignData(&it, buf, len, pk, algID); |
|
345 if (rv) goto loser; |
|
346 |
|
347 /* Fill out SignedData object */ |
|
348 PORT_Memset(&sd, 0, sizeof(sd)); |
|
349 sd.data.data = (unsigned char*) buf; |
|
350 sd.data.len = len; |
|
351 sd.signature.data = it.data; |
|
352 sd.signature.len = it.len << 3; /* convert to bit string */ |
|
353 rv = SECOID_SetAlgorithmID(arena, &sd.signatureAlgorithm, algID, 0); |
|
354 if (rv) goto loser; |
|
355 |
|
356 /* DER encode the signed data object */ |
|
357 rv = DER_Encode(arena, result, CERTSignedDataTemplate, &sd); |
|
358 /* FALL THROUGH */ |
|
359 |
|
360 loser: |
|
361 PORT_Free(it.data); |
|
362 return rv; |
|
363 } |
|
364 |
|
365 SECStatus |
|
366 SGN_Digest(SECKEYPrivateKey *privKey, |
|
367 SECOidTag algtag, SECItem *result, SECItem *digest) |
|
368 { |
|
369 int modulusLen; |
|
370 SECStatus rv; |
|
371 SECItem digder; |
|
372 PLArenaPool *arena = 0; |
|
373 SGNDigestInfo *di = 0; |
|
374 |
|
375 |
|
376 result->data = 0; |
|
377 |
|
378 if (privKey->keyType == rsaKey) { |
|
379 |
|
380 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); |
|
381 if ( !arena ) { |
|
382 rv = SECFailure; |
|
383 goto loser; |
|
384 } |
|
385 |
|
386 /* Construct digest info */ |
|
387 di = SGN_CreateDigestInfo(algtag, digest->data, digest->len); |
|
388 if (!di) { |
|
389 rv = SECFailure; |
|
390 goto loser; |
|
391 } |
|
392 |
|
393 /* Der encode the digest as a DigestInfo */ |
|
394 rv = DER_Encode(arena, &digder, SGNDigestInfoTemplate, |
|
395 di); |
|
396 if (rv != SECSuccess) { |
|
397 goto loser; |
|
398 } |
|
399 } else { |
|
400 digder.data = digest->data; |
|
401 digder.len = digest->len; |
|
402 } |
|
403 |
|
404 /* |
|
405 ** Encrypt signature after constructing appropriate PKCS#1 signature |
|
406 ** block |
|
407 */ |
|
408 modulusLen = PK11_SignatureLen(privKey); |
|
409 if (modulusLen <= 0) { |
|
410 PORT_SetError(SEC_ERROR_INVALID_KEY); |
|
411 rv = SECFailure; |
|
412 goto loser; |
|
413 } |
|
414 result->len = modulusLen; |
|
415 result->data = (unsigned char*) PORT_Alloc(modulusLen); |
|
416 |
|
417 if (result->data == NULL) { |
|
418 rv = SECFailure; |
|
419 goto loser; |
|
420 } |
|
421 |
|
422 rv = PK11_Sign(privKey, result, &digder); |
|
423 if (rv != SECSuccess) { |
|
424 PORT_Free(result->data); |
|
425 result->data = NULL; |
|
426 } |
|
427 |
|
428 loser: |
|
429 SGN_DestroyDigestInfo(di); |
|
430 if (arena != NULL) { |
|
431 PORT_FreeArena(arena, PR_FALSE); |
|
432 } |
|
433 return rv; |
|
434 } |
|
435 |
|
436 SECOidTag |
|
437 SEC_GetSignatureAlgorithmOidTag(KeyType keyType, SECOidTag hashAlgTag) |
|
438 { |
|
439 SECOidTag sigTag = SEC_OID_UNKNOWN; |
|
440 |
|
441 switch (keyType) { |
|
442 case rsaKey: |
|
443 switch (hashAlgTag) { |
|
444 case SEC_OID_MD2: |
|
445 sigTag = SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION; break; |
|
446 case SEC_OID_MD5: |
|
447 sigTag = SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION; break; |
|
448 case SEC_OID_UNKNOWN: /* default for RSA if not specified */ |
|
449 case SEC_OID_SHA1: |
|
450 sigTag = SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION; break; |
|
451 case SEC_OID_SHA224: |
|
452 sigTag = SEC_OID_PKCS1_SHA224_WITH_RSA_ENCRYPTION; break; |
|
453 case SEC_OID_SHA256: |
|
454 sigTag = SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION; break; |
|
455 case SEC_OID_SHA384: |
|
456 sigTag = SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION; break; |
|
457 case SEC_OID_SHA512: |
|
458 sigTag = SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION; break; |
|
459 default: |
|
460 break; |
|
461 } |
|
462 break; |
|
463 case dsaKey: |
|
464 switch (hashAlgTag) { |
|
465 case SEC_OID_UNKNOWN: /* default for DSA if not specified */ |
|
466 case SEC_OID_SHA1: |
|
467 sigTag = SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST; break; |
|
468 case SEC_OID_SHA224: |
|
469 sigTag = SEC_OID_NIST_DSA_SIGNATURE_WITH_SHA224_DIGEST; break; |
|
470 case SEC_OID_SHA256: |
|
471 sigTag = SEC_OID_NIST_DSA_SIGNATURE_WITH_SHA256_DIGEST; break; |
|
472 default: |
|
473 break; |
|
474 } |
|
475 break; |
|
476 case ecKey: |
|
477 switch (hashAlgTag) { |
|
478 case SEC_OID_UNKNOWN: /* default for ECDSA if not specified */ |
|
479 case SEC_OID_SHA1: |
|
480 sigTag = SEC_OID_ANSIX962_ECDSA_SHA1_SIGNATURE; break; |
|
481 case SEC_OID_SHA224: |
|
482 sigTag = SEC_OID_ANSIX962_ECDSA_SHA224_SIGNATURE; break; |
|
483 case SEC_OID_SHA256: |
|
484 sigTag = SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE; break; |
|
485 case SEC_OID_SHA384: |
|
486 sigTag = SEC_OID_ANSIX962_ECDSA_SHA384_SIGNATURE; break; |
|
487 case SEC_OID_SHA512: |
|
488 sigTag = SEC_OID_ANSIX962_ECDSA_SHA512_SIGNATURE; break; |
|
489 default: |
|
490 break; |
|
491 } |
|
492 default: |
|
493 break; |
|
494 } |
|
495 return sigTag; |
|
496 } |