Chromium Code Reviews

Side by Side Diff: mozilla/security/nss/lib/pkcs7/secmime.c

Issue 14249009: Change the NSS and NSPR source tree to the new directory structure to be (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/deps/third_party/nss/
Patch Set: Created 7 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff | | Annotate | Revision Log
« no previous file with comments | « mozilla/security/nss/lib/pkcs7/secmime.h ('k') | mozilla/security/nss/lib/pkcs7/secpkcs7.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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 * Stuff specific to S/MIME policy and interoperability.
7 * Depends on PKCS7, but there should be no dependency the other way around.
8 *
9 * $Id: secmime.c,v 1.6 2012/04/25 14:50:06 gerv%gerv.net Exp $
10 */
11
12 #include "secmime.h"
13 #include "secoid.h"
14 #include "pk11func.h"
15 #include "ciferfam.h" /* for CIPHER_FAMILY symbols */
16 #include "secasn1.h"
17 #include "secitem.h"
18 #include "cert.h"
19 #include "key.h"
20 #include "secerr.h"
21
22 typedef struct smime_cipher_map_struct {
23 unsigned long cipher;
24 SECOidTag algtag;
25 SECItem *parms;
26 } smime_cipher_map;
27
28 /*
29 * These are macros because I think some subsequent parameters,
30 * like those for RC5, will want to use them, too, separately.
31 */
32 #define SMIME_DER_INTVAL_16 SEC_ASN1_INTEGER, 0x01, 0x10
33 #define SMIME_DER_INTVAL_40 SEC_ASN1_INTEGER, 0x01, 0x28
34 #define SMIME_DER_INTVAL_64 SEC_ASN1_INTEGER, 0x01, 0x40
35 #define SMIME_DER_INTVAL_128 SEC_ASN1_INTEGER, 0x02, 0x00, 0x80
36
37 #ifdef SMIME_DOES_RC5 /* will be needed; quiet unused warning for now */
38 static unsigned char smime_int16[] = { SMIME_DER_INTVAL_16 };
39 #endif
40 static unsigned char smime_int40[] = { SMIME_DER_INTVAL_40 };
41 static unsigned char smime_int64[] = { SMIME_DER_INTVAL_64 };
42 static unsigned char smime_int128[] = { SMIME_DER_INTVAL_128 };
43
44 static SECItem smime_rc2p40 = { siBuffer, smime_int40, sizeof(smime_int40) };
45 static SECItem smime_rc2p64 = { siBuffer, smime_int64, sizeof(smime_int64) };
46 static SECItem smime_rc2p128 = { siBuffer, smime_int128, sizeof(smime_int128) };
47
48 static smime_cipher_map smime_cipher_maps[] = {
49 { SMIME_RC2_CBC_40, SEC_OID_RC2_CBC, &smime_rc2p40 },
50 { SMIME_RC2_CBC_64, SEC_OID_RC2_CBC, &smime_rc2p64 },
51 { SMIME_RC2_CBC_128, SEC_OID_RC2_CBC, &smime_rc2p128 },
52 #ifdef SMIME_DOES_RC5
53 { SMIME_RC5PAD_64_16_40, SEC_OID_RC5_CBC_PAD, &smime_rc5p40 },
54 { SMIME_RC5PAD_64_16_64, SEC_OID_RC5_CBC_PAD, &smime_rc5p64 },
55 { SMIME_RC5PAD_64_16_128, SEC_OID_RC5_CBC_PAD, &smime_rc5p128 },
56 #endif
57 { SMIME_DES_CBC_56, SEC_OID_DES_CBC, NULL },
58 { SMIME_DES_EDE3_168, SEC_OID_DES_EDE3_CBC, NULL }
59 };
60
61 /*
62 * Note, the following value really just needs to be an upper bound
63 * on the ciphers.
64 */
65 static const int smime_symmetric_count = sizeof(smime_cipher_maps)
66 / sizeof(smime_cipher_map);
67
68 static unsigned long *smime_prefs, *smime_newprefs;
69 static int smime_current_pref_index = 0;
70 static PRBool smime_prefs_complete = PR_FALSE;
71 static PRBool smime_prefs_changed = PR_TRUE;
72
73 static unsigned long smime_policy_bits = 0;
74
75
76 static int
77 smime_mapi_by_cipher (unsigned long cipher)
78 {
79 int i;
80
81 for (i = 0; i < smime_symmetric_count; i++) {
82 if (smime_cipher_maps[i].cipher == cipher)
83 break;
84 }
85
86 if (i == smime_symmetric_count)
87 return -1;
88
89 return i;
90 }
91
92
93 /*
94 * this function locally records the user's preference
95 */
96 SECStatus
97 SECMIME_EnableCipher(long which, int on)
98 {
99 unsigned long mask;
100
101 if (smime_newprefs == NULL || smime_prefs_complete) {
102 /*
103 * This is either the very first time, or we are starting over.
104 */
105 smime_newprefs = (unsigned long*)PORT_ZAlloc (smime_symmetric_count
106 * sizeof(*smime_newprefs));
107 if (smime_newprefs == NULL)
108 return SECFailure;
109 smime_current_pref_index = 0;
110 smime_prefs_complete = PR_FALSE;
111 }
112
113 mask = which & CIPHER_FAMILYID_MASK;
114 if (mask == CIPHER_FAMILYID_MASK) {
115 /*
116 * This call signifies that all preferences have been set.
117 * Move "newprefs" over, after checking first whether or
118 * not the new ones are different from the old ones.
119 */
120 if (smime_prefs != NULL) {
121 if (PORT_Memcmp (smime_prefs, smime_newprefs,
122 smime_symmetric_count * sizeof(*smime_prefs)) == 0)
123 smime_prefs_changed = PR_FALSE;
124 else
125 smime_prefs_changed = PR_TRUE;
126 PORT_Free (smime_prefs);
127 }
128
129 smime_prefs = smime_newprefs;
130 smime_prefs_complete = PR_TRUE;
131 return SECSuccess;
132 }
133
134 PORT_Assert (mask == CIPHER_FAMILYID_SMIME);
135 if (mask != CIPHER_FAMILYID_SMIME) {
136 /* XXX set an error! */
137 return SECFailure;
138 }
139
140 if (on) {
141 PORT_Assert (smime_current_pref_index < smime_symmetric_count);
142 if (smime_current_pref_index >= smime_symmetric_count) {
143 /* XXX set an error! */
144 return SECFailure;
145 }
146
147 smime_newprefs[smime_current_pref_index++] = which;
148 }
149
150 return SECSuccess;
151 }
152
153
154 /*
155 * this function locally records the export policy
156 */
157 SECStatus
158 SECMIME_SetPolicy(long which, int on)
159 {
160 unsigned long mask;
161
162 PORT_Assert ((which & CIPHER_FAMILYID_MASK) == CIPHER_FAMILYID_SMIME);
163 if ((which & CIPHER_FAMILYID_MASK) != CIPHER_FAMILYID_SMIME) {
164 /* XXX set an error! */
165 return SECFailure;
166 }
167
168 which &= ~CIPHER_FAMILYID_MASK;
169
170 PORT_Assert (which < 32); /* bits in the long */
171 if (which >= 32) {
172 /* XXX set an error! */
173 return SECFailure;
174 }
175
176 mask = 1UL << which;
177
178 if (on) {
179 smime_policy_bits |= mask;
180 } else {
181 smime_policy_bits &= ~mask;
182 }
183
184 return SECSuccess;
185 }
186
187
188 /*
189 * Based on the given algorithm (including its parameters, in some cases!)
190 * and the given key (may or may not be inspected, depending on the
191 * algorithm), find the appropriate policy algorithm specification
192 * and return it. If no match can be made, -1 is returned.
193 */
194 static long
195 smime_policy_algorithm (SECAlgorithmID *algid, PK11SymKey *key)
196 {
197 SECOidTag algtag;
198
199 algtag = SECOID_GetAlgorithmTag (algid);
200 switch (algtag) {
201 case SEC_OID_RC2_CBC:
202 {
203 unsigned int keylen_bits;
204
205 keylen_bits = PK11_GetKeyStrength (key, algid);
206 switch (keylen_bits) {
207 case 40:
208 return SMIME_RC2_CBC_40;
209 case 64:
210 return SMIME_RC2_CBC_64;
211 case 128:
212 return SMIME_RC2_CBC_128;
213 default:
214 break;
215 }
216 }
217 break;
218 case SEC_OID_DES_CBC:
219 return SMIME_DES_CBC_56;
220 case SEC_OID_DES_EDE3_CBC:
221 return SMIME_DES_EDE3_168;
222 #ifdef SMIME_DOES_RC5
223 case SEC_OID_RC5_CBC_PAD:
224 PORT_Assert (0); /* XXX need to pull out parameters and match */
225 break;
226 #endif
227 default:
228 break;
229 }
230
231 return -1;
232 }
233
234
235 static PRBool
236 smime_cipher_allowed (unsigned long which)
237 {
238 unsigned long mask;
239
240 which &= ~CIPHER_FAMILYID_MASK;
241 PORT_Assert (which < 32); /* bits per long (min) */
242 if (which >= 32)
243 return PR_FALSE;
244
245 mask = 1UL << which;
246 if ((mask & smime_policy_bits) == 0)
247 return PR_FALSE;
248
249 return PR_TRUE;
250 }
251
252
253 PRBool
254 SECMIME_DecryptionAllowed(SECAlgorithmID *algid, PK11SymKey *key)
255 {
256 long which;
257
258 which = smime_policy_algorithm (algid, key);
259 if (which < 0)
260 return PR_FALSE;
261
262 return smime_cipher_allowed ((unsigned long)which);
263 }
264
265
266 /*
267 * Does the current policy allow *any* S/MIME encryption (or decryption)?
268 *
269 * This tells whether or not *any* S/MIME encryption can be done,
270 * according to policy. Callers may use this to do nicer user interface
271 * (say, greying out a checkbox so a user does not even try to encrypt
272 * a message when they are not allowed to) or for any reason they want
273 * to check whether S/MIME encryption (or decryption, for that matter)
274 * may be done.
275 *
276 * It takes no arguments. The return value is a simple boolean:
277 * PR_TRUE means encryption (or decryption) is *possible*
278 * (but may still fail due to other reasons, like because we cannot
279 * find all the necessary certs, etc.; PR_TRUE is *not* a guarantee)
280 * PR_FALSE means encryption (or decryption) is not permitted
281 *
282 * There are no errors from this routine.
283 */
284 PRBool
285 SECMIME_EncryptionPossible (void)
286 {
287 if (smime_policy_bits != 0)
288 return PR_TRUE;
289
290 return PR_FALSE;
291 }
292
293
294 /*
295 * XXX Would like the "parameters" field to be a SECItem *, but the
296 * encoder is having trouble with optional pointers to an ANY. Maybe
297 * once that is fixed, can change this back...
298 */
299 typedef struct smime_capability_struct {
300 unsigned long cipher; /* local; not part of encoding */
301 SECOidTag capIDTag; /* local; not part of encoding */
302 SECItem capabilityID;
303 SECItem parameters;
304 } smime_capability;
305
306 static const SEC_ASN1Template smime_capability_template[] = {
307 { SEC_ASN1_SEQUENCE,
308 0, NULL, sizeof(smime_capability) },
309 { SEC_ASN1_OBJECT_ID,
310 offsetof(smime_capability,capabilityID), },
311 { SEC_ASN1_OPTIONAL | SEC_ASN1_ANY,
312 offsetof(smime_capability,parameters), },
313 { 0, }
314 };
315
316 static const SEC_ASN1Template smime_capabilities_template[] = {
317 { SEC_ASN1_SEQUENCE_OF, 0, smime_capability_template }
318 };
319
320
321
322 static void
323 smime_fill_capability (smime_capability *cap)
324 {
325 unsigned long cipher;
326 SECOidTag algtag;
327 int i;
328
329 algtag = SECOID_FindOIDTag (&(cap->capabilityID));
330
331 for (i = 0; i < smime_symmetric_count; i++) {
332 if (smime_cipher_maps[i].algtag != algtag)
333 continue;
334 /*
335 * XXX If SECITEM_CompareItem allowed NULLs as arguments (comparing
336 * 2 NULLs as equal and NULL and non-NULL as not equal), we could
337 * use that here instead of all of the following comparison code.
338 */
339 if (cap->parameters.data != NULL) {
340 if (smime_cipher_maps[i].parms == NULL)
341 continue;
342 if (cap->parameters.len != smime_cipher_maps[i].parms->len)
343 continue;
344 if (PORT_Memcmp (cap->parameters.data,
345 smime_cipher_maps[i].parms->data,
346 cap->parameters.len) == 0)
347 break;
348 } else if (smime_cipher_maps[i].parms == NULL) {
349 break;
350 }
351 }
352
353 if (i == smime_symmetric_count)
354 cipher = 0;
355 else
356 cipher = smime_cipher_maps[i].cipher;
357
358 cap->cipher = cipher;
359 cap->capIDTag = algtag;
360 }
361
362
363 static long
364 smime_choose_cipher (CERTCertificate *scert, CERTCertificate **rcerts)
365 {
366 PRArenaPool *poolp;
367 long chosen_cipher;
368 int *cipher_abilities;
369 int *cipher_votes;
370 int strong_mapi;
371 int rcount, mapi, max;
372
373 if (smime_policy_bits == 0) {
374 PORT_SetError (SEC_ERROR_BAD_EXPORT_ALGORITHM);
375 return -1;
376 }
377
378 chosen_cipher = SMIME_RC2_CBC_40; /* the default, LCD */
379
380 poolp = PORT_NewArena (1024); /* XXX what is right value? */
381 if (poolp == NULL)
382 goto done;
383
384 cipher_abilities = (int*)PORT_ArenaZAlloc (poolp,
385 smime_symmetric_count * sizeof(int));
386 if (cipher_abilities == NULL)
387 goto done;
388
389 cipher_votes = (int*)PORT_ArenaZAlloc (poolp,
390 smime_symmetric_count * sizeof(int));
391 if (cipher_votes == NULL)
392 goto done;
393
394 /*
395 * XXX Should have a #define somewhere which specifies default
396 * strong cipher. (Or better, a way to configure.)
397 */
398
399 /* Make triple-DES the strong cipher. */
400 strong_mapi = smime_mapi_by_cipher (SMIME_DES_EDE3_168);
401
402 PORT_Assert (strong_mapi >= 0);
403
404 for (rcount = 0; rcerts[rcount] != NULL; rcount++) {
405 SECItem *profile;
406 smime_capability **caps;
407 int capi, pref;
408 SECStatus dstat;
409
410 pref = smime_symmetric_count;
411 profile = CERT_FindSMimeProfile (rcerts[rcount]);
412 if (profile != NULL && profile->data != NULL && profile->len > 0) {
413 caps = NULL;
414 dstat = SEC_QuickDERDecodeItem (poolp, &caps,
415 smime_capabilities_template,
416 profile);
417 if (dstat == SECSuccess && caps != NULL) {
418 for (capi = 0; caps[capi] != NULL; capi++) {
419 smime_fill_capability (caps[capi]);
420 mapi = smime_mapi_by_cipher (caps[capi]->cipher);
421 if (mapi >= 0) {
422 cipher_abilities[mapi]++;
423 cipher_votes[mapi] += pref;
424 --pref;
425 }
426 }
427 }
428 } else {
429 SECKEYPublicKey *key;
430 unsigned int pklen_bits;
431
432 /*
433 * XXX This is probably only good for RSA keys. What I would
434 * really like is a function to just say; Is the public key in
435 * this cert an export-length key? Then I would not have to
436 * know things like the value 512, or the kind of key, or what
437 * a subjectPublicKeyInfo is, etc.
438 */
439 key = CERT_ExtractPublicKey (rcerts[rcount]);
440 if (key != NULL) {
441 pklen_bits = SECKEY_PublicKeyStrength (key) * 8;
442 SECKEY_DestroyPublicKey (key);
443
444 if (pklen_bits > 512) {
445 cipher_abilities[strong_mapi]++;
446 cipher_votes[strong_mapi] += pref;
447 }
448 }
449 }
450 if (profile != NULL)
451 SECITEM_FreeItem (profile, PR_TRUE);
452 }
453
454 max = 0;
455 for (mapi = 0; mapi < smime_symmetric_count; mapi++) {
456 if (cipher_abilities[mapi] != rcount)
457 continue;
458 if (! smime_cipher_allowed (smime_cipher_maps[mapi].cipher))
459 continue;
460 if (cipher_votes[mapi] > max) {
461 chosen_cipher = smime_cipher_maps[mapi].cipher;
462 max = cipher_votes[mapi];
463 } /* XXX else if a tie, let scert break it? */
464 }
465
466 done:
467 if (poolp != NULL)
468 PORT_FreeArena (poolp, PR_FALSE);
469
470 return chosen_cipher;
471 }
472
473
474 /*
475 * XXX This is a hack for now to satisfy our current interface.
476 * Eventually, with more parameters needing to be specified, just
477 * looking up the keysize is not going to be sufficient.
478 */
479 static int
480 smime_keysize_by_cipher (unsigned long which)
481 {
482 int keysize;
483
484 switch (which) {
485 case SMIME_RC2_CBC_40:
486 keysize = 40;
487 break;
488 case SMIME_RC2_CBC_64:
489 keysize = 64;
490 break;
491 case SMIME_RC2_CBC_128:
492 keysize = 128;
493 break;
494 #ifdef SMIME_DOES_RC5
495 case SMIME_RC5PAD_64_16_40:
496 case SMIME_RC5PAD_64_16_64:
497 case SMIME_RC5PAD_64_16_128:
498 /* XXX See comment above; keysize is not enough... */
499 PORT_Assert (0);
500 PORT_SetError (SEC_ERROR_INVALID_ALGORITHM);
501 keysize = -1;
502 break;
503 #endif
504 case SMIME_DES_CBC_56:
505 case SMIME_DES_EDE3_168:
506 /*
507 * These are special; since the key size is fixed, we actually
508 * want to *avoid* specifying a key size.
509 */
510 keysize = 0;
511 break;
512 default:
513 keysize = -1;
514 break;
515 }
516
517 return keysize;
518 }
519
520
521 /*
522 * Start an S/MIME encrypting context.
523 *
524 * "scert" is the cert for the sender. It will be checked for validity.
525 * "rcerts" are the certs for the recipients. They will also be checked.
526 *
527 * "certdb" is the cert database to use for verifying the certs.
528 * It can be NULL if a default database is available (like in the client).
529 *
530 * This function already does all of the stuff specific to S/MIME protocol
531 * and local policy; the return value just needs to be passed to
532 * SEC_PKCS7Encode() or to SEC_PKCS7EncoderStart() to create the encoded data,
533 * and finally to SEC_PKCS7DestroyContentInfo().
534 *
535 * An error results in a return value of NULL and an error set.
536 * (Retrieve specific errors via PORT_GetError()/XP_GetError().)
537 */
538 SEC_PKCS7ContentInfo *
539 SECMIME_CreateEncrypted(CERTCertificate *scert,
540 CERTCertificate **rcerts,
541 CERTCertDBHandle *certdb,
542 SECKEYGetPasswordKey pwfn,
543 void *pwfn_arg)
544 {
545 SEC_PKCS7ContentInfo *cinfo;
546 long cipher;
547 SECOidTag encalg;
548 int keysize;
549 int mapi, rci;
550
551 cipher = smime_choose_cipher (scert, rcerts);
552 if (cipher < 0)
553 return NULL;
554
555 mapi = smime_mapi_by_cipher (cipher);
556 if (mapi < 0)
557 return NULL;
558
559 /*
560 * XXX This is stretching it -- CreateEnvelopedData should probably
561 * take a cipher itself of some sort, because we cannot know what the
562 * future will bring in terms of parameters for each type of algorithm.
563 * For example, just an algorithm and keysize is *not* sufficient to
564 * fully specify the usage of RC5 (which also needs to know rounds and
565 * block size). Work this out into a better API!
566 */
567 encalg = smime_cipher_maps[mapi].algtag;
568 keysize = smime_keysize_by_cipher (cipher);
569 if (keysize < 0)
570 return NULL;
571
572 cinfo = SEC_PKCS7CreateEnvelopedData (scert, certUsageEmailRecipient,
573 certdb, encalg, keysize,
574 pwfn, pwfn_arg);
575 if (cinfo == NULL)
576 return NULL;
577
578 for (rci = 0; rcerts[rci] != NULL; rci++) {
579 if (rcerts[rci] == scert)
580 continue;
581 if (SEC_PKCS7AddRecipient (cinfo, rcerts[rci], certUsageEmailRecipient,
582 NULL) != SECSuccess) {
583 SEC_PKCS7DestroyContentInfo (cinfo);
584 return NULL;
585 }
586 }
587
588 return cinfo;
589 }
590
591
592 static smime_capability **smime_capabilities;
593 static SECItem *smime_encoded_caps;
594
595
596 static SECStatus
597 smime_init_caps (void)
598 {
599 smime_capability *cap;
600 smime_cipher_map *map;
601 SECOidData *oiddata;
602 SECStatus rv;
603 int i;
604
605 if (smime_encoded_caps != NULL && (! smime_prefs_changed))
606 return SECSuccess;
607
608 if (smime_encoded_caps != NULL) {
609 SECITEM_FreeItem (smime_encoded_caps, PR_TRUE);
610 smime_encoded_caps = NULL;
611 }
612
613 if (smime_capabilities == NULL) {
614 smime_capabilities = (smime_capability**)PORT_ZAlloc (
615 (smime_symmetric_count + 1)
616 * sizeof(smime_capability *));
617 if (smime_capabilities == NULL)
618 return SECFailure;
619 }
620
621 rv = SECFailure;
622
623 /*
624 The process of creating the encoded PKCS7 cipher capability list
625 involves two basic steps:
626
627 (a) Convert our internal representation of cipher preferences
628 (smime_prefs) into an array containing cipher OIDs and
629 parameter data (smime_capabilities). This step is
630 performed here.
631
632 (b) Encode, using ASN.1, the cipher information in
633 smime_capabilities, leaving the encoded result in
634 smime_encoded_caps.
635
636 (In the process of performing (a), Lisa put in some optimizations
637 which allow us to avoid needlessly re-populating elements in
638 smime_capabilities as we walk through smime_prefs.)
639 */
640 for (i = 0; i < smime_current_pref_index; i++) {
641 int mapi;
642
643 /* Get the next cipher preference in smime_prefs. */
644 mapi = smime_mapi_by_cipher (smime_prefs[i]);
645 if (mapi < 0)
646 break;
647
648 /* Find the corresponding entry in the cipher map. */
649 PORT_Assert (mapi < smime_symmetric_count);
650 map = &(smime_cipher_maps[mapi]);
651
652 /*
653 * Convert the next preference found in smime_prefs into an
654 * smime_capability.
655 */
656
657 cap = smime_capabilities[i];
658 if (cap == NULL) {
659 cap = (smime_capability*)PORT_ZAlloc (sizeof(smime_capability));
660 if (cap == NULL)
661 break;
662 smime_capabilities[i] = cap;
663 } else if (cap->cipher == smime_prefs[i]) {
664 continue; /* no change to this one */
665 }
666
667 cap->capIDTag = map->algtag;
668 oiddata = SECOID_FindOIDByTag (map->algtag);
669 if (oiddata == NULL)
670 break;
671
672 if (cap->capabilityID.data != NULL) {
673 SECITEM_FreeItem (&(cap->capabilityID), PR_FALSE);
674 cap->capabilityID.data = NULL;
675 cap->capabilityID.len = 0;
676 }
677
678 rv = SECITEM_CopyItem (NULL, &(cap->capabilityID), &(oiddata->oid));
679 if (rv != SECSuccess)
680 break;
681
682 if (map->parms == NULL) {
683 cap->parameters.data = NULL;
684 cap->parameters.len = 0;
685 } else {
686 cap->parameters.data = map->parms->data;
687 cap->parameters.len = map->parms->len;
688 }
689
690 cap->cipher = smime_prefs[i];
691 }
692
693 if (i != smime_current_pref_index)
694 return rv;
695
696 while (i < smime_symmetric_count) {
697 cap = smime_capabilities[i];
698 if (cap != NULL) {
699 SECITEM_FreeItem (&(cap->capabilityID), PR_FALSE);
700 PORT_Free (cap);
701 }
702 smime_capabilities[i] = NULL;
703 i++;
704 }
705 smime_capabilities[i] = NULL;
706
707 smime_encoded_caps = SEC_ASN1EncodeItem (NULL, NULL, &smime_capabilities,
708 smime_capabilities_template);
709 if (smime_encoded_caps == NULL)
710 return SECFailure;
711
712 return SECSuccess;
713 }
714
715
716 static SECStatus
717 smime_add_profile (CERTCertificate *cert, SEC_PKCS7ContentInfo *cinfo)
718 {
719 PORT_Assert (smime_prefs_complete);
720 if (! smime_prefs_complete)
721 return SECFailure;
722
723 /* For that matter, if capabilities haven't been initialized yet,
724 do so now. */
725 if (smime_encoded_caps == NULL || smime_prefs_changed) {
726 SECStatus rv;
727
728 rv = smime_init_caps();
729 if (rv != SECSuccess)
730 return rv;
731
732 PORT_Assert (smime_encoded_caps != NULL);
733 }
734
735 return SEC_PKCS7AddSignedAttribute (cinfo, SEC_OID_PKCS9_SMIME_CAPABILITIES,
736 smime_encoded_caps);
737 }
738
739
740 /*
741 * Start an S/MIME signing context.
742 *
743 * "scert" is the cert that will be used to sign the data. It will be
744 * checked for validity.
745 *
746 * "ecert" is the signer's encryption cert. If it is different from
747 * scert, then it will be included in the signed message so that the
748 * recipient can save it for future encryptions.
749 *
750 * "certdb" is the cert database to use for verifying the cert.
751 * It can be NULL if a default database is available (like in the client).
752 *
753 * "digestalg" names the digest algorithm (e.g. SEC_OID_SHA1).
754 * XXX There should be SECMIME functions for hashing, or the hashing should
755 * be built into this interface, which we would like because we would
756 * support more smartcards that way, and then this argument should go away.)
757 *
758 * "digest" is the actual digest of the data. It must be provided in
759 * the case of detached data or NULL if the content will be included.
760 *
761 * This function already does all of the stuff specific to S/MIME protocol
762 * and local policy; the return value just needs to be passed to
763 * SEC_PKCS7Encode() or to SEC_PKCS7EncoderStart() to create the encoded data,
764 * and finally to SEC_PKCS7DestroyContentInfo().
765 *
766 * An error results in a return value of NULL and an error set.
767 * (Retrieve specific errors via PORT_GetError()/XP_GetError().)
768 */
769
770 SEC_PKCS7ContentInfo *
771 SECMIME_CreateSigned (CERTCertificate *scert,
772 CERTCertificate *ecert,
773 CERTCertDBHandle *certdb,
774 SECOidTag digestalg,
775 SECItem *digest,
776 SECKEYGetPasswordKey pwfn,
777 void *pwfn_arg)
778 {
779 SEC_PKCS7ContentInfo *cinfo;
780 SECStatus rv;
781
782 /* See note in header comment above about digestalg. */
783 /* Doesn't explain this. PORT_Assert (digestalg == SEC_OID_SHA1); */
784
785 cinfo = SEC_PKCS7CreateSignedData (scert, certUsageEmailSigner,
786 certdb, digestalg, digest,
787 pwfn, pwfn_arg);
788 if (cinfo == NULL)
789 return NULL;
790
791 if (SEC_PKCS7IncludeCertChain (cinfo, NULL) != SECSuccess) {
792 SEC_PKCS7DestroyContentInfo (cinfo);
793 return NULL;
794 }
795
796 /* if the encryption cert and the signing cert differ, then include
797 * the encryption cert too.
798 */
799 /* it is ok to compare the pointers since we ref count, and the same
800 * cert will always have the same pointer
801 */
802 if ( ( ecert != NULL ) && ( ecert != scert ) ) {
803 rv = SEC_PKCS7AddCertificate(cinfo, ecert);
804 if ( rv != SECSuccess ) {
805 SEC_PKCS7DestroyContentInfo (cinfo);
806 return NULL;
807 }
808 }
809 /*
810 * Add the signing time. But if it fails for some reason,
811 * may as well not give up altogether -- just assert.
812 */
813 rv = SEC_PKCS7AddSigningTime (cinfo);
814 PORT_Assert (rv == SECSuccess);
815
816 /*
817 * Add the email profile. Again, if it fails for some reason,
818 * may as well not give up altogether -- just assert.
819 */
820 rv = smime_add_profile (ecert, cinfo);
821 PORT_Assert (rv == SECSuccess);
822
823 return cinfo;
824 }
OLDNEW
« no previous file with comments | « mozilla/security/nss/lib/pkcs7/secmime.h ('k') | mozilla/security/nss/lib/pkcs7/secpkcs7.h » ('j') | no next file with comments »

Powered by Google App Engine