Mercurial > trustbridge > nss-cmake-static
comparison nss/lib/cryptohi/secsign.c @ 0:1e5118fa0cb1
This is NSS with a Cmake Buildsyste
To compile a static NSS library for Windows we've used the
Chromium-NSS fork and added a Cmake buildsystem to compile
it statically for Windows. See README.chromium for chromium
changes and README.trustbridge for our modifications.
author | Andre Heinecke <andre.heinecke@intevation.de> |
---|---|
date | Mon, 28 Jul 2014 10:47:06 +0200 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:1e5118fa0cb1 |
---|---|
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 } |