Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(16)

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

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

Powered by Google App Engine
This is Rietveld 408576698