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