Mercurial > trustbridge > nss-cmake-static
comparison nss/lib/pkcs7/p7decode.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 /* 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 | |
5 /* | |
6 * PKCS7 decoding, verification. | |
7 */ | |
8 | |
9 #include "p7local.h" | |
10 | |
11 #include "cert.h" | |
12 /* XXX do not want to have to include */ | |
13 #include "certdb.h" /* certdb.h -- the trust stuff needed by */ | |
14 /* the add certificate code needs to get */ | |
15 /* rewritten/abstracted and then this */ | |
16 /* include should be removed! */ | |
17 /*#include "cdbhdl.h" */ | |
18 #include "cryptohi.h" | |
19 #include "key.h" | |
20 #include "secasn1.h" | |
21 #include "secitem.h" | |
22 #include "secoid.h" | |
23 #include "pk11func.h" | |
24 #include "prtime.h" | |
25 #include "secerr.h" | |
26 #include "sechash.h" /* for HASH_GetHashObject() */ | |
27 #include "secder.h" | |
28 #include "secpkcs5.h" | |
29 | |
30 struct sec_pkcs7_decoder_worker { | |
31 int depth; | |
32 int digcnt; | |
33 void **digcxs; | |
34 const SECHashObject **digobjs; | |
35 sec_PKCS7CipherObject *decryptobj; | |
36 PRBool saw_contents; | |
37 }; | |
38 | |
39 struct SEC_PKCS7DecoderContextStr { | |
40 SEC_ASN1DecoderContext *dcx; | |
41 SEC_PKCS7ContentInfo *cinfo; | |
42 SEC_PKCS7DecoderContentCallback cb; | |
43 void *cb_arg; | |
44 SECKEYGetPasswordKey pwfn; | |
45 void *pwfn_arg; | |
46 struct sec_pkcs7_decoder_worker worker; | |
47 PLArenaPool *tmp_poolp; | |
48 int error; | |
49 SEC_PKCS7GetDecryptKeyCallback dkcb; | |
50 void *dkcb_arg; | |
51 SEC_PKCS7DecryptionAllowedCallback decrypt_allowed_cb; | |
52 }; | |
53 | |
54 /* | |
55 * Handle one worker, decrypting and digesting the data as necessary. | |
56 * | |
57 * XXX If/when we support nested contents, this probably needs to be | |
58 * revised somewhat to get passed the content-info (which unfortunately | |
59 * can be two different types depending on whether it is encrypted or not) | |
60 * corresponding to the given worker. | |
61 */ | |
62 static void | |
63 sec_pkcs7_decoder_work_data (SEC_PKCS7DecoderContext *p7dcx, | |
64 struct sec_pkcs7_decoder_worker *worker, | |
65 const unsigned char *data, unsigned long len, | |
66 PRBool final) | |
67 { | |
68 unsigned char *buf = NULL; | |
69 SECStatus rv; | |
70 int i; | |
71 | |
72 /* | |
73 * We should really have data to process, or we should be trying | |
74 * to finish/flush the last block. (This is an overly paranoid | |
75 * check since all callers are in this file and simple inspection | |
76 * proves they do it right. But it could find a bug in future | |
77 * modifications/development, that is why it is here.) | |
78 */ | |
79 PORT_Assert ((data != NULL && len) || final); | |
80 | |
81 /* | |
82 * Decrypt this chunk. | |
83 * | |
84 * XXX If we get an error, we do not want to do the digest or callback, | |
85 * but we want to keep decoding. Or maybe we want to stop decoding | |
86 * altogether if there is a callback, because obviously we are not | |
87 * sending the data back and they want to know that. | |
88 */ | |
89 if (worker->decryptobj != NULL) { | |
90 /* XXX the following lengths should all be longs? */ | |
91 unsigned int inlen; /* length of data being decrypted */ | |
92 unsigned int outlen; /* length of decrypted data */ | |
93 unsigned int buflen; /* length available for decrypted data */ | |
94 SECItem *plain; | |
95 | |
96 inlen = len; | |
97 buflen = sec_PKCS7DecryptLength (worker->decryptobj, inlen, final); | |
98 if (buflen == 0) { | |
99 if (inlen == 0) /* no input and no output */ | |
100 return; | |
101 /* | |
102 * No output is expected, but the input data may be buffered | |
103 * so we still have to call Decrypt. | |
104 */ | |
105 rv = sec_PKCS7Decrypt (worker->decryptobj, NULL, NULL, 0, | |
106 data, inlen, final); | |
107 if (rv != SECSuccess) { | |
108 p7dcx->error = PORT_GetError(); | |
109 return; /* XXX indicate error? */ | |
110 } | |
111 return; | |
112 } | |
113 | |
114 if (p7dcx->cb != NULL) { | |
115 buf = (unsigned char *) PORT_Alloc (buflen); | |
116 plain = NULL; | |
117 } else { | |
118 unsigned long oldlen; | |
119 | |
120 /* | |
121 * XXX This assumes one level of content only. | |
122 * See comment above about nested content types. | |
123 * XXX Also, it should work for signedAndEnvelopedData, too! | |
124 */ | |
125 plain = &(p7dcx->cinfo-> | |
126 content.envelopedData->encContentInfo.plainContent); | |
127 | |
128 oldlen = plain->len; | |
129 if (oldlen == 0) { | |
130 buf = (unsigned char*)PORT_ArenaAlloc (p7dcx->cinfo->poolp, | |
131 buflen); | |
132 } else { | |
133 buf = (unsigned char*)PORT_ArenaGrow (p7dcx->cinfo->poolp, | |
134 plain->data, | |
135 oldlen, oldlen + buflen); | |
136 if (buf != NULL) | |
137 buf += oldlen; | |
138 } | |
139 plain->data = buf; | |
140 } | |
141 if (buf == NULL) { | |
142 p7dcx->error = SEC_ERROR_NO_MEMORY; | |
143 return; /* XXX indicate error? */ | |
144 } | |
145 rv = sec_PKCS7Decrypt (worker->decryptobj, buf, &outlen, buflen, | |
146 data, inlen, final); | |
147 if (rv != SECSuccess) { | |
148 p7dcx->error = PORT_GetError(); | |
149 return; /* XXX indicate error? */ | |
150 } | |
151 if (plain != NULL) { | |
152 PORT_Assert (final || outlen == buflen); | |
153 plain->len += outlen; | |
154 } | |
155 data = buf; | |
156 len = outlen; | |
157 } | |
158 | |
159 /* | |
160 * Update the running digests. | |
161 */ | |
162 if (len) { | |
163 for (i = 0; i < worker->digcnt; i++) { | |
164 (* worker->digobjs[i]->update) (worker->digcxs[i], data, len); | |
165 } | |
166 } | |
167 | |
168 /* | |
169 * Pass back the contents bytes, and free the temporary buffer. | |
170 */ | |
171 if (p7dcx->cb != NULL) { | |
172 if (len) | |
173 (* p7dcx->cb) (p7dcx->cb_arg, (const char *)data, len); | |
174 if (worker->decryptobj != NULL) { | |
175 PORT_Assert (buf != NULL); | |
176 PORT_Free (buf); | |
177 } | |
178 } | |
179 } | |
180 | |
181 static void | |
182 sec_pkcs7_decoder_filter (void *arg, const char *data, unsigned long len, | |
183 int depth, SEC_ASN1EncodingPart data_kind) | |
184 { | |
185 SEC_PKCS7DecoderContext *p7dcx; | |
186 struct sec_pkcs7_decoder_worker *worker; | |
187 | |
188 /* | |
189 * Since we do not handle any nested contents, the only bytes we | |
190 * are really interested in are the actual contents bytes (not | |
191 * the identifier, length, or end-of-contents bytes). If we were | |
192 * handling nested types we would probably need to do something | |
193 * smarter based on depth and data_kind. | |
194 */ | |
195 if (data_kind != SEC_ASN1_Contents) | |
196 return; | |
197 | |
198 /* | |
199 * The ASN.1 decoder should not even call us with a length of 0. | |
200 * Just being paranoid. | |
201 */ | |
202 PORT_Assert (len); | |
203 if (len == 0) | |
204 return; | |
205 | |
206 p7dcx = (SEC_PKCS7DecoderContext*)arg; | |
207 | |
208 /* | |
209 * Handling nested contents would mean that there is a chain | |
210 * of workers -- one per each level of content. The following | |
211 * would start with the first worker and loop over them. | |
212 */ | |
213 worker = &(p7dcx->worker); | |
214 | |
215 worker->saw_contents = PR_TRUE; | |
216 | |
217 sec_pkcs7_decoder_work_data (p7dcx, worker, | |
218 (const unsigned char *) data, len, PR_FALSE); | |
219 } | |
220 | |
221 | |
222 /* | |
223 * Create digest contexts for each algorithm in "digestalgs". | |
224 * No algorithms is not an error, we just do not do anything. | |
225 * An error (like trouble allocating memory), marks the error | |
226 * in "p7dcx" and returns SECFailure, which means that our caller | |
227 * should just give up altogether. | |
228 */ | |
229 static SECStatus | |
230 sec_pkcs7_decoder_start_digests (SEC_PKCS7DecoderContext *p7dcx, int depth, | |
231 SECAlgorithmID **digestalgs) | |
232 { | |
233 int i, digcnt; | |
234 | |
235 if (digestalgs == NULL) | |
236 return SECSuccess; | |
237 | |
238 /* | |
239 * Count the algorithms. | |
240 */ | |
241 digcnt = 0; | |
242 while (digestalgs[digcnt] != NULL) | |
243 digcnt++; | |
244 | |
245 /* | |
246 * No algorithms means no work to do. | |
247 * Just act as if there were no algorithms specified. | |
248 */ | |
249 if (digcnt == 0) | |
250 return SECSuccess; | |
251 | |
252 p7dcx->worker.digcxs = (void**)PORT_ArenaAlloc (p7dcx->tmp_poolp, | |
253 digcnt * sizeof (void *)); | |
254 p7dcx->worker.digobjs = (const SECHashObject**)PORT_ArenaAlloc (p7dcx->tmp_poolp, | |
255 digcnt * sizeof (SECHashObject *)); | |
256 if (p7dcx->worker.digcxs == NULL || p7dcx->worker.digobjs == NULL) { | |
257 p7dcx->error = SEC_ERROR_NO_MEMORY; | |
258 return SECFailure; | |
259 } | |
260 | |
261 p7dcx->worker.depth = depth; | |
262 p7dcx->worker.digcnt = 0; | |
263 | |
264 /* | |
265 * Create a digest context for each algorithm. | |
266 */ | |
267 for (i = 0; i < digcnt; i++) { | |
268 SECAlgorithmID * algid = digestalgs[i]; | |
269 SECOidTag oidTag = SECOID_FindOIDTag(&(algid->algorithm)); | |
270 const SECHashObject *digobj = HASH_GetHashObjectByOidTag(oidTag); | |
271 void *digcx; | |
272 | |
273 /* | |
274 * Skip any algorithm we do not even recognize; obviously, | |
275 * this could be a problem, but if it is critical then the | |
276 * result will just be that the signature does not verify. | |
277 * We do not necessarily want to error out here, because | |
278 * the particular algorithm may not actually be important, | |
279 * but we cannot know that until later. | |
280 */ | |
281 if (digobj == NULL) { | |
282 p7dcx->worker.digcnt--; | |
283 continue; | |
284 } | |
285 | |
286 digcx = (* digobj->create)(); | |
287 if (digcx != NULL) { | |
288 (* digobj->begin) (digcx); | |
289 p7dcx->worker.digobjs[p7dcx->worker.digcnt] = digobj; | |
290 p7dcx->worker.digcxs[p7dcx->worker.digcnt] = digcx; | |
291 p7dcx->worker.digcnt++; | |
292 } | |
293 } | |
294 | |
295 if (p7dcx->worker.digcnt != 0) | |
296 SEC_ASN1DecoderSetFilterProc (p7dcx->dcx, | |
297 sec_pkcs7_decoder_filter, | |
298 p7dcx, | |
299 (PRBool)(p7dcx->cb != NULL)); | |
300 return SECSuccess; | |
301 } | |
302 | |
303 | |
304 /* | |
305 * Close out all of the digest contexts, storing the results in "digestsp". | |
306 */ | |
307 static SECStatus | |
308 sec_pkcs7_decoder_finish_digests (SEC_PKCS7DecoderContext *p7dcx, | |
309 PLArenaPool *poolp, | |
310 SECItem ***digestsp) | |
311 { | |
312 struct sec_pkcs7_decoder_worker *worker; | |
313 const SECHashObject *digobj; | |
314 void *digcx; | |
315 SECItem **digests, *digest; | |
316 int i; | |
317 void *mark; | |
318 | |
319 /* | |
320 * XXX Handling nested contents would mean that there is a chain | |
321 * of workers -- one per each level of content. The following | |
322 * would want to find the last worker in the chain. | |
323 */ | |
324 worker = &(p7dcx->worker); | |
325 | |
326 /* | |
327 * If no digests, then we have nothing to do. | |
328 */ | |
329 if (worker->digcnt == 0) | |
330 return SECSuccess; | |
331 | |
332 /* | |
333 * No matter what happens after this, we want to stop filtering. | |
334 * XXX If we handle nested contents, we only want to stop filtering | |
335 * if we are finishing off the *last* worker. | |
336 */ | |
337 SEC_ASN1DecoderClearFilterProc (p7dcx->dcx); | |
338 | |
339 /* | |
340 * If we ended up with no contents, just destroy each | |
341 * digest context -- they are meaningless and potentially | |
342 * confusing, because their presence would imply some content | |
343 * was digested. | |
344 */ | |
345 if (! worker->saw_contents) { | |
346 for (i = 0; i < worker->digcnt; i++) { | |
347 digcx = worker->digcxs[i]; | |
348 digobj = worker->digobjs[i]; | |
349 (* digobj->destroy) (digcx, PR_TRUE); | |
350 } | |
351 return SECSuccess; | |
352 } | |
353 | |
354 mark = PORT_ArenaMark (poolp); | |
355 | |
356 /* | |
357 * Close out each digest context, saving digest away. | |
358 */ | |
359 digests = | |
360 (SECItem**)PORT_ArenaAlloc (poolp,(worker->digcnt+1)*sizeof(SECItem *)); | |
361 digest = (SECItem*)PORT_ArenaAlloc (poolp, worker->digcnt*sizeof(SECItem)); | |
362 if (digests == NULL || digest == NULL) { | |
363 p7dcx->error = PORT_GetError(); | |
364 PORT_ArenaRelease (poolp, mark); | |
365 return SECFailure; | |
366 } | |
367 | |
368 for (i = 0; i < worker->digcnt; i++, digest++) { | |
369 digcx = worker->digcxs[i]; | |
370 digobj = worker->digobjs[i]; | |
371 | |
372 digest->data = (unsigned char*)PORT_ArenaAlloc (poolp, digobj->length); | |
373 if (digest->data == NULL) { | |
374 p7dcx->error = PORT_GetError(); | |
375 PORT_ArenaRelease (poolp, mark); | |
376 return SECFailure; | |
377 } | |
378 | |
379 digest->len = digobj->length; | |
380 (* digobj->end) (digcx, digest->data, &(digest->len), digest->len); | |
381 (* digobj->destroy) (digcx, PR_TRUE); | |
382 | |
383 digests[i] = digest; | |
384 } | |
385 digests[i] = NULL; | |
386 *digestsp = digests; | |
387 | |
388 PORT_ArenaUnmark (poolp, mark); | |
389 return SECSuccess; | |
390 } | |
391 | |
392 /* | |
393 * XXX Need comment explaining following helper function (which is used | |
394 * by sec_pkcs7_decoder_start_decrypt). | |
395 */ | |
396 | |
397 static PK11SymKey * | |
398 sec_pkcs7_decoder_get_recipient_key (SEC_PKCS7DecoderContext *p7dcx, | |
399 SEC_PKCS7RecipientInfo **recipientinfos, | |
400 SEC_PKCS7EncryptedContentInfo *enccinfo) | |
401 { | |
402 SEC_PKCS7RecipientInfo *ri; | |
403 CERTCertificate *cert = NULL; | |
404 SECKEYPrivateKey *privkey = NULL; | |
405 PK11SymKey *bulkkey = NULL; | |
406 SECOidTag keyalgtag, bulkalgtag, encalgtag; | |
407 PK11SlotInfo *slot = NULL; | |
408 | |
409 if (recipientinfos == NULL || recipientinfos[0] == NULL) { | |
410 p7dcx->error = SEC_ERROR_NOT_A_RECIPIENT; | |
411 goto no_key_found; | |
412 } | |
413 | |
414 cert = PK11_FindCertAndKeyByRecipientList(&slot,recipientinfos,&ri, | |
415 &privkey, p7dcx->pwfn_arg); | |
416 if (cert == NULL) { | |
417 p7dcx->error = SEC_ERROR_NOT_A_RECIPIENT; | |
418 goto no_key_found; | |
419 } | |
420 | |
421 ri->cert = cert; /* so we can find it later */ | |
422 PORT_Assert(privkey != NULL); | |
423 | |
424 keyalgtag = SECOID_GetAlgorithmTag(&(cert->subjectPublicKeyInfo.algorithm)); | |
425 encalgtag = SECOID_GetAlgorithmTag (&(ri->keyEncAlg)); | |
426 if (keyalgtag != encalgtag) { | |
427 p7dcx->error = SEC_ERROR_PKCS7_KEYALG_MISMATCH; | |
428 goto no_key_found; | |
429 } | |
430 bulkalgtag = SECOID_GetAlgorithmTag (&(enccinfo->contentEncAlg)); | |
431 | |
432 switch (encalgtag) { | |
433 case SEC_OID_PKCS1_RSA_ENCRYPTION: | |
434 bulkkey = PK11_PubUnwrapSymKey (privkey, &ri->encKey, | |
435 PK11_AlgtagToMechanism (bulkalgtag), | |
436 CKA_DECRYPT, 0); | |
437 if (bulkkey == NULL) { | |
438 p7dcx->error = PORT_GetError(); | |
439 PORT_SetError(0); | |
440 goto no_key_found; | |
441 } | |
442 break; | |
443 default: | |
444 p7dcx->error = SEC_ERROR_UNSUPPORTED_KEYALG; | |
445 break; | |
446 } | |
447 | |
448 no_key_found: | |
449 if (privkey != NULL) | |
450 SECKEY_DestroyPrivateKey (privkey); | |
451 if (slot != NULL) | |
452 PK11_FreeSlot(slot); | |
453 | |
454 return bulkkey; | |
455 } | |
456 | |
457 /* | |
458 * XXX The following comment is old -- the function used to only handle | |
459 * EnvelopedData or SignedAndEnvelopedData but now handles EncryptedData | |
460 * as well (and it had all of the code of the helper function above | |
461 * built into it), though the comment was left as is. Fix it... | |
462 * | |
463 * We are just about to decode the content of an EnvelopedData. | |
464 * Set up a decryption context so we can decrypt as we go. | |
465 * Presumably we are one of the recipients listed in "recipientinfos". | |
466 * (XXX And if we are not, or if we have trouble, what should we do? | |
467 * It would be nice to let the decoding still work. Maybe it should | |
468 * be an error if there is a content callback, but not an error otherwise?) | |
469 * The encryption key and related information can be found in "enccinfo". | |
470 */ | |
471 static SECStatus | |
472 sec_pkcs7_decoder_start_decrypt (SEC_PKCS7DecoderContext *p7dcx, int depth, | |
473 SEC_PKCS7RecipientInfo **recipientinfos, | |
474 SEC_PKCS7EncryptedContentInfo *enccinfo, | |
475 PK11SymKey **copy_key_for_signature) | |
476 { | |
477 PK11SymKey *bulkkey = NULL; | |
478 sec_PKCS7CipherObject *decryptobj; | |
479 | |
480 /* | |
481 * If a callback is supplied to retrieve the encryption key, | |
482 * for instance, for Encrypted Content infos, then retrieve | |
483 * the bulkkey from the callback. Otherwise, assume that | |
484 * we are processing Enveloped or SignedAndEnveloped data | |
485 * content infos. | |
486 * | |
487 * XXX Put an assert here? | |
488 */ | |
489 if (SEC_PKCS7ContentType(p7dcx->cinfo) == SEC_OID_PKCS7_ENCRYPTED_DATA) { | |
490 if (p7dcx->dkcb != NULL) { | |
491 bulkkey = (*p7dcx->dkcb)(p7dcx->dkcb_arg, | |
492 &(enccinfo->contentEncAlg)); | |
493 } | |
494 enccinfo->keysize = 0; | |
495 } else { | |
496 bulkkey = sec_pkcs7_decoder_get_recipient_key (p7dcx, recipientinfos, | |
497 enccinfo); | |
498 if (bulkkey == NULL) goto no_decryption; | |
499 enccinfo->keysize = PK11_GetKeyStrength(bulkkey, | |
500 &(enccinfo->contentEncAlg)); | |
501 | |
502 } | |
503 | |
504 /* | |
505 * XXX I think following should set error in p7dcx and clear set error | |
506 * (as used to be done here, or as is done in get_receipient_key above. | |
507 */ | |
508 if(bulkkey == NULL) { | |
509 goto no_decryption; | |
510 } | |
511 | |
512 /* | |
513 * We want to make sure decryption is allowed. This is done via | |
514 * a callback specified in SEC_PKCS7DecoderStart(). | |
515 */ | |
516 if (p7dcx->decrypt_allowed_cb) { | |
517 if ((*p7dcx->decrypt_allowed_cb) (&(enccinfo->contentEncAlg), | |
518 bulkkey) == PR_FALSE) { | |
519 p7dcx->error = SEC_ERROR_DECRYPTION_DISALLOWED; | |
520 goto no_decryption; | |
521 } | |
522 } else { | |
523 p7dcx->error = SEC_ERROR_DECRYPTION_DISALLOWED; | |
524 goto no_decryption; | |
525 } | |
526 | |
527 /* | |
528 * When decrypting a signedAndEnvelopedData, the signature also has | |
529 * to be decrypted with the bulk encryption key; to avoid having to | |
530 * get it all over again later (and do another potentially expensive | |
531 * RSA operation), copy it for later signature verification to use. | |
532 */ | |
533 if (copy_key_for_signature != NULL) | |
534 *copy_key_for_signature = PK11_ReferenceSymKey (bulkkey); | |
535 | |
536 /* | |
537 * Now we have the bulk encryption key (in bulkkey) and the | |
538 * the algorithm (in enccinfo->contentEncAlg). Using those, | |
539 * create a decryption context. | |
540 */ | |
541 decryptobj = sec_PKCS7CreateDecryptObject (bulkkey, | |
542 &(enccinfo->contentEncAlg)); | |
543 | |
544 /* | |
545 * We are done with (this) bulkkey now. | |
546 */ | |
547 PK11_FreeSymKey (bulkkey); | |
548 | |
549 if (decryptobj == NULL) { | |
550 p7dcx->error = PORT_GetError(); | |
551 PORT_SetError(0); | |
552 goto no_decryption; | |
553 } | |
554 | |
555 SEC_ASN1DecoderSetFilterProc (p7dcx->dcx, | |
556 sec_pkcs7_decoder_filter, | |
557 p7dcx, | |
558 (PRBool)(p7dcx->cb != NULL)); | |
559 | |
560 p7dcx->worker.depth = depth; | |
561 p7dcx->worker.decryptobj = decryptobj; | |
562 | |
563 return SECSuccess; | |
564 | |
565 no_decryption: | |
566 /* | |
567 * For some reason (error set already, if appropriate), we cannot | |
568 * decrypt the content. I am not sure what exactly is the right | |
569 * thing to do here; in some cases we want to just stop, and in | |
570 * others we want to let the decoding finish even though we cannot | |
571 * decrypt the content. My current thinking is that if the caller | |
572 * set up a content callback, then they are really interested in | |
573 * getting (decrypted) content, and if they cannot they will want | |
574 * to know about it. However, if no callback was specified, then | |
575 * maybe it is not important that the decryption failed. | |
576 */ | |
577 if (p7dcx->cb != NULL) | |
578 return SECFailure; | |
579 else | |
580 return SECSuccess; /* Let the decoding continue. */ | |
581 } | |
582 | |
583 | |
584 static SECStatus | |
585 sec_pkcs7_decoder_finish_decrypt (SEC_PKCS7DecoderContext *p7dcx, | |
586 PLArenaPool *poolp, | |
587 SEC_PKCS7EncryptedContentInfo *enccinfo) | |
588 { | |
589 struct sec_pkcs7_decoder_worker *worker; | |
590 | |
591 /* | |
592 * XXX Handling nested contents would mean that there is a chain | |
593 * of workers -- one per each level of content. The following | |
594 * would want to find the last worker in the chain. | |
595 */ | |
596 worker = &(p7dcx->worker); | |
597 | |
598 /* | |
599 * If no decryption context, then we have nothing to do. | |
600 */ | |
601 if (worker->decryptobj == NULL) | |
602 return SECSuccess; | |
603 | |
604 /* | |
605 * No matter what happens after this, we want to stop filtering. | |
606 * XXX If we handle nested contents, we only want to stop filtering | |
607 * if we are finishing off the *last* worker. | |
608 */ | |
609 SEC_ASN1DecoderClearFilterProc (p7dcx->dcx); | |
610 | |
611 /* | |
612 * Handle the last block. | |
613 */ | |
614 sec_pkcs7_decoder_work_data (p7dcx, worker, NULL, 0, PR_TRUE); | |
615 | |
616 /* | |
617 * All done, destroy it. | |
618 */ | |
619 sec_PKCS7DestroyDecryptObject (worker->decryptobj); | |
620 worker->decryptobj = NULL; | |
621 | |
622 return SECSuccess; | |
623 } | |
624 | |
625 | |
626 static void | |
627 sec_pkcs7_decoder_notify (void *arg, PRBool before, void *dest, int depth) | |
628 { | |
629 SEC_PKCS7DecoderContext *p7dcx; | |
630 SEC_PKCS7ContentInfo *cinfo; | |
631 SEC_PKCS7SignedData *sigd; | |
632 SEC_PKCS7EnvelopedData *envd; | |
633 SEC_PKCS7SignedAndEnvelopedData *saed; | |
634 SEC_PKCS7EncryptedData *encd; | |
635 SEC_PKCS7DigestedData *digd; | |
636 PRBool after; | |
637 SECStatus rv; | |
638 | |
639 /* | |
640 * Just to make the code easier to read, create an "after" variable | |
641 * that is equivalent to "not before". | |
642 * (This used to be just the statement "after = !before", but that | |
643 * causes a warning on the mac; to avoid that, we do it the long way.) | |
644 */ | |
645 if (before) | |
646 after = PR_FALSE; | |
647 else | |
648 after = PR_TRUE; | |
649 | |
650 p7dcx = (SEC_PKCS7DecoderContext*)arg; | |
651 cinfo = p7dcx->cinfo; | |
652 | |
653 if (cinfo->contentTypeTag == NULL) { | |
654 if (after && dest == &(cinfo->contentType)) | |
655 cinfo->contentTypeTag = SECOID_FindOID(&(cinfo->contentType)); | |
656 return; | |
657 } | |
658 | |
659 switch (cinfo->contentTypeTag->offset) { | |
660 case SEC_OID_PKCS7_SIGNED_DATA: | |
661 sigd = cinfo->content.signedData; | |
662 if (sigd == NULL) | |
663 break; | |
664 | |
665 if (sigd->contentInfo.contentTypeTag == NULL) { | |
666 if (after && dest == &(sigd->contentInfo.contentType)) | |
667 sigd->contentInfo.contentTypeTag = | |
668 SECOID_FindOID(&(sigd->contentInfo.contentType)); | |
669 break; | |
670 } | |
671 | |
672 /* | |
673 * We only set up a filtering digest if the content is | |
674 * plain DATA; anything else needs more work because a | |
675 * second pass is required to produce a DER encoding from | |
676 * an input that can be BER encoded. (This is a requirement | |
677 * of PKCS7 that is unfortunate, but there you have it.) | |
678 * | |
679 * XXX Also, since we stop here if this is not DATA, the | |
680 * inner content is not getting processed at all. Someday | |
681 * we may want to fix that. | |
682 */ | |
683 if (sigd->contentInfo.contentTypeTag->offset != SEC_OID_PKCS7_DATA) { | |
684 /* XXX Set an error in p7dcx->error */ | |
685 SEC_ASN1DecoderClearNotifyProc (p7dcx->dcx); | |
686 break; | |
687 } | |
688 | |
689 /* | |
690 * Just before the content, we want to set up a digest context | |
691 * for each digest algorithm listed, and start a filter which | |
692 * will run all of the contents bytes through that digest. | |
693 */ | |
694 if (before && dest == &(sigd->contentInfo.content)) { | |
695 rv = sec_pkcs7_decoder_start_digests (p7dcx, depth, | |
696 sigd->digestAlgorithms); | |
697 if (rv != SECSuccess) | |
698 SEC_ASN1DecoderClearNotifyProc (p7dcx->dcx); | |
699 | |
700 break; | |
701 } | |
702 | |
703 /* | |
704 * XXX To handle nested types, here is where we would want | |
705 * to check for inner boundaries that need handling. | |
706 */ | |
707 | |
708 /* | |
709 * Are we done? | |
710 */ | |
711 if (after && dest == &(sigd->contentInfo.content)) { | |
712 /* | |
713 * Close out the digest contexts. We ignore any error | |
714 * because we are stopping anyway; the error status left | |
715 * behind in p7dcx will be seen by outer functions. | |
716 */ | |
717 (void) sec_pkcs7_decoder_finish_digests (p7dcx, cinfo->poolp, | |
718 &(sigd->digests)); | |
719 | |
720 /* | |
721 * XXX To handle nested contents, we would need to remove | |
722 * the worker from the chain (and free it). | |
723 */ | |
724 | |
725 /* | |
726 * Stop notify. | |
727 */ | |
728 SEC_ASN1DecoderClearNotifyProc (p7dcx->dcx); | |
729 } | |
730 break; | |
731 | |
732 case SEC_OID_PKCS7_ENVELOPED_DATA: | |
733 envd = cinfo->content.envelopedData; | |
734 if (envd == NULL) | |
735 break; | |
736 | |
737 if (envd->encContentInfo.contentTypeTag == NULL) { | |
738 if (after && dest == &(envd->encContentInfo.contentType)) | |
739 envd->encContentInfo.contentTypeTag = | |
740 SECOID_FindOID(&(envd->encContentInfo.contentType)); | |
741 break; | |
742 } | |
743 | |
744 /* | |
745 * Just before the content, we want to set up a decryption | |
746 * context, and start a filter which will run all of the | |
747 * contents bytes through it to determine the plain content. | |
748 */ | |
749 if (before && dest == &(envd->encContentInfo.encContent)) { | |
750 rv = sec_pkcs7_decoder_start_decrypt (p7dcx, depth, | |
751 envd->recipientInfos, | |
752 &(envd->encContentInfo), | |
753 NULL); | |
754 if (rv != SECSuccess) | |
755 SEC_ASN1DecoderClearNotifyProc (p7dcx->dcx); | |
756 | |
757 break; | |
758 } | |
759 | |
760 /* | |
761 * Are we done? | |
762 */ | |
763 if (after && dest == &(envd->encContentInfo.encContent)) { | |
764 /* | |
765 * Close out the decryption context. We ignore any error | |
766 * because we are stopping anyway; the error status left | |
767 * behind in p7dcx will be seen by outer functions. | |
768 */ | |
769 (void) sec_pkcs7_decoder_finish_decrypt (p7dcx, cinfo->poolp, | |
770 &(envd->encContentInfo)); | |
771 | |
772 /* | |
773 * XXX To handle nested contents, we would need to remove | |
774 * the worker from the chain (and free it). | |
775 */ | |
776 | |
777 /* | |
778 * Stop notify. | |
779 */ | |
780 SEC_ASN1DecoderClearNotifyProc (p7dcx->dcx); | |
781 } | |
782 break; | |
783 | |
784 case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA: | |
785 saed = cinfo->content.signedAndEnvelopedData; | |
786 if (saed == NULL) | |
787 break; | |
788 | |
789 if (saed->encContentInfo.contentTypeTag == NULL) { | |
790 if (after && dest == &(saed->encContentInfo.contentType)) | |
791 saed->encContentInfo.contentTypeTag = | |
792 SECOID_FindOID(&(saed->encContentInfo.contentType)); | |
793 break; | |
794 } | |
795 | |
796 /* | |
797 * Just before the content, we want to set up a decryption | |
798 * context *and* digest contexts, and start a filter which | |
799 * will run all of the contents bytes through both. | |
800 */ | |
801 if (before && dest == &(saed->encContentInfo.encContent)) { | |
802 rv = sec_pkcs7_decoder_start_decrypt (p7dcx, depth, | |
803 saed->recipientInfos, | |
804 &(saed->encContentInfo), | |
805 &(saed->sigKey)); | |
806 if (rv == SECSuccess) | |
807 rv = sec_pkcs7_decoder_start_digests (p7dcx, depth, | |
808 saed->digestAlgorithms); | |
809 if (rv != SECSuccess) | |
810 SEC_ASN1DecoderClearNotifyProc (p7dcx->dcx); | |
811 | |
812 break; | |
813 } | |
814 | |
815 /* | |
816 * Are we done? | |
817 */ | |
818 if (after && dest == &(saed->encContentInfo.encContent)) { | |
819 /* | |
820 * Close out the decryption and digests contexts. | |
821 * We ignore any errors because we are stopping anyway; | |
822 * the error status left behind in p7dcx will be seen by | |
823 * outer functions. | |
824 * | |
825 * Note that the decrypt stuff must be called first; | |
826 * it may have a last buffer to do which in turn has | |
827 * to be added to the digest. | |
828 */ | |
829 (void) sec_pkcs7_decoder_finish_decrypt (p7dcx, cinfo->poolp, | |
830 &(saed->encContentInfo)); | |
831 (void) sec_pkcs7_decoder_finish_digests (p7dcx, cinfo->poolp, | |
832 &(saed->digests)); | |
833 | |
834 /* | |
835 * XXX To handle nested contents, we would need to remove | |
836 * the worker from the chain (and free it). | |
837 */ | |
838 | |
839 /* | |
840 * Stop notify. | |
841 */ | |
842 SEC_ASN1DecoderClearNotifyProc (p7dcx->dcx); | |
843 } | |
844 break; | |
845 | |
846 case SEC_OID_PKCS7_DIGESTED_DATA: | |
847 digd = cinfo->content.digestedData; | |
848 | |
849 /* | |
850 * XXX Want to do the digest or not? Maybe future enhancement... | |
851 */ | |
852 if (before && dest == &(digd->contentInfo.content.data)) { | |
853 SEC_ASN1DecoderSetFilterProc (p7dcx->dcx, sec_pkcs7_decoder_filter, | |
854 p7dcx, | |
855 (PRBool)(p7dcx->cb != NULL)); | |
856 break; | |
857 } | |
858 | |
859 /* | |
860 * Are we done? | |
861 */ | |
862 if (after && dest == &(digd->contentInfo.content.data)) { | |
863 SEC_ASN1DecoderClearFilterProc (p7dcx->dcx); | |
864 } | |
865 break; | |
866 | |
867 case SEC_OID_PKCS7_ENCRYPTED_DATA: | |
868 encd = cinfo->content.encryptedData; | |
869 | |
870 /* | |
871 * XXX If the decryption key callback is set, we want to start | |
872 * the decryption. If the callback is not set, we will treat the | |
873 * content as plain data, since we do not have the key. | |
874 * | |
875 * Is this the proper thing to do? | |
876 */ | |
877 if (before && dest == &(encd->encContentInfo.encContent)) { | |
878 /* | |
879 * Start the encryption process if the decryption key callback | |
880 * is present. Otherwise, treat the content like plain data. | |
881 */ | |
882 rv = SECSuccess; | |
883 if (p7dcx->dkcb != NULL) { | |
884 rv = sec_pkcs7_decoder_start_decrypt (p7dcx, depth, NULL, | |
885 &(encd->encContentInfo), | |
886 NULL); | |
887 } | |
888 | |
889 if (rv != SECSuccess) | |
890 SEC_ASN1DecoderClearNotifyProc (p7dcx->dcx); | |
891 | |
892 break; | |
893 } | |
894 | |
895 /* | |
896 * Are we done? | |
897 */ | |
898 if (after && dest == &(encd->encContentInfo.encContent)) { | |
899 /* | |
900 * Close out the decryption context. We ignore any error | |
901 * because we are stopping anyway; the error status left | |
902 * behind in p7dcx will be seen by outer functions. | |
903 */ | |
904 (void) sec_pkcs7_decoder_finish_decrypt (p7dcx, cinfo->poolp, | |
905 &(encd->encContentInfo)); | |
906 | |
907 /* | |
908 * Stop notify. | |
909 */ | |
910 SEC_ASN1DecoderClearNotifyProc (p7dcx->dcx); | |
911 } | |
912 break; | |
913 | |
914 case SEC_OID_PKCS7_DATA: | |
915 /* | |
916 * If a output callback has been specified, we want to set the filter | |
917 * to call the callback. This is taken care of in | |
918 * sec_pkcs7_decoder_start_decrypt() or | |
919 * sec_pkcs7_decoder_start_digests() for the other content types. | |
920 */ | |
921 | |
922 if (before && dest == &(cinfo->content.data)) { | |
923 | |
924 /* | |
925 * Set the filter proc up. | |
926 */ | |
927 SEC_ASN1DecoderSetFilterProc (p7dcx->dcx, | |
928 sec_pkcs7_decoder_filter, | |
929 p7dcx, | |
930 (PRBool)(p7dcx->cb != NULL)); | |
931 break; | |
932 } | |
933 | |
934 if (after && dest == &(cinfo->content.data)) { | |
935 /* | |
936 * Time to clean up after ourself, stop the Notify and Filter | |
937 * procedures. | |
938 */ | |
939 SEC_ASN1DecoderClearNotifyProc (p7dcx->dcx); | |
940 SEC_ASN1DecoderClearFilterProc (p7dcx->dcx); | |
941 } | |
942 break; | |
943 | |
944 default: | |
945 SEC_ASN1DecoderClearNotifyProc (p7dcx->dcx); | |
946 break; | |
947 } | |
948 } | |
949 | |
950 | |
951 SEC_PKCS7DecoderContext * | |
952 SEC_PKCS7DecoderStart(SEC_PKCS7DecoderContentCallback cb, void *cb_arg, | |
953 SECKEYGetPasswordKey pwfn, void *pwfn_arg, | |
954 SEC_PKCS7GetDecryptKeyCallback decrypt_key_cb, | |
955 void *decrypt_key_cb_arg, | |
956 SEC_PKCS7DecryptionAllowedCallback decrypt_allowed_cb) | |
957 { | |
958 SEC_PKCS7DecoderContext *p7dcx; | |
959 SEC_ASN1DecoderContext *dcx; | |
960 SEC_PKCS7ContentInfo *cinfo; | |
961 PLArenaPool *poolp; | |
962 | |
963 poolp = PORT_NewArena (1024); /* XXX what is right value? */ | |
964 if (poolp == NULL) | |
965 return NULL; | |
966 | |
967 cinfo = (SEC_PKCS7ContentInfo*)PORT_ArenaZAlloc (poolp, sizeof(*cinfo)); | |
968 if (cinfo == NULL) { | |
969 PORT_FreeArena (poolp, PR_FALSE); | |
970 return NULL; | |
971 } | |
972 | |
973 cinfo->poolp = poolp; | |
974 cinfo->pwfn = pwfn; | |
975 cinfo->pwfn_arg = pwfn_arg; | |
976 cinfo->created = PR_FALSE; | |
977 cinfo->refCount = 1; | |
978 | |
979 p7dcx = | |
980 (SEC_PKCS7DecoderContext*)PORT_ZAlloc (sizeof(SEC_PKCS7DecoderContext)); | |
981 if (p7dcx == NULL) { | |
982 PORT_FreeArena (poolp, PR_FALSE); | |
983 return NULL; | |
984 } | |
985 | |
986 p7dcx->tmp_poolp = PORT_NewArena (1024); /* XXX what is right value? */ | |
987 if (p7dcx->tmp_poolp == NULL) { | |
988 PORT_Free (p7dcx); | |
989 PORT_FreeArena (poolp, PR_FALSE); | |
990 return NULL; | |
991 } | |
992 | |
993 dcx = SEC_ASN1DecoderStart (poolp, cinfo, sec_PKCS7ContentInfoTemplate); | |
994 if (dcx == NULL) { | |
995 PORT_FreeArena (p7dcx->tmp_poolp, PR_FALSE); | |
996 PORT_Free (p7dcx); | |
997 PORT_FreeArena (poolp, PR_FALSE); | |
998 return NULL; | |
999 } | |
1000 | |
1001 SEC_ASN1DecoderSetNotifyProc (dcx, sec_pkcs7_decoder_notify, p7dcx); | |
1002 | |
1003 p7dcx->dcx = dcx; | |
1004 p7dcx->cinfo = cinfo; | |
1005 p7dcx->cb = cb; | |
1006 p7dcx->cb_arg = cb_arg; | |
1007 p7dcx->pwfn = pwfn; | |
1008 p7dcx->pwfn_arg = pwfn_arg; | |
1009 p7dcx->dkcb = decrypt_key_cb; | |
1010 p7dcx->dkcb_arg = decrypt_key_cb_arg; | |
1011 p7dcx->decrypt_allowed_cb = decrypt_allowed_cb; | |
1012 | |
1013 return p7dcx; | |
1014 } | |
1015 | |
1016 | |
1017 /* | |
1018 * Do the next chunk of PKCS7 decoding. If there is a problem, set | |
1019 * an error and return a failure status. Note that in the case of | |
1020 * an error, this routine is still prepared to be called again and | |
1021 * again in case that is the easiest route for our caller to take. | |
1022 * We simply detect it and do not do anything except keep setting | |
1023 * that error in case our caller has not noticed it yet... | |
1024 */ | |
1025 SECStatus | |
1026 SEC_PKCS7DecoderUpdate(SEC_PKCS7DecoderContext *p7dcx, | |
1027 const char *buf, unsigned long len) | |
1028 { | |
1029 if (p7dcx->cinfo != NULL && p7dcx->dcx != NULL) { | |
1030 PORT_Assert (p7dcx->error == 0); | |
1031 if (p7dcx->error == 0) { | |
1032 if (SEC_ASN1DecoderUpdate (p7dcx->dcx, buf, len) != SECSuccess) { | |
1033 p7dcx->error = PORT_GetError(); | |
1034 PORT_Assert (p7dcx->error); | |
1035 if (p7dcx->error == 0) | |
1036 p7dcx->error = -1; | |
1037 } | |
1038 } | |
1039 } | |
1040 | |
1041 if (p7dcx->error) { | |
1042 if (p7dcx->dcx != NULL) { | |
1043 (void) SEC_ASN1DecoderFinish (p7dcx->dcx); | |
1044 p7dcx->dcx = NULL; | |
1045 } | |
1046 if (p7dcx->cinfo != NULL) { | |
1047 SEC_PKCS7DestroyContentInfo (p7dcx->cinfo); | |
1048 p7dcx->cinfo = NULL; | |
1049 } | |
1050 PORT_SetError (p7dcx->error); | |
1051 return SECFailure; | |
1052 } | |
1053 | |
1054 return SECSuccess; | |
1055 } | |
1056 | |
1057 | |
1058 SEC_PKCS7ContentInfo * | |
1059 SEC_PKCS7DecoderFinish(SEC_PKCS7DecoderContext *p7dcx) | |
1060 { | |
1061 SEC_PKCS7ContentInfo *cinfo; | |
1062 | |
1063 cinfo = p7dcx->cinfo; | |
1064 if (p7dcx->dcx != NULL) { | |
1065 if (SEC_ASN1DecoderFinish (p7dcx->dcx) != SECSuccess) { | |
1066 SEC_PKCS7DestroyContentInfo (cinfo); | |
1067 cinfo = NULL; | |
1068 } | |
1069 } | |
1070 /* free any NSS data structures */ | |
1071 if (p7dcx->worker.decryptobj) { | |
1072 sec_PKCS7DestroyDecryptObject (p7dcx->worker.decryptobj); | |
1073 } | |
1074 PORT_FreeArena (p7dcx->tmp_poolp, PR_FALSE); | |
1075 PORT_Free (p7dcx); | |
1076 return cinfo; | |
1077 } | |
1078 | |
1079 | |
1080 SEC_PKCS7ContentInfo * | |
1081 SEC_PKCS7DecodeItem(SECItem *p7item, | |
1082 SEC_PKCS7DecoderContentCallback cb, void *cb_arg, | |
1083 SECKEYGetPasswordKey pwfn, void *pwfn_arg, | |
1084 SEC_PKCS7GetDecryptKeyCallback decrypt_key_cb, | |
1085 void *decrypt_key_cb_arg, | |
1086 SEC_PKCS7DecryptionAllowedCallback decrypt_allowed_cb) | |
1087 { | |
1088 SEC_PKCS7DecoderContext *p7dcx; | |
1089 | |
1090 p7dcx = SEC_PKCS7DecoderStart(cb, cb_arg, pwfn, pwfn_arg, decrypt_key_cb, | |
1091 decrypt_key_cb_arg, decrypt_allowed_cb); | |
1092 if (!p7dcx) { | |
1093 /* error code is set */ | |
1094 return NULL; | |
1095 } | |
1096 (void) SEC_PKCS7DecoderUpdate(p7dcx, (char *) p7item->data, p7item->len); | |
1097 return SEC_PKCS7DecoderFinish(p7dcx); | |
1098 } | |
1099 | |
1100 /* | |
1101 * Abort the ASN.1 stream. Used by pkcs 12 | |
1102 */ | |
1103 void | |
1104 SEC_PKCS7DecoderAbort(SEC_PKCS7DecoderContext *p7dcx, int error) | |
1105 { | |
1106 PORT_Assert(p7dcx); | |
1107 SEC_ASN1DecoderAbort(p7dcx->dcx, error); | |
1108 } | |
1109 | |
1110 | |
1111 /* | |
1112 * If the thing contains any certs or crls return true; false otherwise. | |
1113 */ | |
1114 PRBool | |
1115 SEC_PKCS7ContainsCertsOrCrls(SEC_PKCS7ContentInfo *cinfo) | |
1116 { | |
1117 SECOidTag kind; | |
1118 SECItem **certs; | |
1119 CERTSignedCrl **crls; | |
1120 | |
1121 kind = SEC_PKCS7ContentType (cinfo); | |
1122 switch (kind) { | |
1123 default: | |
1124 case SEC_OID_PKCS7_DATA: | |
1125 case SEC_OID_PKCS7_DIGESTED_DATA: | |
1126 case SEC_OID_PKCS7_ENVELOPED_DATA: | |
1127 case SEC_OID_PKCS7_ENCRYPTED_DATA: | |
1128 return PR_FALSE; | |
1129 case SEC_OID_PKCS7_SIGNED_DATA: | |
1130 certs = cinfo->content.signedData->rawCerts; | |
1131 crls = cinfo->content.signedData->crls; | |
1132 break; | |
1133 case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA: | |
1134 certs = cinfo->content.signedAndEnvelopedData->rawCerts; | |
1135 crls = cinfo->content.signedAndEnvelopedData->crls; | |
1136 break; | |
1137 } | |
1138 | |
1139 /* | |
1140 * I know this could be collapsed, but I was in a mood to be explicit. | |
1141 */ | |
1142 if (certs != NULL && certs[0] != NULL) | |
1143 return PR_TRUE; | |
1144 else if (crls != NULL && crls[0] != NULL) | |
1145 return PR_TRUE; | |
1146 else | |
1147 return PR_FALSE; | |
1148 } | |
1149 | |
1150 /* return the content length...could use GetContent, however we | |
1151 * need the encrypted content length | |
1152 */ | |
1153 PRBool | |
1154 SEC_PKCS7IsContentEmpty(SEC_PKCS7ContentInfo *cinfo, unsigned int minLen) | |
1155 { | |
1156 SECItem *item = NULL; | |
1157 | |
1158 if(cinfo == NULL) { | |
1159 return PR_TRUE; | |
1160 } | |
1161 | |
1162 switch(SEC_PKCS7ContentType(cinfo)) | |
1163 { | |
1164 case SEC_OID_PKCS7_DATA: | |
1165 item = cinfo->content.data; | |
1166 break; | |
1167 case SEC_OID_PKCS7_ENCRYPTED_DATA: | |
1168 item = &cinfo->content.encryptedData->encContentInfo.encContent; | |
1169 break; | |
1170 default: | |
1171 /* add other types */ | |
1172 return PR_FALSE; | |
1173 } | |
1174 | |
1175 if(!item) { | |
1176 return PR_TRUE; | |
1177 } else if(item->len <= minLen) { | |
1178 return PR_TRUE; | |
1179 } | |
1180 | |
1181 return PR_FALSE; | |
1182 } | |
1183 | |
1184 | |
1185 PRBool | |
1186 SEC_PKCS7ContentIsEncrypted(SEC_PKCS7ContentInfo *cinfo) | |
1187 { | |
1188 SECOidTag kind; | |
1189 | |
1190 kind = SEC_PKCS7ContentType (cinfo); | |
1191 switch (kind) { | |
1192 default: | |
1193 case SEC_OID_PKCS7_DATA: | |
1194 case SEC_OID_PKCS7_DIGESTED_DATA: | |
1195 case SEC_OID_PKCS7_SIGNED_DATA: | |
1196 return PR_FALSE; | |
1197 case SEC_OID_PKCS7_ENCRYPTED_DATA: | |
1198 case SEC_OID_PKCS7_ENVELOPED_DATA: | |
1199 case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA: | |
1200 return PR_TRUE; | |
1201 } | |
1202 } | |
1203 | |
1204 | |
1205 /* | |
1206 * If the PKCS7 content has a signature (not just *could* have a signature) | |
1207 * return true; false otherwise. This can/should be called before calling | |
1208 * VerifySignature, which will always indicate failure if no signature is | |
1209 * present, but that does not mean there even was a signature! | |
1210 * Note that the content itself can be empty (detached content was sent | |
1211 * another way); it is the presence of the signature that matters. | |
1212 */ | |
1213 PRBool | |
1214 SEC_PKCS7ContentIsSigned(SEC_PKCS7ContentInfo *cinfo) | |
1215 { | |
1216 SECOidTag kind; | |
1217 SEC_PKCS7SignerInfo **signerinfos; | |
1218 | |
1219 kind = SEC_PKCS7ContentType (cinfo); | |
1220 switch (kind) { | |
1221 default: | |
1222 case SEC_OID_PKCS7_DATA: | |
1223 case SEC_OID_PKCS7_DIGESTED_DATA: | |
1224 case SEC_OID_PKCS7_ENVELOPED_DATA: | |
1225 case SEC_OID_PKCS7_ENCRYPTED_DATA: | |
1226 return PR_FALSE; | |
1227 case SEC_OID_PKCS7_SIGNED_DATA: | |
1228 signerinfos = cinfo->content.signedData->signerInfos; | |
1229 break; | |
1230 case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA: | |
1231 signerinfos = cinfo->content.signedAndEnvelopedData->signerInfos; | |
1232 break; | |
1233 } | |
1234 | |
1235 /* | |
1236 * I know this could be collapsed; but I kind of think it will get | |
1237 * more complicated before I am finished, so... | |
1238 */ | |
1239 if (signerinfos != NULL && signerinfos[0] != NULL) | |
1240 return PR_TRUE; | |
1241 else | |
1242 return PR_FALSE; | |
1243 } | |
1244 | |
1245 | |
1246 /* | |
1247 * sec_pkcs7_verify_signature | |
1248 * | |
1249 * Look at a PKCS7 contentInfo and check if the signature is good. | |
1250 * The digest was either calculated earlier (and is stored in the | |
1251 * contentInfo itself) or is passed in via "detached_digest". | |
1252 * | |
1253 * The verification checks that the signing cert is valid and trusted | |
1254 * for the purpose specified by "certusage" at | |
1255 * - "*atTime" if "atTime" is not null, or | |
1256 * - the signing time if the signing time is available in "cinfo", or | |
1257 * - the current time (as returned by PR_Now). | |
1258 * | |
1259 * In addition, if "keepcerts" is true, add any new certificates found | |
1260 * into our local database. | |
1261 * | |
1262 * XXX Each place which returns PR_FALSE should be sure to have a good | |
1263 * error set for inspection by the caller. Alternatively, we could create | |
1264 * an enumeration of success and each type of failure and return that | |
1265 * instead of a boolean. For now, the default in a bad situation is to | |
1266 * set the error to SEC_ERROR_PKCS7_BAD_SIGNATURE. But this should be | |
1267 * reviewed; better (more specific) errors should be possible (to distinguish | |
1268 * a signature failure from a badly-formed pkcs7 signedData, for example). | |
1269 * Some of the errors should probably just be SEC_ERROR_BAD_SIGNATURE, | |
1270 * but that has a less helpful error string associated with it right now; | |
1271 * if/when that changes, review and change these as needed. | |
1272 * | |
1273 * XXX This is broken wrt signedAndEnvelopedData. In that case, the | |
1274 * message digest is doubly encrypted -- first encrypted with the signer | |
1275 * private key but then again encrypted with the bulk encryption key used | |
1276 * to encrypt the content. So before we can pass the digest to VerifyDigest, | |
1277 * we need to decrypt it with the bulk encryption key. Also, in this case, | |
1278 * there should be NO authenticatedAttributes (signerinfo->authAttr should | |
1279 * be NULL). | |
1280 */ | |
1281 static PRBool | |
1282 sec_pkcs7_verify_signature(SEC_PKCS7ContentInfo *cinfo, | |
1283 SECCertUsage certusage, | |
1284 const SECItem *detached_digest, | |
1285 HASH_HashType digest_type, | |
1286 PRBool keepcerts, | |
1287 const PRTime *atTime) | |
1288 { | |
1289 SECAlgorithmID **digestalgs, *bulkid; | |
1290 const SECItem *digest; | |
1291 SECItem **digests; | |
1292 SECItem **rawcerts; | |
1293 CERTSignedCrl **crls; | |
1294 SEC_PKCS7SignerInfo **signerinfos, *signerinfo; | |
1295 CERTCertificate *cert, **certs; | |
1296 PRBool goodsig; | |
1297 CERTCertDBHandle *certdb, *defaultdb; | |
1298 SECOidTag encTag,digestTag; | |
1299 HASH_HashType found_type; | |
1300 int i, certcount; | |
1301 SECKEYPublicKey *publickey; | |
1302 SECItem *content_type; | |
1303 PK11SymKey *sigkey; | |
1304 SECItem *encoded_stime; | |
1305 PRTime stime; | |
1306 PRTime verificationTime; | |
1307 SECStatus rv; | |
1308 | |
1309 /* | |
1310 * Everything needed in order to "goto done" safely. | |
1311 */ | |
1312 goodsig = PR_FALSE; | |
1313 certcount = 0; | |
1314 cert = NULL; | |
1315 certs = NULL; | |
1316 certdb = NULL; | |
1317 defaultdb = CERT_GetDefaultCertDB(); | |
1318 publickey = NULL; | |
1319 | |
1320 if (! SEC_PKCS7ContentIsSigned(cinfo)) { | |
1321 PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE); | |
1322 goto done; | |
1323 } | |
1324 | |
1325 PORT_Assert (cinfo->contentTypeTag != NULL); | |
1326 | |
1327 switch (cinfo->contentTypeTag->offset) { | |
1328 default: | |
1329 case SEC_OID_PKCS7_DATA: | |
1330 case SEC_OID_PKCS7_DIGESTED_DATA: | |
1331 case SEC_OID_PKCS7_ENVELOPED_DATA: | |
1332 case SEC_OID_PKCS7_ENCRYPTED_DATA: | |
1333 /* Could only get here if SEC_PKCS7ContentIsSigned is broken. */ | |
1334 PORT_Assert (0); | |
1335 case SEC_OID_PKCS7_SIGNED_DATA: | |
1336 { | |
1337 SEC_PKCS7SignedData *sdp; | |
1338 | |
1339 sdp = cinfo->content.signedData; | |
1340 digestalgs = sdp->digestAlgorithms; | |
1341 digests = sdp->digests; | |
1342 rawcerts = sdp->rawCerts; | |
1343 crls = sdp->crls; | |
1344 signerinfos = sdp->signerInfos; | |
1345 content_type = &(sdp->contentInfo.contentType); | |
1346 sigkey = NULL; | |
1347 bulkid = NULL; | |
1348 } | |
1349 break; | |
1350 case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA: | |
1351 { | |
1352 SEC_PKCS7SignedAndEnvelopedData *saedp; | |
1353 | |
1354 saedp = cinfo->content.signedAndEnvelopedData; | |
1355 digestalgs = saedp->digestAlgorithms; | |
1356 digests = saedp->digests; | |
1357 rawcerts = saedp->rawCerts; | |
1358 crls = saedp->crls; | |
1359 signerinfos = saedp->signerInfos; | |
1360 content_type = &(saedp->encContentInfo.contentType); | |
1361 sigkey = saedp->sigKey; | |
1362 bulkid = &(saedp->encContentInfo.contentEncAlg); | |
1363 } | |
1364 break; | |
1365 } | |
1366 | |
1367 if ((signerinfos == NULL) || (signerinfos[0] == NULL)) { | |
1368 PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE); | |
1369 goto done; | |
1370 } | |
1371 | |
1372 /* | |
1373 * XXX Need to handle multiple signatures; checking them is easy, | |
1374 * but what should be the semantics here (like, return value)? | |
1375 */ | |
1376 if (signerinfos[1] != NULL) { | |
1377 PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE); | |
1378 goto done; | |
1379 } | |
1380 | |
1381 signerinfo = signerinfos[0]; | |
1382 | |
1383 /* | |
1384 * XXX I would like to just pass the issuerAndSN, along with the rawcerts | |
1385 * and crls, to some function that did all of this certificate stuff | |
1386 * (open/close the database if necessary, verifying the certs, etc.) | |
1387 * and gave me back a cert pointer if all was good. | |
1388 */ | |
1389 certdb = defaultdb; | |
1390 if (certdb == NULL) { | |
1391 goto done; | |
1392 } | |
1393 | |
1394 certcount = 0; | |
1395 if (rawcerts != NULL) { | |
1396 for (; rawcerts[certcount] != NULL; certcount++) { | |
1397 /* just counting */ | |
1398 } | |
1399 } | |
1400 | |
1401 /* | |
1402 * Note that the result of this is that each cert in "certs" | |
1403 * needs to be destroyed. | |
1404 */ | |
1405 rv = CERT_ImportCerts(certdb, certusage, certcount, rawcerts, &certs, | |
1406 keepcerts, PR_FALSE, NULL); | |
1407 if ( rv != SECSuccess ) { | |
1408 goto done; | |
1409 } | |
1410 | |
1411 /* | |
1412 * This cert will also need to be freed, but since we save it | |
1413 * in signerinfo for later, we do not want to destroy it when | |
1414 * we leave this function -- we let the clean-up of the entire | |
1415 * cinfo structure later do the destroy of this cert. | |
1416 */ | |
1417 cert = CERT_FindCertByIssuerAndSN(certdb, signerinfo->issuerAndSN); | |
1418 if (cert == NULL) { | |
1419 goto done; | |
1420 } | |
1421 | |
1422 signerinfo->cert = cert; | |
1423 | |
1424 /* | |
1425 * Get and convert the signing time; if available, it will be used | |
1426 * both on the cert verification and for importing the sender | |
1427 * email profile. | |
1428 */ | |
1429 encoded_stime = SEC_PKCS7GetSigningTime (cinfo); | |
1430 if (encoded_stime != NULL) { | |
1431 if (DER_DecodeTimeChoice (&stime, encoded_stime) != SECSuccess) | |
1432 encoded_stime = NULL; /* conversion failed, so pretend none */ | |
1433 } | |
1434 | |
1435 /* | |
1436 * XXX This uses the signing time, if available. Additionally, we | |
1437 * might want to, if there is no signing time, get the message time | |
1438 * from the mail header itself, and use that. That would require | |
1439 * a change to our interface though, and for S/MIME callers to pass | |
1440 * in a time (and for non-S/MIME callers to pass in nothing, or | |
1441 * maybe make them pass in the current time, always?). | |
1442 */ | |
1443 if (atTime) { | |
1444 verificationTime = *atTime; | |
1445 } else if (encoded_stime != NULL) { | |
1446 verificationTime = stime; | |
1447 } else { | |
1448 verificationTime = PR_Now(); | |
1449 } | |
1450 if (CERT_VerifyCert (certdb, cert, PR_TRUE, certusage, verificationTime, | |
1451 cinfo->pwfn_arg, NULL) != SECSuccess) | |
1452 { | |
1453 /* | |
1454 * XXX Give the user an option to check the signature anyway? | |
1455 * If we want to do this, need to give a way to leave and display | |
1456 * some dialog and get the answer and come back through (or do | |
1457 * the rest of what we do below elsewhere, maybe by putting it | |
1458 * in a function that we call below and could call from a dialog | |
1459 * finish handler). | |
1460 */ | |
1461 goto savecert; | |
1462 } | |
1463 | |
1464 publickey = CERT_ExtractPublicKey (cert); | |
1465 if (publickey == NULL) | |
1466 goto done; | |
1467 | |
1468 /* | |
1469 * XXX No! If digests is empty, see if we can create it now by | |
1470 * digesting the contents. This is necessary if we want to allow | |
1471 * somebody to do a simple decode (without filtering, etc.) and | |
1472 * then later call us here to do the verification. | |
1473 * OR, we can just specify that the interface to this routine | |
1474 * *requires* that the digest(s) be done before calling and either | |
1475 * stashed in the struct itself or passed in explicitly (as would | |
1476 * be done for detached contents). | |
1477 */ | |
1478 if ((digests == NULL || digests[0] == NULL) | |
1479 && (detached_digest == NULL || detached_digest->data == NULL)) | |
1480 goto done; | |
1481 | |
1482 /* | |
1483 * Find and confirm digest algorithm. | |
1484 */ | |
1485 digestTag = SECOID_FindOIDTag(&(signerinfo->digestAlg.algorithm)); | |
1486 | |
1487 /* make sure we understand the digest type first */ | |
1488 found_type = HASH_GetHashTypeByOidTag(digestTag); | |
1489 if ((digestTag == SEC_OID_UNKNOWN) || (found_type == HASH_AlgNULL)) { | |
1490 PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE); | |
1491 goto done; | |
1492 } | |
1493 | |
1494 if (detached_digest != NULL) { | |
1495 unsigned int hashLen = HASH_ResultLen(found_type); | |
1496 | |
1497 if (digest_type != found_type || | |
1498 detached_digest->len != hashLen) { | |
1499 PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE); | |
1500 goto done; | |
1501 } | |
1502 digest = detached_digest; | |
1503 } else { | |
1504 PORT_Assert (digestalgs != NULL && digestalgs[0] != NULL); | |
1505 if (digestalgs == NULL || digestalgs[0] == NULL) { | |
1506 PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE); | |
1507 goto done; | |
1508 } | |
1509 | |
1510 /* | |
1511 * pick digest matching signerinfo->digestAlg from digests | |
1512 */ | |
1513 for (i = 0; digestalgs[i] != NULL; i++) { | |
1514 if (SECOID_FindOIDTag(&(digestalgs[i]->algorithm)) == digestTag) | |
1515 break; | |
1516 } | |
1517 if (digestalgs[i] == NULL) { | |
1518 PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE); | |
1519 goto done; | |
1520 } | |
1521 | |
1522 digest = digests[i]; | |
1523 } | |
1524 | |
1525 encTag = SECOID_FindOIDTag(&(signerinfo->digestEncAlg.algorithm)); | |
1526 if (encTag == SEC_OID_UNKNOWN) { | |
1527 PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE); | |
1528 goto done; | |
1529 } | |
1530 | |
1531 if (signerinfo->authAttr != NULL) { | |
1532 SEC_PKCS7Attribute *attr; | |
1533 SECItem *value; | |
1534 SECItem encoded_attrs; | |
1535 | |
1536 /* | |
1537 * We have a sigkey only for signedAndEnvelopedData, which is | |
1538 * not supposed to have any authenticated attributes. | |
1539 */ | |
1540 if (sigkey != NULL) { | |
1541 PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE); | |
1542 goto done; | |
1543 } | |
1544 | |
1545 /* | |
1546 * PKCS #7 says that if there are any authenticated attributes, | |
1547 * then there must be one for content type which matches the | |
1548 * content type of the content being signed, and there must | |
1549 * be one for message digest which matches our message digest. | |
1550 * So check these things first. | |
1551 * XXX Might be nice to have a compare-attribute-value function | |
1552 * which could collapse the following nicely. | |
1553 */ | |
1554 attr = sec_PKCS7FindAttribute (signerinfo->authAttr, | |
1555 SEC_OID_PKCS9_CONTENT_TYPE, PR_TRUE); | |
1556 value = sec_PKCS7AttributeValue (attr); | |
1557 if (value == NULL || value->len != content_type->len) { | |
1558 PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE); | |
1559 goto done; | |
1560 } | |
1561 if (PORT_Memcmp (value->data, content_type->data, value->len) != 0) { | |
1562 PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE); | |
1563 goto done; | |
1564 } | |
1565 | |
1566 attr = sec_PKCS7FindAttribute (signerinfo->authAttr, | |
1567 SEC_OID_PKCS9_MESSAGE_DIGEST, PR_TRUE); | |
1568 value = sec_PKCS7AttributeValue (attr); | |
1569 if (value == NULL || value->len != digest->len) { | |
1570 PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE); | |
1571 goto done; | |
1572 } | |
1573 if (PORT_Memcmp (value->data, digest->data, value->len) != 0) { | |
1574 PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE); | |
1575 goto done; | |
1576 } | |
1577 | |
1578 /* | |
1579 * Okay, we met the constraints of the basic attributes. | |
1580 * Now check the signature, which is based on a digest of | |
1581 * the DER-encoded authenticated attributes. So, first we | |
1582 * encode and then we digest/verify. | |
1583 */ | |
1584 encoded_attrs.data = NULL; | |
1585 encoded_attrs.len = 0; | |
1586 if (sec_PKCS7EncodeAttributes (NULL, &encoded_attrs, | |
1587 &(signerinfo->authAttr)) == NULL) | |
1588 goto done; | |
1589 | |
1590 if (encoded_attrs.data == NULL || encoded_attrs.len == 0) { | |
1591 PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE); | |
1592 goto done; | |
1593 } | |
1594 | |
1595 goodsig = (PRBool)(VFY_VerifyDataDirect(encoded_attrs.data, | |
1596 encoded_attrs.len, | |
1597 publickey, &(signerinfo->encDigest), | |
1598 encTag, digestTag, NULL, | |
1599 cinfo->pwfn_arg) == SECSuccess); | |
1600 PORT_Free (encoded_attrs.data); | |
1601 } else { | |
1602 SECItem *sig; | |
1603 SECItem holder; | |
1604 SECStatus rv; | |
1605 | |
1606 /* | |
1607 * No authenticated attributes. | |
1608 * The signature is based on the plain message digest. | |
1609 */ | |
1610 | |
1611 sig = &(signerinfo->encDigest); | |
1612 if (sig->len == 0) { /* bad signature */ | |
1613 PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE); | |
1614 goto done; | |
1615 } | |
1616 | |
1617 if (sigkey != NULL) { | |
1618 sec_PKCS7CipherObject *decryptobj; | |
1619 unsigned int buflen; | |
1620 | |
1621 /* | |
1622 * For signedAndEnvelopedData, we first must decrypt the encrypted | |
1623 * digest with the bulk encryption key. The result is the normal | |
1624 * encrypted digest (aka the signature). | |
1625 */ | |
1626 decryptobj = sec_PKCS7CreateDecryptObject (sigkey, bulkid); | |
1627 if (decryptobj == NULL) | |
1628 goto done; | |
1629 | |
1630 buflen = sec_PKCS7DecryptLength (decryptobj, sig->len, PR_TRUE); | |
1631 PORT_Assert (buflen); | |
1632 if (buflen == 0) { /* something is wrong */ | |
1633 sec_PKCS7DestroyDecryptObject (decryptobj); | |
1634 goto done; | |
1635 } | |
1636 | |
1637 holder.data = (unsigned char*)PORT_Alloc (buflen); | |
1638 if (holder.data == NULL) { | |
1639 sec_PKCS7DestroyDecryptObject (decryptobj); | |
1640 goto done; | |
1641 } | |
1642 | |
1643 rv = sec_PKCS7Decrypt (decryptobj, holder.data, &holder.len, buflen, | |
1644 sig->data, sig->len, PR_TRUE); | |
1645 sec_PKCS7DestroyDecryptObject (decryptobj); | |
1646 if (rv != SECSuccess) { | |
1647 goto done; | |
1648 } | |
1649 | |
1650 sig = &holder; | |
1651 } | |
1652 | |
1653 goodsig = (PRBool)(VFY_VerifyDigestDirect(digest, publickey, sig, | |
1654 encTag, digestTag, cinfo->pwfn_arg) | |
1655 == SECSuccess); | |
1656 | |
1657 if (sigkey != NULL) { | |
1658 PORT_Assert (sig == &holder); | |
1659 PORT_ZFree (holder.data, holder.len); | |
1660 } | |
1661 } | |
1662 | |
1663 if (! goodsig) { | |
1664 /* | |
1665 * XXX Change the generic error into our specific one, because | |
1666 * in that case we get a better explanation out of the Security | |
1667 * Advisor. This is really a bug in our error strings (the | |
1668 * "generic" error has a lousy/wrong message associated with it | |
1669 * which assumes the signature verification was done for the | |
1670 * purposes of checking the issuer signature on a certificate) | |
1671 * but this is at least an easy workaround and/or in the | |
1672 * Security Advisor, which specifically checks for the error | |
1673 * SEC_ERROR_PKCS7_BAD_SIGNATURE and gives more explanation | |
1674 * in that case but does not similarly check for | |
1675 * SEC_ERROR_BAD_SIGNATURE. It probably should, but then would | |
1676 * probably say the wrong thing in the case that it *was* the | |
1677 * certificate signature check that failed during the cert | |
1678 * verification done above. Our error handling is really a mess. | |
1679 */ | |
1680 if (PORT_GetError() == SEC_ERROR_BAD_SIGNATURE) | |
1681 PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE); | |
1682 } | |
1683 | |
1684 savecert: | |
1685 /* | |
1686 * Only save the smime profile if we are checking an email message and | |
1687 * the cert has an email address in it. | |
1688 */ | |
1689 if ( cert->emailAddr && cert->emailAddr[0] && | |
1690 ( ( certusage == certUsageEmailSigner ) || | |
1691 ( certusage == certUsageEmailRecipient ) ) ) { | |
1692 SECItem *profile = NULL; | |
1693 int save_error; | |
1694 | |
1695 /* | |
1696 * Remember the current error set because we do not care about | |
1697 * anything set by the functions we are about to call. | |
1698 */ | |
1699 save_error = PORT_GetError(); | |
1700 | |
1701 if (goodsig && (signerinfo->authAttr != NULL)) { | |
1702 /* | |
1703 * If the signature is good, then we can save the S/MIME profile, | |
1704 * if we have one. | |
1705 */ | |
1706 SEC_PKCS7Attribute *attr; | |
1707 | |
1708 attr = sec_PKCS7FindAttribute (signerinfo->authAttr, | |
1709 SEC_OID_PKCS9_SMIME_CAPABILITIES, | |
1710 PR_TRUE); | |
1711 profile = sec_PKCS7AttributeValue (attr); | |
1712 } | |
1713 | |
1714 rv = CERT_SaveSMimeProfile (cert, profile, encoded_stime); | |
1715 | |
1716 /* | |
1717 * Restore the saved error in case the calls above set a new | |
1718 * one that we do not actually care about. | |
1719 */ | |
1720 PORT_SetError (save_error); | |
1721 | |
1722 /* | |
1723 * XXX Failure is not indicated anywhere -- the signature | |
1724 * verification itself is unaffected by whether or not the | |
1725 * profile was successfully saved. | |
1726 */ | |
1727 } | |
1728 | |
1729 | |
1730 done: | |
1731 | |
1732 /* | |
1733 * See comment above about why we do not want to destroy cert | |
1734 * itself here. | |
1735 */ | |
1736 | |
1737 if (certs != NULL) | |
1738 CERT_DestroyCertArray (certs, certcount); | |
1739 | |
1740 if (publickey != NULL) | |
1741 SECKEY_DestroyPublicKey (publickey); | |
1742 | |
1743 return goodsig; | |
1744 } | |
1745 | |
1746 /* | |
1747 * SEC_PKCS7VerifySignature | |
1748 * Look at a PKCS7 contentInfo and check if the signature is good. | |
1749 * The verification checks that the signing cert is valid and trusted | |
1750 * for the purpose specified by "certusage". | |
1751 * | |
1752 * In addition, if "keepcerts" is true, add any new certificates found | |
1753 * into our local database. | |
1754 */ | |
1755 PRBool | |
1756 SEC_PKCS7VerifySignature(SEC_PKCS7ContentInfo *cinfo, | |
1757 SECCertUsage certusage, | |
1758 PRBool keepcerts) | |
1759 { | |
1760 return sec_pkcs7_verify_signature (cinfo, certusage, | |
1761 NULL, HASH_AlgNULL, keepcerts, NULL); | |
1762 } | |
1763 | |
1764 /* | |
1765 * SEC_PKCS7VerifyDetachedSignature | |
1766 * Look at a PKCS7 contentInfo and check if the signature matches | |
1767 * a passed-in digest (calculated, supposedly, from detached contents). | |
1768 * The verification checks that the signing cert is valid and trusted | |
1769 * for the purpose specified by "certusage". | |
1770 * | |
1771 * In addition, if "keepcerts" is true, add any new certificates found | |
1772 * into our local database. | |
1773 */ | |
1774 PRBool | |
1775 SEC_PKCS7VerifyDetachedSignature(SEC_PKCS7ContentInfo *cinfo, | |
1776 SECCertUsage certusage, | |
1777 const SECItem *detached_digest, | |
1778 HASH_HashType digest_type, | |
1779 PRBool keepcerts) | |
1780 { | |
1781 return sec_pkcs7_verify_signature (cinfo, certusage, | |
1782 detached_digest, digest_type, | |
1783 keepcerts, NULL); | |
1784 } | |
1785 | |
1786 /* | |
1787 * SEC_PKCS7VerifyDetachedSignatureAtTime | |
1788 * Look at a PKCS7 contentInfo and check if the signature matches | |
1789 * a passed-in digest (calculated, supposedly, from detached contents). | |
1790 * The verification checks that the signing cert is valid and trusted | |
1791 * for the purpose specified by "certusage" at time "atTime". | |
1792 * | |
1793 * In addition, if "keepcerts" is true, add any new certificates found | |
1794 * into our local database. | |
1795 */ | |
1796 PRBool | |
1797 SEC_PKCS7VerifyDetachedSignatureAtTime(SEC_PKCS7ContentInfo *cinfo, | |
1798 SECCertUsage certusage, | |
1799 const SECItem *detached_digest, | |
1800 HASH_HashType digest_type, | |
1801 PRBool keepcerts, | |
1802 PRTime atTime) | |
1803 { | |
1804 return sec_pkcs7_verify_signature (cinfo, certusage, | |
1805 detached_digest, digest_type, | |
1806 keepcerts, &atTime); | |
1807 } | |
1808 | |
1809 /* | |
1810 * Return the asked-for portion of the name of the signer of a PKCS7 | |
1811 * signed object. | |
1812 * | |
1813 * Returns a pointer to allocated memory, which must be freed. | |
1814 * A NULL return value is an error. | |
1815 */ | |
1816 | |
1817 #define sec_common_name 1 | |
1818 #define sec_email_address 2 | |
1819 | |
1820 static char * | |
1821 sec_pkcs7_get_signer_cert_info(SEC_PKCS7ContentInfo *cinfo, int selector) | |
1822 { | |
1823 SECOidTag kind; | |
1824 SEC_PKCS7SignerInfo **signerinfos; | |
1825 CERTCertificate *signercert; | |
1826 char *container; | |
1827 | |
1828 kind = SEC_PKCS7ContentType (cinfo); | |
1829 switch (kind) { | |
1830 default: | |
1831 case SEC_OID_PKCS7_DATA: | |
1832 case SEC_OID_PKCS7_DIGESTED_DATA: | |
1833 case SEC_OID_PKCS7_ENVELOPED_DATA: | |
1834 case SEC_OID_PKCS7_ENCRYPTED_DATA: | |
1835 PORT_Assert (0); | |
1836 return NULL; | |
1837 case SEC_OID_PKCS7_SIGNED_DATA: | |
1838 { | |
1839 SEC_PKCS7SignedData *sdp; | |
1840 | |
1841 sdp = cinfo->content.signedData; | |
1842 signerinfos = sdp->signerInfos; | |
1843 } | |
1844 break; | |
1845 case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA: | |
1846 { | |
1847 SEC_PKCS7SignedAndEnvelopedData *saedp; | |
1848 | |
1849 saedp = cinfo->content.signedAndEnvelopedData; | |
1850 signerinfos = saedp->signerInfos; | |
1851 } | |
1852 break; | |
1853 } | |
1854 | |
1855 if (signerinfos == NULL || signerinfos[0] == NULL) | |
1856 return NULL; | |
1857 | |
1858 signercert = signerinfos[0]->cert; | |
1859 | |
1860 /* | |
1861 * No cert there; see if we can find one by calling verify ourselves. | |
1862 */ | |
1863 if (signercert == NULL) { | |
1864 /* | |
1865 * The cert usage does not matter in this case, because we do not | |
1866 * actually care about the verification itself, but we have to pick | |
1867 * some valid usage to pass in. | |
1868 */ | |
1869 (void) sec_pkcs7_verify_signature (cinfo, certUsageEmailSigner, | |
1870 NULL, HASH_AlgNULL, PR_FALSE, NULL); | |
1871 signercert = signerinfos[0]->cert; | |
1872 if (signercert == NULL) | |
1873 return NULL; | |
1874 } | |
1875 | |
1876 switch (selector) { | |
1877 case sec_common_name: | |
1878 container = CERT_GetCommonName (&signercert->subject); | |
1879 break; | |
1880 case sec_email_address: | |
1881 if(signercert->emailAddr && signercert->emailAddr[0]) { | |
1882 container = PORT_Strdup(signercert->emailAddr); | |
1883 } else { | |
1884 container = NULL; | |
1885 } | |
1886 break; | |
1887 default: | |
1888 PORT_Assert (0); | |
1889 container = NULL; | |
1890 break; | |
1891 } | |
1892 | |
1893 return container; | |
1894 } | |
1895 | |
1896 char * | |
1897 SEC_PKCS7GetSignerCommonName(SEC_PKCS7ContentInfo *cinfo) | |
1898 { | |
1899 return sec_pkcs7_get_signer_cert_info(cinfo, sec_common_name); | |
1900 } | |
1901 | |
1902 char * | |
1903 SEC_PKCS7GetSignerEmailAddress(SEC_PKCS7ContentInfo *cinfo) | |
1904 { | |
1905 return sec_pkcs7_get_signer_cert_info(cinfo, sec_email_address); | |
1906 } | |
1907 | |
1908 | |
1909 /* | |
1910 * Return the signing time, in UTCTime format, of a PKCS7 contentInfo. | |
1911 */ | |
1912 SECItem * | |
1913 SEC_PKCS7GetSigningTime(SEC_PKCS7ContentInfo *cinfo) | |
1914 { | |
1915 SEC_PKCS7SignerInfo **signerinfos; | |
1916 SEC_PKCS7Attribute *attr; | |
1917 | |
1918 if (SEC_PKCS7ContentType (cinfo) != SEC_OID_PKCS7_SIGNED_DATA) | |
1919 return NULL; | |
1920 | |
1921 signerinfos = cinfo->content.signedData->signerInfos; | |
1922 | |
1923 /* | |
1924 * No signature, or more than one, means no deal. | |
1925 */ | |
1926 if (signerinfos == NULL || signerinfos[0] == NULL || signerinfos[1] != NULL) | |
1927 return NULL; | |
1928 | |
1929 attr = sec_PKCS7FindAttribute (signerinfos[0]->authAttr, | |
1930 SEC_OID_PKCS9_SIGNING_TIME, PR_TRUE); | |
1931 return sec_PKCS7AttributeValue (attr); | |
1932 } |