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 | |
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 if (privKey->keyType == rsaKey) { | |
160 | |
161 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); | |
162 if (!arena) { | |
163 rv = SECFailure; | |
164 goto loser; | |
165 } | |
166 | |
167 /* Construct digest info */ | |
168 di = SGN_CreateDigestInfo(cx->hashalg, digest, part1); | |
169 if (!di) { | |
170 rv = SECFailure; | |
171 goto loser; | |
172 } | |
173 | |
174 /* Der encode the digest as a DigestInfo */ | |
175 rv = DER_Encode(arena, &digder, SGNDigestInfoTemplate, | |
176 di); | |
177 if (rv != SECSuccess) { | |
178 goto loser; | |
179 } | |
180 } else { | |
181 digder.data = digest; | |
182 digder.len = part1; | |
183 } | |
184 | |
185 /* | |
186 ** Encrypt signature after constructing appropriate PKCS#1 signature | |
187 ** block | |
188 */ | |
189 signatureLen = PK11_SignatureLen(privKey); | |
190 if (signatureLen <= 0) { | |
191 PORT_SetError(SEC_ERROR_INVALID_KEY); | |
192 rv = SECFailure; | |
193 goto loser; | |
194 } | |
195 sigitem.len = signatureLen; | |
196 sigitem.data = (unsigned char *)PORT_Alloc(signatureLen); | |
197 | |
198 if (sigitem.data == NULL) { | |
199 rv = SECFailure; | |
200 goto loser; | |
201 } | |
202 | |
203 rv = PK11_Sign(privKey, &sigitem, &digder); | |
204 if (rv != SECSuccess) { | |
205 PORT_Free(sigitem.data); | |
206 sigitem.data = NULL; | |
207 goto loser; | |
208 } | |
209 | |
210 if ((cx->signalg == SEC_OID_ANSIX9_DSA_SIGNATURE) || | |
211 (cx->signalg == SEC_OID_ANSIX962_EC_PUBLIC_KEY)) { | |
212 /* DSAU_EncodeDerSigWithLen works for DSA and ECDSA */ | |
213 rv = DSAU_EncodeDerSigWithLen(result, &sigitem, sigitem.len); | |
214 PORT_Free(sigitem.data); | |
215 if (rv != SECSuccess) | |
216 goto loser; | |
217 } else { | |
218 result->len = sigitem.len; | |
219 result->data = sigitem.data; | |
220 } | |
221 | |
222 loser: | |
223 SGN_DestroyDigestInfo(di); | |
224 if (arena != NULL) { | |
225 PORT_FreeArena(arena, PR_FALSE); | |
226 } | |
227 return rv; | |
228 } | |
229 | |
230 /************************************************************************/ | |
231 | |
232 /* | |
233 ** Sign a block of data returning in result a bunch of bytes that are the | |
234 ** signature. Returns zero on success, an error code on failure. | |
235 */ | |
236 SECStatus | |
237 SEC_SignData(SECItem *res, const unsigned char *buf, int len, | |
238 SECKEYPrivateKey *pk, SECOidTag algid) | |
239 { | |
240 SECStatus rv; | |
241 SGNContext *sgn; | |
242 | |
243 sgn = SGN_NewContext(algid, pk); | |
244 | |
245 if (sgn == NULL) | |
246 return SECFailure; | |
247 | |
248 rv = SGN_Begin(sgn); | |
249 if (rv != SECSuccess) | |
250 goto loser; | |
251 | |
252 rv = SGN_Update(sgn, buf, len); | |
253 if (rv != SECSuccess) | |
254 goto loser; | |
255 | |
256 rv = SGN_End(sgn, res); | |
257 | |
258 loser: | |
259 SGN_DestroyContext(sgn, PR_TRUE); | |
260 return rv; | |
261 } | |
262 | |
263 /************************************************************************/ | |
264 | |
265 DERTemplate CERTSignedDataTemplate[] = | |
266 { | |
267 { DER_SEQUENCE, | |
268 0, NULL, sizeof(CERTSignedData) }, | |
269 { DER_ANY, | |
270 offsetof(CERTSignedData, data) }, | |
271 { DER_INLINE, | |
272 offsetof(CERTSignedData, signatureAlgorithm), | |
273 SECAlgorithmIDTemplate }, | |
274 { DER_BIT_STRING, | |
275 offsetof(CERTSignedData, signature) }, | |
276 { 0 } | |
277 }; | |
278 | |
279 SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate) | |
280 | |
281 const SEC_ASN1Template CERT_SignedDataTemplate[] = | |
282 { | |
283 { SEC_ASN1_SEQUENCE, | |
284 0, NULL, sizeof(CERTSignedData) }, | |
285 { SEC_ASN1_ANY, | |
286 offsetof(CERTSignedData, data) }, | |
287 { SEC_ASN1_INLINE | SEC_ASN1_XTRN, | |
288 offsetof(CERTSignedData, signatureAlgorithm), | |
289 SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) }, | |
290 { SEC_ASN1_BIT_STRING, | |
291 offsetof(CERTSignedData, signature) }, | |
292 { 0 } | |
293 }; | |
294 | |
295 SEC_ASN1_CHOOSER_IMPLEMENT(CERT_SignedDataTemplate) | |
296 | |
297 SECStatus | |
298 SEC_DerSignData(PLArenaPool *arena, SECItem *result, | |
299 const unsigned char *buf, int len, SECKEYPrivateKey *pk, | |
300 SECOidTag algID) | |
301 { | |
302 SECItem it; | |
303 CERTSignedData sd; | |
304 SECStatus rv; | |
305 | |
306 it.data = 0; | |
307 | |
308 /* XXX We should probably have some asserts here to make sure the key type | |
309 * and algID match | |
310 */ | |
311 | |
312 if (algID == SEC_OID_UNKNOWN) { | |
313 switch (pk->keyType) { | |
314 case rsaKey: | |
315 algID = SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION; | |
316 break; | |
317 case dsaKey: | |
318 /* get Signature length (= q_len*2) and work from there */ | |
319 switch (PK11_SignatureLen(pk)) { | |
320 case 448: | |
321 algID = SEC_OID_NIST_DSA_SIGNATURE_WITH_SHA224_DIGEST; | |
322 break; | |
323 case 512: | |
324 algID = SEC_OID_NIST_DSA_SIGNATURE_WITH_SHA256_DIGEST; | |
325 break; | |
326 default: | |
327 algID = SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST; | |
328 break; | |
329 } | |
330 break; | |
331 case ecKey: | |
332 algID = SEC_OID_ANSIX962_ECDSA_SIGNATURE_WITH_SHA1_DIGEST; | |
333 break; | |
334 default: | |
335 PORT_SetError(SEC_ERROR_INVALID_KEY); | |
336 return SECFailure; | |
337 } | |
338 } | |
339 | |
340 /* Sign input buffer */ | |
341 rv = SEC_SignData(&it, buf, len, pk, algID); | |
342 if (rv) | |
343 goto loser; | |
344 | |
345 /* Fill out SignedData object */ | |
346 PORT_Memset(&sd, 0, sizeof(sd)); | |
347 sd.data.data = (unsigned char *)buf; | |
348 sd.data.len = len; | |
349 sd.signature.data = it.data; | |
350 sd.signature.len = it.len << 3; /* convert to bit string */ | |
351 rv = SECOID_SetAlgorithmID(arena, &sd.signatureAlgorithm, algID, 0); | |
352 if (rv) | |
353 goto loser; | |
354 | |
355 /* DER encode the signed data object */ | |
356 rv = DER_Encode(arena, result, CERTSignedDataTemplate, &sd); | |
357 /* FALL THROUGH */ | |
358 | |
359 loser: | |
360 PORT_Free(it.data); | |
361 return rv; | |
362 } | |
363 | |
364 SECStatus | |
365 SGN_Digest(SECKEYPrivateKey *privKey, | |
366 SECOidTag algtag, SECItem *result, SECItem *digest) | |
367 { | |
368 int modulusLen; | |
369 SECStatus rv; | |
370 SECItem digder; | |
371 PLArenaPool *arena = 0; | |
372 SGNDigestInfo *di = 0; | |
373 | |
374 result->data = 0; | |
375 | |
376 if (privKey->keyType == rsaKey) { | |
377 | |
378 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); | |
379 if (!arena) { | |
380 rv = SECFailure; | |
381 goto loser; | |
382 } | |
383 | |
384 /* Construct digest info */ | |
385 di = SGN_CreateDigestInfo(algtag, digest->data, digest->len); | |
386 if (!di) { | |
387 rv = SECFailure; | |
388 goto loser; | |
389 } | |
390 | |
391 /* Der encode the digest as a DigestInfo */ | |
392 rv = DER_Encode(arena, &digder, SGNDigestInfoTemplate, | |
393 di); | |
394 if (rv != SECSuccess) { | |
395 goto loser; | |
396 } | |
397 } else { | |
398 digder.data = digest->data; | |
399 digder.len = digest->len; | |
400 } | |
401 | |
402 /* | |
403 ** Encrypt signature after constructing appropriate PKCS#1 signature | |
404 ** block | |
405 */ | |
406 modulusLen = PK11_SignatureLen(privKey); | |
407 if (modulusLen <= 0) { | |
408 PORT_SetError(SEC_ERROR_INVALID_KEY); | |
409 rv = SECFailure; | |
410 goto loser; | |
411 } | |
412 result->len = modulusLen; | |
413 result->data = (unsigned char *)PORT_Alloc(modulusLen); | |
414 result->type = siBuffer; | |
415 | |
416 if (result->data == NULL) { | |
417 rv = SECFailure; | |
418 goto loser; | |
419 } | |
420 | |
421 rv = PK11_Sign(privKey, result, &digder); | |
422 if (rv != SECSuccess) { | |
423 PORT_Free(result->data); | |
424 result->data = NULL; | |
425 } | |
426 | |
427 loser: | |
428 SGN_DestroyDigestInfo(di); | |
429 if (arena != NULL) { | |
430 PORT_FreeArena(arena, PR_FALSE); | |
431 } | |
432 return rv; | |
433 } | |
434 | |
435 SECOidTag | |
436 SEC_GetSignatureAlgorithmOidTag(KeyType keyType, SECOidTag hashAlgTag) | |
437 { | |
438 SECOidTag sigTag = SEC_OID_UNKNOWN; | |
439 | |
440 switch (keyType) { | |
441 case rsaKey: | |
442 switch (hashAlgTag) { | |
443 case SEC_OID_MD2: | |
444 sigTag = SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION; | |
445 break; | |
446 case SEC_OID_MD5: | |
447 sigTag = SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION; | |
448 break; | |
449 case SEC_OID_SHA1: | |
450 sigTag = SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION; | |
451 break; | |
452 case SEC_OID_SHA224: | |
453 sigTag = SEC_OID_PKCS1_SHA224_WITH_RSA_ENCRYPTION; | |
454 break; | |
455 case SEC_OID_UNKNOWN: /* default for RSA if not specified */ | |
456 case SEC_OID_SHA256: | |
457 sigTag = SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION; | |
458 break; | |
459 case SEC_OID_SHA384: | |
460 sigTag = SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION; | |
461 break; | |
462 case SEC_OID_SHA512: | |
463 sigTag = SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION; | |
464 break; | |
465 default: | |
466 break; | |
467 } | |
468 break; | |
469 case dsaKey: | |
470 switch (hashAlgTag) { | |
471 case SEC_OID_UNKNOWN: /* default for DSA if not specified */ | |
472 case SEC_OID_SHA1: | |
473 sigTag = SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST; | |
474 break; | |
475 case SEC_OID_SHA224: | |
476 sigTag = SEC_OID_NIST_DSA_SIGNATURE_WITH_SHA224_DIGEST; | |
477 break; | |
478 case SEC_OID_SHA256: | |
479 sigTag = SEC_OID_NIST_DSA_SIGNATURE_WITH_SHA256_DIGEST; | |
480 break; | |
481 default: | |
482 break; | |
483 } | |
484 break; | |
485 case ecKey: | |
486 switch (hashAlgTag) { | |
487 case SEC_OID_UNKNOWN: /* default for ECDSA if not specified */ | |
488 case SEC_OID_SHA1: | |
489 sigTag = SEC_OID_ANSIX962_ECDSA_SHA1_SIGNATURE; | |
490 break; | |
491 case SEC_OID_SHA224: | |
492 sigTag = SEC_OID_ANSIX962_ECDSA_SHA224_SIGNATURE; | |
493 break; | |
494 case SEC_OID_SHA256: | |
495 sigTag = SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE; | |
496 break; | |
497 case SEC_OID_SHA384: | |
498 sigTag = SEC_OID_ANSIX962_ECDSA_SHA384_SIGNATURE; | |
499 break; | |
500 case SEC_OID_SHA512: | |
501 sigTag = SEC_OID_ANSIX962_ECDSA_SHA512_SIGNATURE; | |
502 break; | |
503 default: | |
504 break; | |
505 } | |
506 default: | |
507 break; | |
508 } | |
509 return sigTag; | |
510 } | |
OLD | NEW |