smimeutil.c (46412B)
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 */ 8 9 #include "secmime.h" 10 #include "secoid.h" 11 #include "pk11func.h" 12 #include "ciferfam.h" /* for CIPHER_FAMILY symbols */ 13 #include "secasn1.h" 14 #include "secitem.h" 15 #include "sechash.h" 16 #include "cert.h" 17 #include "keyhi.h" 18 #include "secerr.h" 19 #include "cms.h" 20 #include "nss.h" 21 #include "prerror.h" 22 #include "prinit.h" 23 24 SEC_ASN1_MKSUB(CERT_IssuerAndSNTemplate) 25 SEC_ASN1_MKSUB(SEC_OctetStringTemplate) 26 SEC_ASN1_CHOOSER_DECLARE(CERT_IssuerAndSNTemplate) 27 28 /* 29 * XXX Would like the "parameters" field to be a SECItem *, but the 30 * encoder is having trouble with optional pointers to an ANY. Maybe 31 * once that is fixed, can change this back... 32 */ 33 typedef struct { 34 SECItem capabilityID; 35 SECItem parameters; 36 long cipher; /* optimization */ 37 } NSSSMIMECapability; 38 39 static const SEC_ASN1Template NSSSMIMECapabilityTemplate[] = { 40 { SEC_ASN1_SEQUENCE, 41 0, NULL, sizeof(NSSSMIMECapability) }, 42 { SEC_ASN1_OBJECT_ID, 43 offsetof(NSSSMIMECapability, capabilityID) }, 44 { SEC_ASN1_OPTIONAL | SEC_ASN1_ANY, 45 offsetof(NSSSMIMECapability, parameters) }, 46 { 0 } 47 }; 48 49 static const SEC_ASN1Template NSSSMIMECapabilitiesTemplate[] = { 50 { SEC_ASN1_SEQUENCE_OF, 0, NSSSMIMECapabilityTemplate } 51 }; 52 53 /* 54 * NSSSMIMEEncryptionKeyPreference - if we find one of these, it needs to prompt us 55 * to store this and only this certificate permanently for the sender email address. 56 */ 57 typedef enum { 58 NSSSMIMEEncryptionKeyPref_IssuerSN, 59 NSSSMIMEEncryptionKeyPref_RKeyID, 60 NSSSMIMEEncryptionKeyPref_SubjectKeyID 61 } NSSSMIMEEncryptionKeyPrefSelector; 62 63 typedef struct { 64 NSSSMIMEEncryptionKeyPrefSelector selector; 65 union { 66 CERTIssuerAndSN *issuerAndSN; 67 NSSCMSRecipientKeyIdentifier *recipientKeyID; 68 SECItem *subjectKeyID; 69 } id; 70 } NSSSMIMEEncryptionKeyPreference; 71 72 extern const SEC_ASN1Template NSSCMSRecipientKeyIdentifierTemplate[]; 73 74 static const SEC_ASN1Template smime_encryptionkeypref_template[] = { 75 { SEC_ASN1_CHOICE, 76 offsetof(NSSSMIMEEncryptionKeyPreference, selector), NULL, 77 sizeof(NSSSMIMEEncryptionKeyPreference) }, 78 { SEC_ASN1_POINTER | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 0 | SEC_ASN1_CONSTRUCTED, 79 offsetof(NSSSMIMEEncryptionKeyPreference, id.issuerAndSN), 80 SEC_ASN1_SUB(CERT_IssuerAndSNTemplate), 81 NSSSMIMEEncryptionKeyPref_IssuerSN }, 82 { SEC_ASN1_POINTER | SEC_ASN1_CONTEXT_SPECIFIC | 1 | SEC_ASN1_CONSTRUCTED, 83 offsetof(NSSSMIMEEncryptionKeyPreference, id.recipientKeyID), 84 NSSCMSRecipientKeyIdentifierTemplate, 85 NSSSMIMEEncryptionKeyPref_RKeyID }, 86 { SEC_ASN1_POINTER | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 2 | SEC_ASN1_CONSTRUCTED, 87 offsetof(NSSSMIMEEncryptionKeyPreference, id.subjectKeyID), 88 SEC_ASN1_SUB(SEC_OctetStringTemplate), 89 NSSSMIMEEncryptionKeyPref_SubjectKeyID }, 90 { 0 } 91 }; 92 93 /* table of implemented key exchange algorithms. As we add algorithms, 94 * update this table */ 95 static const SECOidTag implemented_key_encipherment[] = { 96 SEC_OID_PKCS1_RSA_ENCRYPTION, 97 SEC_OID_DHSINGLEPASS_STDDH_SHA1KDF_SCHEME, 98 SEC_OID_DHSINGLEPASS_STDDH_SHA224KDF_SCHEME, 99 SEC_OID_DHSINGLEPASS_STDDH_SHA256KDF_SCHEME, 100 SEC_OID_DHSINGLEPASS_STDDH_SHA384KDF_SCHEME, 101 SEC_OID_DHSINGLEPASS_STDDH_SHA512KDF_SCHEME, 102 SEC_OID_DHSINGLEPASS_COFACTORDH_SHA1KDF_SCHEME, 103 SEC_OID_DHSINGLEPASS_COFACTORDH_SHA224KDF_SCHEME, 104 SEC_OID_DHSINGLEPASS_COFACTORDH_SHA256KDF_SCHEME, 105 SEC_OID_DHSINGLEPASS_COFACTORDH_SHA384KDF_SCHEME, 106 SEC_OID_DHSINGLEPASS_COFACTORDH_SHA512KDF_SCHEME, 107 }; 108 static const int implemented_key_encipherment_len = 109 PR_ARRAY_SIZE(implemented_key_encipherment); 110 111 /* smime_cipher_map - map of SMIME symmetric "ciphers" to algtag & parameters */ 112 typedef struct { 113 unsigned long cipher; 114 SECOidTag policytag; 115 } smime_legacy_map_entry; 116 117 /* legacy array of S/MIME values to map old SMIME entries to modern 118 * algtags. */ 119 static const smime_legacy_map_entry smime_legacy_map[] = { 120 /* cipher, algtag, policy */ 121 /* --------------------------------------- */ 122 { SMIME_RC2_CBC_40, SEC_OID_RC2_40_CBC }, 123 { SMIME_DES_CBC_56, SEC_OID_DES_CBC }, 124 { SMIME_RC2_CBC_64, SEC_OID_RC2_64_CBC }, 125 { SMIME_RC2_CBC_128, SEC_OID_RC2_128_CBC }, 126 { SMIME_DES_EDE3_168, SEC_OID_DES_EDE3_CBC }, 127 { SMIME_AES_CBC_128, SEC_OID_AES_128_CBC }, 128 { SMIME_AES_CBC_256, SEC_OID_AES_256_CBC }, 129 }; 130 static const int smime_legacy_map_count = PR_ARRAY_SIZE(smime_legacy_map); 131 132 static int 133 smime_legacy_pref(SECOidTag algtag) 134 { 135 int i; 136 137 for (i = 0; i < smime_legacy_map_count; i++) { 138 if (smime_legacy_map[i].policytag == algtag) 139 return i; 140 } 141 return -1; 142 } 143 144 /* 145 * smime_legacy_to policy - find policy algtag from a legacy input 146 */ 147 static SECOidTag 148 smime_legacy_to_policy(unsigned long which) 149 { 150 int i; 151 152 for (i = 0; i < smime_legacy_map_count; i++) { 153 if (smime_legacy_map[i].cipher == which) 154 return smime_legacy_map[i].policytag; 155 } 156 return SEC_OID_UNKNOWN; 157 } 158 159 /* map the old legacy values to modern oids. If the value isn't a recognized 160 * legacy value, assume it's a SECOidTag and continue. This allows us to use 161 * the old query and set interfaces with modern oids. */ 162 SECOidTag 163 smime_legacy_to_oid(unsigned long which) 164 { 165 unsigned long mask; 166 167 /* NOTE: all the legacy values and a CIPHER_FAMILYID of 0x00010000, 168 * (CIPHER_FAMILYID_MASK is 0xffff0000). SECOidTags start at 0 and 169 * increase monotonically, so as long as there is less than 16K of 170 * tags, we can distinguish between values intended to be SMIME ciphers 171 * and values intended to be SECOidTags */ 172 mask = which & CIPHER_FAMILYID_MASK; 173 if (mask == CIPHER_FAMILYID_SMIME) { 174 return smime_legacy_to_policy(which); 175 } 176 return (SECOidTag)which; 177 } 178 179 /* SEC_OID_RC2_CBC is actually 3 ciphers with different key lengths. All modern 180 * symmetric ciphers include the key length with the oid. To handle policy for 181 * the different keylengths, we include fake oids that let us map the policy based 182 * on key length */ 183 static SECOidTag 184 smime_get_policy_tag_from_key_length(SECOidTag algtag, unsigned long keybits) 185 { 186 if (algtag == SEC_OID_RC2_CBC) { 187 switch (keybits) { 188 case 40: 189 return SEC_OID_RC2_40_CBC; 190 case 64: 191 return SEC_OID_RC2_64_CBC; 192 case 128: 193 return SEC_OID_RC2_128_CBC; 194 default: 195 break; 196 } 197 return SEC_OID_UNKNOWN; 198 } 199 return algtag; 200 } 201 202 PRBool 203 smime_allowed_by_policy(SECOidTag algtag, PRUint32 neededPolicy) 204 { 205 PRUint32 policyFlags; 206 207 /* some S/MIME algs map to the same underlying KEA mechanism, 208 * collaps them here */ 209 if ((neededPolicy & (NSS_USE_ALG_IN_SMIME_KX | NSS_USE_ALG_IN_SMIME_KX_LEGACY)) != 0) { 210 CK_MECHANISM_TYPE mechType = PK11_AlgtagToMechanism(algtag); 211 switch (mechType) { 212 case CKM_ECDH1_DERIVE: 213 case CKM_ECDH1_COFACTOR_DERIVE: 214 algtag = SEC_OID_ECDH_KEA; 215 break; 216 } 217 } 218 219 if ((NSS_GetAlgorithmPolicy(algtag, &policyFlags) == SECFailure) || 220 ((policyFlags & neededPolicy) != neededPolicy)) { 221 PORT_SetError(SEC_ERROR_BAD_EXPORT_ALGORITHM); 222 return PR_FALSE; 223 } 224 return PR_TRUE; 225 } 226 227 /* 228 * We'll need this for the fake policy oids for RC2, but the 229 * rest of these should be moved to pk11wrap for generic 230 * algtag to key size values. We already need this for 231 * sec_pkcs5v2_key_length_by oid. 232 */ 233 static int 234 smime_keysize_by_cipher(SECOidTag algtag) 235 { 236 int keysize; 237 238 switch (algtag) { 239 case SEC_OID_RC2_40_CBC: 240 keysize = 40; 241 break; 242 case SEC_OID_RC2_64_CBC: 243 keysize = 64; 244 break; 245 case SEC_OID_RC2_128_CBC: 246 case SEC_OID_AES_128_CBC: 247 case SEC_OID_CAMELLIA_128_CBC: 248 keysize = 128; 249 break; 250 case SEC_OID_AES_192_CBC: 251 case SEC_OID_CAMELLIA_192_CBC: 252 keysize = 192; 253 break; 254 case SEC_OID_AES_256_CBC: 255 case SEC_OID_CAMELLIA_256_CBC: 256 keysize = 256; 257 break; 258 default: 259 keysize = 0; 260 break; 261 } 262 263 return keysize; 264 } 265 266 static int 267 smime_max_keysize_by_cipher(SECOidTag algtag) 268 { 269 int keysize = smime_keysize_by_cipher(algtag); 270 271 if (keysize == 0) { 272 CK_MECHANISM_TYPE mech = PK11_AlgtagToMechanism(algtag); 273 return PK11_GetMaxKeyLength(mech) * PR_BITS_PER_BYTE; 274 } 275 return keysize; 276 } 277 278 SECOidTag 279 smime_get_alg_from_policy(SECOidTag policy) 280 { 281 switch (policy) { 282 case SEC_OID_RC2_40_CBC: 283 case SEC_OID_RC2_64_CBC: 284 case SEC_OID_RC2_128_CBC: 285 return SEC_OID_RC2_CBC; 286 default: 287 break; 288 } 289 return policy; 290 } 291 292 typedef struct SMIMEListStr { 293 SECOidTag *tags; 294 size_t space_len; 295 size_t array_len; 296 } SMIMEList; 297 298 static SMIMEList *smime_algorithm_list = NULL; 299 static PZLock *algorithm_list_lock = NULL; 300 static PRCallOnceType smime_init_arg = { 0 }; 301 302 /* return the number of algorithms in the list */ 303 size_t 304 smime_list_length(const SMIMEList *list) 305 { 306 if ((list == NULL) || (list->tags == NULL)) { 307 return 0; 308 } 309 return list->array_len; 310 } 311 312 /* find the index of the algtag in the list. If the algtag isn't on the list, 313 * return the size of the list */ 314 size_t 315 smime_list_index_find(const SMIMEList *list, SECOidTag algtag) 316 { 317 int i; 318 if ((list == NULL) || (list->tags == NULL)) { 319 return 0; 320 } 321 for (i = 0; i < list->array_len; i++) { 322 if (algtag == list->tags[i]) { 323 return i; 324 } 325 } 326 return list->array_len; 327 } 328 329 #define SMIME_CHUNK_COUNT 10 330 /* initialize and grow the list if necessary */ 331 static SECStatus 332 smime_list_grow(SMIMEList **list) 333 { 334 /* first make sure the inital list is created */ 335 if (*list == NULL) { 336 *list = PORT_ZNew(SMIMEList); 337 if (*list == NULL) { 338 return SECFailure; 339 } 340 } 341 /* make sure the tag array is intialized */ 342 if ((*list)->tags == NULL) { 343 (*list)->tags = PORT_ZNewArray(SECOidTag, SMIME_CHUNK_COUNT); 344 if ((*list)->tags == NULL) { 345 return SECFailure; 346 } 347 (*list)->space_len = SMIME_CHUNK_COUNT; 348 } 349 /* grow the tag array if necessary */ 350 if ((*list)->array_len == (*list)->space_len) { 351 SECOidTag *new_space; 352 size_t new_len = (*list)->space_len + SMIME_CHUNK_COUNT; 353 new_space = (SECOidTag *)PORT_Realloc((*list)->tags, 354 new_len * sizeof(SECOidTag)); 355 if (new_space) { 356 return SECFailure; 357 } 358 (*list)->tags = new_space; 359 (*list)->space_len = new_len; 360 } 361 return SECSuccess; 362 } 363 364 /* add a new algtag to the list. if the algtag is already on the list, 365 * do nothing */ 366 static SECStatus 367 smime_list_add(SMIMEList **list, SECOidTag algtag) 368 { 369 SECStatus rv; 370 size_t array_len = smime_list_length(*list); 371 size_t c_index = smime_list_index_find(*list, algtag); 372 373 if (array_len != c_index) { 374 /* already on the list */ 375 return SECSuccess; 376 } 377 378 /* go the list if necessary */ 379 rv = smime_list_grow(list); 380 if (rv != SECSuccess) { 381 return rv; 382 } 383 (*list)->tags[(*list)->array_len++] = algtag; 384 return SECSuccess; 385 } 386 387 static SECStatus 388 smime_list_remove(SMIMEList *list, SECOidTag algtag) 389 { 390 size_t c_index, i; 391 size_t cipher_count = smime_list_length(list); 392 393 if (cipher_count == 0) { 394 return SECSuccess; 395 } 396 c_index = smime_list_index_find(list, algtag); 397 if (c_index == cipher_count) { 398 /* already removed from the list */ 399 return SECSuccess; 400 } 401 for (i = c_index; i < cipher_count - 1; i++) { 402 list->tags[i] = list->tags[i + 1]; 403 } 404 list->array_len--; 405 list->tags[i] = 0; 406 return SECSuccess; 407 } 408 409 static SECOidTag 410 smime_list_fetch_by_index(const SMIMEList *list, size_t c_index) 411 { 412 size_t cipher_count = smime_list_length(list); 413 414 if (c_index >= cipher_count) { 415 return SEC_OID_UNKNOWN; 416 } 417 /* we know this is safe because list cipher_count is non-zero (if it were 418 * any value of c_index will cause the above if to trigger */ 419 return list->tags[c_index]; 420 } 421 422 static void 423 smime_free_list(SMIMEList **list) 424 { 425 if (*list) { 426 if ((*list)->tags) { 427 PORT_Free((*list)->tags); 428 } 429 PORT_Free(*list); 430 } 431 *list = NULL; 432 } 433 434 static void 435 smime_lock_algorithm_list(void) 436 { 437 PORT_Assert(algorithm_list_lock); 438 if (algorithm_list_lock) { 439 PZ_Lock(algorithm_list_lock); 440 } 441 return; 442 } 443 444 static void 445 smime_unlock_algorithm_list(void) 446 { 447 PORT_Assert(algorithm_list_lock); 448 if (algorithm_list_lock) { 449 PZ_Unlock(algorithm_list_lock); 450 } 451 return; 452 } 453 454 static SECStatus 455 smime_shutdown(void *appData, void *nssData) 456 { 457 if (algorithm_list_lock) { 458 PZ_DestroyLock(algorithm_list_lock); 459 algorithm_list_lock = NULL; 460 } 461 smime_free_list(&smime_algorithm_list); 462 memset(&smime_init_arg, 0, sizeof(smime_init_arg)); 463 return SECSuccess; 464 } 465 466 static PRStatus 467 smime_init_once(void *arg) 468 { 469 SECOidTag *tags = NULL; 470 SECStatus rv; 471 int tagCount; 472 int i; 473 int *error = (int *)arg; 474 int *lengths = NULL; 475 int *legacy_prefs = NULL; 476 477 rv = NSS_RegisterShutdown(smime_shutdown, NULL); 478 if (rv != SECSuccess) { 479 *error = PORT_GetError(); 480 return PR_FAILURE; 481 } 482 algorithm_list_lock = PZ_NewLock(nssILockCache); 483 if (algorithm_list_lock == NULL) { 484 *error = PORT_GetError(); 485 return PR_FAILURE; 486 } 487 488 /* At initialization time, we need to set up the defaults. We first 489 * look to see if the system or application has set up certain algorithms 490 * by policy. If they have set up values by policy we'll only allow those 491 * algorithms. We'll then look to see if any algorithms are enabled by 492 * the application. */ 493 rv = NSS_GetAlgorithmPolicyAll(NSS_USE_ALG_IN_SMIME_LEGACY, 494 NSS_USE_ALG_IN_SMIME_LEGACY, 495 &tags, &tagCount); 496 if (tags) { 497 PORT_Free(tags); 498 tags = NULL; 499 } 500 if ((rv != SECSuccess) || (tagCount == 0)) { 501 /* No algorithms have been enabled by policy (either by the system 502 * or by the application, we then will use the traditional default 503 * algorithms from the policy map */ 504 for (i = smime_legacy_map_count - 1; i >= 0; i--) { 505 SECOidTag policytag = smime_legacy_map[i].policytag; 506 /* this enables the algorithm by policy. We need this or 507 * the policy code will reject attempts to use it */ 508 NSS_SetAlgorithmPolicy(policytag, NSS_USE_ALG_IN_SMIME, 0); 509 /* We also need to enable the algorithm. This is usually unde 510 * application control once the defaults are set up, so the 511 * application can turn off a policy that is already on, but 512 * not turn on a policy that is already off */ 513 smime_list_add(&smime_algorithm_list, policytag); 514 } 515 return PR_SUCCESS; 516 } 517 /* We have a system supplied policy, do we also have 518 * system supplied defaults? If we do we will only actually 519 * turn on the algorithms that have been specified. */ 520 rv = NSS_GetAlgorithmPolicyAll(NSS_USE_DEFAULT_NOT_VALID | 521 NSS_USE_DEFAULT_SMIME_ENABLE, 522 NSS_USE_DEFAULT_SMIME_ENABLE, 523 &tags, &tagCount); 524 /* if none found, enable the default algorithms */ 525 if ((rv != SECSuccess) || (tagCount == 0)) { 526 if (tags) { 527 PORT_Free(tags); 528 tags = NULL; 529 } 530 for (i = smime_legacy_map_count - 1; i >= 0; i--) { 531 SECOidTag policytag = smime_legacy_map[i].policytag; 532 /* we only enable the default algorithm, we don't change 533 * it's policy, which the system has already set. NOTE: 534 * what 'enable' means in the S/MIME sense is we advertise 535 * that we can do the given algorithm in our smime capabilities. */ 536 smime_list_add(&smime_algorithm_list, policytag); 537 } 538 return PR_SUCCESS; 539 } 540 541 /* Sort tags by key strength here */ 542 lengths = PORT_ZNewArray(int, tagCount); 543 if (lengths == NULL) { 544 *error = PORT_GetError(); 545 goto loser; 546 } 547 legacy_prefs = PORT_ZNewArray(int, tagCount); 548 if (lengths == NULL) { 549 *error = PORT_GetError(); 550 goto loser; 551 } 552 /* Sort the tags array, highest preference at index 0 */ 553 for (i = 0; i < tagCount; i++) { 554 int len = smime_max_keysize_by_cipher(tags[i]); 555 int lpref = smime_legacy_pref(tags[i]); 556 SECOidTag current = tags[i]; 557 PRBool shift = PR_FALSE; 558 int j; 559 /* Determine best position for tags[i]. 560 * For each position j, check if tags [i] has a higher preference. 561 * If yes, store tags[i] at position j, and move all following 562 * entries one position to the back of the array. 563 */ 564 for (j = 0; j < i; j++) { 565 int tlen = lengths[j]; 566 int tpref = legacy_prefs[j]; 567 SECOidTag ttag = tags[j]; 568 /* we prefer ciphers with bigger keysizes, then 569 * we prefer ciphers in our historical list, 570 * then we prefer ciphers that show up first 571 * from the oid table */ 572 if (shift || (len > tlen) || ((len == tlen) && (lpref > tpref))) { 573 tags[j] = current; 574 lengths[j] = len; 575 legacy_prefs[j] = lpref; 576 current = ttag; 577 len = tlen; 578 lpref = tpref; 579 shift = PR_TRUE; 580 } 581 } 582 tags[i] = current; 583 lengths[i] = len; 584 legacy_prefs[i] = lpref; 585 } 586 587 /* put them in the enable list */ 588 for (i = 0; i < tagCount; i++) { 589 smime_list_add(&smime_algorithm_list, tags[i]); 590 } 591 PORT_Free(lengths); 592 PORT_Free(legacy_prefs); 593 PORT_Free(tags); 594 return PR_SUCCESS; 595 loser: 596 if (lengths) 597 PORT_Free(lengths); 598 if (legacy_prefs) 599 PORT_Free(legacy_prefs); 600 if (tags) 601 PORT_Free(tags); 602 return PR_FAILURE; 603 } 604 605 static SECStatus 606 smime_init(void) 607 { 608 static PRBool smime_policy_initted = PR_FALSE; 609 static int error = 0; 610 PRStatus nrv; 611 612 /* has NSS been initialized? */ 613 if (!NSS_IsInitialized()) { 614 PORT_SetError(SEC_ERROR_NOT_INITIALIZED); 615 return SECFailure; 616 } 617 if (smime_policy_initted) { 618 return SECSuccess; 619 } 620 nrv = PR_CallOnceWithArg(&smime_init_arg, smime_init_once, &error); 621 if (nrv == PR_SUCCESS) { 622 smime_policy_initted = PR_TRUE; 623 return SECSuccess; 624 } 625 PORT_SetError(error); 626 return SECFailure; 627 } 628 629 /* 630 * NSS_SMIME_EnableCipher - this function locally records the user's preference 631 */ 632 SECStatus 633 NSS_SMIMEUtil_EnableCipher(unsigned long which, PRBool on) 634 { 635 SECOidTag algtag; 636 637 SECStatus rv = smime_init(); 638 if (rv != SECSuccess) { 639 return SECFailure; 640 } 641 642 algtag = smime_legacy_to_oid(which); 643 if (!smime_allowed_by_policy(algtag, NSS_USE_ALG_IN_SMIME)) { 644 PORT_SetError(SEC_ERROR_BAD_EXPORT_ALGORITHM); 645 return SECFailure; 646 } 647 648 smime_lock_algorithm_list(); 649 if (on) { 650 rv = smime_list_add(&smime_algorithm_list, algtag); 651 } else { 652 rv = smime_list_remove(smime_algorithm_list, algtag); 653 } 654 smime_unlock_algorithm_list(); 655 return rv; 656 } 657 658 /* 659 * this function locally records the export policy 660 */ 661 SECStatus 662 NSS_SMIMEUtil_AllowCipher(unsigned long which, PRBool on) 663 { 664 SECOidTag algtag = smime_legacy_to_oid(which); 665 PRUint32 set = on ? NSS_USE_ALG_IN_SMIME : 0; 666 PRUint32 clear = on ? 0 : NSS_USE_ALG_IN_SMIME; 667 /* make sure we are inited before setting, so 668 * the defaults are correct */ 669 SECStatus rv = smime_init(); 670 if (rv != SECSuccess) { 671 return SECFailure; 672 } 673 674 return NSS_SetAlgorithmPolicy(algtag, set, clear); 675 } 676 677 PRBool 678 NSS_SMIMEUtil_DecryptionAllowed(SECAlgorithmID *algid, PK11SymKey *key) 679 { 680 SECOidTag algtag; 681 /* make sure we are inited before checking policy, so 682 * the defaults are correct */ 683 SECStatus rv = smime_init(); 684 if (rv != SECSuccess) { 685 return SECFailure; 686 } 687 688 algtag = smime_get_policy_tag_from_key_length(SECOID_GetAlgorithmTag(algid), 689 PK11_GetKeyStrength(key, algid)); 690 return smime_allowed_by_policy(algtag, NSS_USE_ALG_IN_SMIME_LEGACY); 691 } 692 693 PRBool 694 NSS_SMIMEUtil_EncryptionAllowed(SECAlgorithmID *algid, PK11SymKey *key) 695 { 696 SECOidTag algtag; 697 /* make sure we are inited before checking policy, so 698 * the defaults are correct */ 699 SECStatus rv = smime_init(); 700 if (rv != SECSuccess) { 701 return SECFailure; 702 } 703 704 algtag = smime_get_policy_tag_from_key_length(SECOID_GetAlgorithmTag(algid), 705 PK11_GetKeyStrength(key, algid)); 706 return smime_allowed_by_policy(algtag, NSS_USE_ALG_IN_SMIME); 707 } 708 709 PRBool 710 NSS_SMIMEUtil_SigningAllowed(SECAlgorithmID *algid) 711 { 712 SECOidTag algtag; 713 /* we don't adjust SIGNATURE policy based on defaults, so no need 714 * to call smime_init() */ 715 716 algtag = SECOID_GetAlgorithmTag(algid); 717 return smime_allowed_by_policy(algtag, NSS_USE_ALG_IN_SMIME_SIGNATURE); 718 } 719 720 static PRBool 721 nss_smime_enforce_key_size(void) 722 { 723 PRInt32 optFlags; 724 725 if (NSS_OptionGet(NSS_KEY_SIZE_POLICY_FLAGS, &optFlags) != SECFailure) { 726 if (optFlags & NSS_KEY_SIZE_POLICY_SMIME_FLAG) { 727 return PR_TRUE; 728 } 729 } 730 return PR_FALSE; 731 } 732 733 PRBool 734 NSS_SMIMEUtil_KeyEncodingAllowed(SECAlgorithmID *algid, CERTCertificate *cert, 735 SECKEYPublicKey *key) 736 { 737 SECOidTag algtag; 738 /* we don't adjust KEA policy based on defaults, so no need 739 * to call smime_init() */ 740 741 /* if required, make sure the key lengths are enforced */ 742 if (nss_smime_enforce_key_size()) { 743 SECStatus rv; 744 PRBool freeKey = PR_FALSE; 745 746 if (!key) { 747 /* either the public key or the cert must be supplied. If the 748 * key wasn't supplied, get it from the certificate */ 749 if (!cert) { 750 PORT_SetError(SEC_ERROR_INVALID_ARGS); 751 return PR_FALSE; 752 } 753 key = CERT_ExtractPublicKey(cert); 754 freeKey = PR_TRUE; 755 } 756 rv = SECKEY_EnforceKeySize(key->keyType, 757 SECKEY_PublicKeyStrengthInBits(key), 758 SEC_ERROR_BAD_EXPORT_ALGORITHM); 759 if (freeKey) { 760 SECKEY_DestroyPublicKey(key); 761 } 762 if (rv != SECSuccess) { 763 return PR_FALSE; 764 } 765 } 766 algtag = SECOID_GetAlgorithmTag(algid); 767 return smime_allowed_by_policy(algtag, NSS_USE_ALG_IN_SMIME_KX); 768 } 769 770 PRBool 771 NSS_SMIMEUtil_KeyDecodingAllowed(SECAlgorithmID *algid, SECKEYPrivateKey *key) 772 { 773 SECOidTag algtag; 774 /* we don't adjust KEA policy based on defaults, so no need 775 * to call smime_init() */ 776 777 /* if required, make sure the key lengths are enforced */ 778 if (nss_smime_enforce_key_size()) { 779 SECStatus rv; 780 rv = SECKEY_EnforceKeySize(key->keyType, 781 SECKEY_PrivateKeyStrengthInBits(key), 782 SEC_ERROR_BAD_EXPORT_ALGORITHM); 783 if (rv != SECSuccess) { 784 return PR_FALSE; 785 } 786 } 787 algtag = SECOID_GetAlgorithmTag(algid); 788 return smime_allowed_by_policy(algtag, NSS_USE_ALG_IN_SMIME_KX_LEGACY); 789 } 790 791 /* 792 * NSS_SMIME_EncryptionPossible - check if any encryption is allowed 793 * 794 * This tells whether or not *any* S/MIME encryption can be done, 795 * according to policy. Callers may use this to do nicer user interface 796 * (say, greying out a checkbox so a user does not even try to encrypt 797 * a message when they are not allowed to) or for any reason they want 798 * to check whether S/MIME encryption (or decryption, for that matter) 799 * may be done. 800 * 801 * It takes no arguments. The return value is a simple boolean: 802 * PR_TRUE means encryption (or decryption) is *possible* 803 * (but may still fail due to other reasons, like because we cannot 804 * find all the necessary certs, etc.; PR_TRUE is *not* a guarantee) 805 * PR_FALSE means encryption (or decryption) is not permitted 806 * 807 * There are no errors from this routine. 808 */ 809 PRBool 810 NSS_SMIMEUtil_EncryptionPossible(void) 811 { 812 SECStatus rv = smime_init(); 813 size_t len; 814 if (rv != SECSuccess) { 815 return SECFailure; 816 } 817 smime_lock_algorithm_list(); 818 len = smime_list_length(smime_algorithm_list); 819 smime_unlock_algorithm_list(); 820 return len != 0 ? PR_TRUE : PR_FALSE; 821 } 822 823 PRBool 824 NSS_SMIMEUtil_EncryptionEnabled(int which) 825 { 826 SECOidTag algtag; 827 size_t c_index, len; 828 829 SECStatus rv = smime_init(); 830 if (rv != SECSuccess) { 831 return SECFailure; 832 } 833 834 algtag = smime_legacy_to_oid(which); 835 836 smime_lock_algorithm_list(); 837 len = smime_list_length(smime_algorithm_list); 838 c_index = smime_list_index_find(smime_algorithm_list, algtag); 839 smime_unlock_algorithm_list(); 840 841 if (len >= c_index) { 842 return PR_FALSE; 843 } 844 845 return smime_allowed_by_policy(algtag, NSS_USE_ALG_IN_SMIME); 846 } 847 848 static SECOidTag 849 nss_SMIME_FindCipherForSMIMECap(NSSSMIMECapability *cap) 850 { 851 SECOidTag capIDTag; 852 853 /* we need the OIDTag here */ 854 capIDTag = SECOID_FindOIDTag(&(cap->capabilityID)); 855 856 /* RC2 used a generic oid and encoded the key length in the 857 * parameters */ 858 if (capIDTag == SEC_OID_RC2_CBC) { 859 SECStatus rv; 860 unsigned long key_bits; 861 SECItem keyItem = { siBuffer, NULL, 0 }; 862 863 rv = SEC_ASN1DecodeItem(NULL, &keyItem, 864 SEC_ASN1_GET(SEC_IntegerTemplate), &cap->parameters); 865 if (rv != SECSuccess) { 866 return SEC_OID_UNKNOWN; 867 } 868 rv = SEC_ASN1DecodeInteger(&keyItem, &key_bits); 869 SECITEM_FreeItem(&keyItem, PR_FALSE); 870 if (rv != SECSuccess) { 871 return SEC_OID_UNKNOWN; 872 } 873 return smime_get_policy_tag_from_key_length(capIDTag, key_bits); 874 } 875 876 /* everything else uses a null parameter */ 877 if (!cap->parameters.data || !cap->parameters.len) { 878 return capIDTag; 879 } 880 if (cap->parameters.len == 2 && 881 cap->parameters.data[0] == SEC_ASN1_NULL && 882 cap->parameters.data[1] == 0) { 883 return capIDTag; 884 } 885 return SEC_OID_UNKNOWN; 886 } 887 888 /* 889 * smime_choose_cipher - choose a cipher that works for all the recipients 890 * 891 * "rcerts" - recipient's certificates 892 */ 893 static SECOidTag 894 smime_choose_cipher(CERTCertificate **rcerts) 895 { 896 PLArenaPool *poolp = NULL; 897 SECOidTag chosen_cipher = SEC_OID_UNKNOWN; 898 size_t cipher_count; 899 SECOidTag cipher; 900 int *cipher_abilities; 901 int *cipher_votes; 902 size_t weak_index; 903 size_t strong_index; 904 size_t aes128_index; 905 size_t aes256_index; 906 size_t c_index; 907 int rcount, max; 908 909 smime_lock_algorithm_list(); 910 cipher_count = smime_list_length(smime_algorithm_list); 911 if (cipher_count == 0) { 912 goto done; 913 } 914 915 chosen_cipher = SEC_OID_RC2_40_CBC; /* the default, LCD */ 916 weak_index = smime_list_index_find(smime_algorithm_list, chosen_cipher); 917 strong_index = smime_list_index_find(smime_algorithm_list, SEC_OID_DES_EDE3_CBC); 918 aes128_index = smime_list_index_find(smime_algorithm_list, SEC_OID_AES_128_CBC); 919 aes256_index = smime_list_index_find(smime_algorithm_list, SEC_OID_AES_256_CBC); 920 /* make sure the default selected cipher is enabled */ 921 if (weak_index == cipher_count) { 922 chosen_cipher = SEC_OID_DES_EDE3_CBC; 923 if (strong_index == cipher_count) { 924 chosen_cipher = SEC_OID_AES_128_CBC; 925 if (aes128_index == cipher_count) { 926 chosen_cipher = SEC_OID_AES_256_CBC; 927 if (aes256_index == cipher_count) { 928 /* none of the standard algorithms are enabled, If the 929 * recipients don't explicitly include a better cipher 930 * then fail */ 931 chosen_cipher = SEC_OID_UNKNOWN; 932 } 933 } 934 } 935 } 936 937 poolp = PORT_NewArena(1024); /* XXX what is right value? */ 938 if (poolp == NULL) 939 goto done; 940 941 cipher_abilities = PORT_ArenaZNewArray(poolp, int, cipher_count + 1); 942 cipher_votes = PORT_ArenaZNewArray(poolp, int, cipher_count + 1); 943 if (cipher_votes == NULL || cipher_abilities == NULL) { 944 goto done; 945 } 946 947 /* Make triple-DES the strong cipher. */ 948 949 /* walk all the recipient's certs */ 950 for (rcount = 0; rcerts[rcount] != NULL; rcount++) { 951 SECItem *profile; 952 NSSSMIMECapability **caps; 953 int pref; 954 955 /* the first cipher that matches in the user's SMIME profile gets 956 * "cipher_count" votes; the next one gets "cipher_count" - 1 957 * and so on. If every cipher matches, the last one gets 1 (one) vote */ 958 pref = cipher_count; 959 960 /* find recipient's SMIME profile */ 961 profile = CERT_FindSMimeProfile(rcerts[rcount]); 962 963 if (profile != NULL && profile->data != NULL && profile->len > 0) { 964 /* we have a profile (still DER-encoded) */ 965 caps = NULL; 966 /* decode it */ 967 if (SEC_QuickDERDecodeItem(poolp, &caps, 968 NSSSMIMECapabilitiesTemplate, profile) == SECSuccess && 969 caps != NULL) { 970 int i; 971 /* walk the SMIME capabilities for this recipient */ 972 for (i = 0; caps[i] != NULL; i++) { 973 cipher = nss_SMIME_FindCipherForSMIMECap(caps[i]); 974 c_index = smime_list_index_find(smime_algorithm_list, cipher); 975 if (c_index < cipher_count) { 976 /* found the cipher */ 977 cipher_abilities[c_index]++; 978 cipher_votes[c_index] += pref; 979 --pref; 980 } 981 } 982 } 983 } else { 984 /* no profile found - so we can only assume that the user can do 985 * the mandatory algorithms which are RC2-40 (weak crypto) and 986 * 3DES (strong crypto), unless the user has an elliptic curve 987 * key. For elliptic curve keys, RFC 5753 mandates support 988 * for AES 128 CBC. */ 989 SECKEYPublicKey *key; 990 unsigned int pklen_bits; 991 KeyType key_type; 992 993 /* 994 * if recipient's public key length is > 512, vote for a strong cipher 995 * please not that the side effect of this is that if only one recipient 996 * has an export-level public key, the strong cipher is disabled. 997 * 998 * XXX This is probably only good for RSA keys. What I would 999 * really like is a function to just say; Is the public key in 1000 * this cert an export-length key? Then I would not have to 1001 * know things like the value 512, or the kind of key, or what 1002 * a subjectPublicKeyInfo is, etc. 1003 */ 1004 key = CERT_ExtractPublicKey(rcerts[rcount]); 1005 pklen_bits = 0; 1006 key_type = nullKey; 1007 if (key != NULL) { 1008 pklen_bits = SECKEY_PublicKeyStrengthInBits(key); 1009 key_type = SECKEY_GetPublicKeyType(key); 1010 SECKEY_DestroyPublicKey(key); 1011 key = NULL; 1012 } 1013 1014 if (key_type == ecKey) { 1015 /* While RFC 5753 mandates support for AES-128 CBC, should use 1016 * AES 256 if user's key provides more than 128 bits of 1017 * security strength so that symmetric key is not weak link. */ 1018 1019 /* RC2-40 is not compatible with elliptic curve keys. */ 1020 if (chosen_cipher == SEC_OID_RC2_40_CBC) { 1021 chosen_cipher = SEC_OID_AES_128_CBC; 1022 } 1023 if (pklen_bits > 256) { 1024 cipher_abilities[aes256_index]++; 1025 cipher_votes[aes256_index] += pref; 1026 pref--; 1027 } 1028 cipher_abilities[aes128_index]++; 1029 cipher_votes[aes128_index] += pref; 1030 pref--; 1031 cipher_abilities[strong_index]++; 1032 cipher_votes[strong_index] += pref; 1033 pref--; 1034 } else { 1035 if (pklen_bits > 3072) { 1036 /* While support for AES 256 is a SHOULD+ in RFC 5751 1037 * rather than a MUST, RSA and DSA keys longer than 3072 1038 * bits provide more than 128 bits of security strength. 1039 * So, AES 256 should be used to provide comparable 1040 * security. */ 1041 cipher_abilities[aes256_index]++; 1042 cipher_votes[aes256_index] += pref; 1043 pref--; 1044 } 1045 if (pklen_bits > 1023) { 1046 /* RFC 5751 mandates support for AES 128, but also says 1047 * that RSA and DSA signature keys SHOULD NOT be less than 1048 * 1024 bits. So, cast vote for AES 128 if key length 1049 * is at least 1024 bits. */ 1050 cipher_abilities[aes128_index]++; 1051 cipher_votes[aes128_index] += pref; 1052 pref--; 1053 } 1054 if (pklen_bits > 512) { 1055 /* cast votes for the strong algorithm */ 1056 cipher_abilities[strong_index]++; 1057 cipher_votes[strong_index] += pref; 1058 pref--; 1059 } 1060 1061 /* always cast (possibly less) votes for the weak algorithm */ 1062 cipher_abilities[weak_index]++; 1063 cipher_votes[weak_index] += pref; 1064 } 1065 } 1066 if (profile != NULL) 1067 SECITEM_FreeItem(profile, PR_TRUE); 1068 } 1069 1070 /* find cipher that is agreeable by all recipients and that has the most votes */ 1071 max = 0; 1072 for (c_index = 0; c_index < cipher_count; c_index++) { 1073 /* if not all of the recipients can do this, forget it */ 1074 if (cipher_abilities[c_index] != rcount) 1075 continue; 1076 cipher = smime_list_fetch_by_index(smime_algorithm_list, c_index); 1077 /* if cipher is allowed by policy, forget it */ 1078 if (!smime_allowed_by_policy(cipher, NSS_USE_ALG_IN_SMIME)) { 1079 continue; 1080 } 1081 /* now see if this one has more votes than the last best one */ 1082 if (cipher_votes[c_index] >= max) { 1083 /* if equal number of votes, prefer the ones further down in the list */ 1084 /* with the expectation that these are higher rated ciphers */ 1085 chosen_cipher = cipher; 1086 max = cipher_votes[c_index]; 1087 } 1088 } 1089 /* if no common cipher was found, chosen_cipher stays at the default */ 1090 1091 done: 1092 smime_unlock_algorithm_list(); 1093 if (poolp != NULL) 1094 PORT_FreeArena(poolp, PR_FALSE); 1095 1096 return chosen_cipher; 1097 } 1098 1099 /* 1100 * NSS_SMIMEUtil_FindBulkAlgForRecipients - find bulk algorithm suitable for all recipients 1101 * 1102 * it would be great for UI purposes if there would be a way to find out which recipients 1103 * prevented a strong cipher from being used... 1104 */ 1105 SECStatus 1106 NSS_SMIMEUtil_FindBulkAlgForRecipients(CERTCertificate **rcerts, 1107 SECOidTag *bulkalgtag, int *keysize) 1108 { 1109 SECOidTag cipher; 1110 1111 SECStatus rv = smime_init(); 1112 if (rv != SECSuccess) { 1113 return SECFailure; 1114 } 1115 1116 cipher = smime_choose_cipher(rcerts); 1117 if (cipher == SEC_OID_UNKNOWN) { 1118 PORT_SetError(SEC_ERROR_BAD_EXPORT_ALGORITHM); 1119 return SECFailure; 1120 } 1121 1122 *bulkalgtag = smime_get_alg_from_policy(cipher); 1123 *keysize = smime_keysize_by_cipher(cipher); 1124 1125 return SECSuccess; 1126 } 1127 1128 /* 1129 * Create a new Capability from an oid tag 1130 */ 1131 static NSSSMIMECapability * 1132 smime_create_capability(SECOidTag cipher) 1133 { 1134 NSSSMIMECapability *cap = NULL; 1135 SECOidData *oiddata = NULL; 1136 SECItem *dummy = NULL; 1137 1138 oiddata = SECOID_FindOIDByTag(smime_get_alg_from_policy(cipher)); 1139 if (oiddata == NULL) { 1140 return NULL; 1141 } 1142 1143 cap = PORT_ZNew(NSSSMIMECapability); 1144 if (cap == NULL) { 1145 return NULL; 1146 } 1147 1148 cap->capabilityID.data = oiddata->oid.data; 1149 cap->capabilityID.len = oiddata->oid.len; 1150 if (cipher == SEC_OID_RC2_CBC) { 1151 SECItem keyItem = { siBuffer, NULL, 0 }; 1152 unsigned long keybits = smime_get_alg_from_policy(cipher); 1153 dummy = SEC_ASN1EncodeInteger(NULL, &keyItem, keybits); 1154 if (dummy == NULL) { 1155 PORT_Free(cap); 1156 return NULL; 1157 } 1158 dummy = SEC_ASN1EncodeItem(NULL, &cap->parameters, 1159 &keyItem, SEC_ASN1_GET(SEC_IntegerTemplate)); 1160 SECITEM_FreeItem(&keyItem, PR_FALSE); 1161 if (dummy == NULL) { 1162 PORT_Free(cap); 1163 return NULL; 1164 } 1165 } else { 1166 cap->parameters.data = NULL; 1167 cap->parameters.len = 0; 1168 } 1169 return cap; 1170 } 1171 /* 1172 * NSS_SMIMEUtil_CreateSMIMECapabilities - get S/MIME capabilities for this instance of NSS 1173 * 1174 * scans the list of allowed and enabled ciphers and construct a PKCS9-compliant 1175 * S/MIME capabilities attribute value. 1176 * 1177 * XXX Please note that, in contradiction to RFC2633 2.5.2, the capabilities only include 1178 * symmetric ciphers, NO signature algorithms or key encipherment algorithms. 1179 * 1180 * "poolp" - arena pool to create the S/MIME capabilities data on 1181 * "dest" - SECItem to put the data in 1182 */ 1183 SECStatus 1184 NSS_SMIMEUtil_CreateSMIMECapabilities(PLArenaPool *poolp, SECItem *dest) 1185 { 1186 NSSSMIMECapability *cap = NULL; 1187 NSSSMIMECapability **smime_capabilities = NULL; 1188 SECItem *dummy = NULL; 1189 int i, capIndex; 1190 int cap_count; 1191 int cipher_count; 1192 int hash_count; 1193 1194 SECStatus rv = smime_init(); 1195 if (rv != SECSuccess) { 1196 return SECFailure; 1197 } 1198 /* First get the hash count */ 1199 for (i = HASH_AlgNULL + 1;; i++) { 1200 if (HASH_GetHashOidTagByHashType(i) == SEC_OID_UNKNOWN) { 1201 break; 1202 } 1203 } 1204 hash_count = i - 1; 1205 1206 smime_lock_algorithm_list(); 1207 /* now get the cipher count */ 1208 cipher_count = smime_list_length(smime_algorithm_list); 1209 if (cipher_count == 0) { 1210 smime_unlock_algorithm_list(); 1211 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); 1212 return SECFailure; 1213 } 1214 1215 cap_count = cipher_count + hash_count + implemented_key_encipherment_len; 1216 1217 /* cipher_count + 1 is an upper bound - we might end up with less */ 1218 smime_capabilities = PORT_ZNewArray(NSSSMIMECapability *, cap_count + 1); 1219 if (smime_capabilities == NULL) { 1220 smime_unlock_algorithm_list(); 1221 return SECFailure; 1222 } 1223 1224 capIndex = 0; 1225 1226 /* Add all the symmetric ciphers 1227 * We walk the cipher list, as it is ordered by decreasing strength, 1228 * we prefer the stronger cipher over a weaker one, and we have to list the 1229 * preferred algorithm first */ 1230 for (i = 0; i < cipher_count; i++) { 1231 SECOidTag cipher = smime_list_fetch_by_index(smime_algorithm_list, i); 1232 1233 /* is it allowed by policy? */ 1234 if (!smime_allowed_by_policy(cipher, NSS_USE_ALG_IN_SMIME)) { 1235 continue; 1236 } 1237 cipher = smime_get_alg_from_policy(cipher); 1238 1239 cap = smime_create_capability(cipher); 1240 if (cap == NULL) 1241 break; 1242 smime_capabilities[capIndex++] = cap; 1243 } 1244 /* add signature algorithms = hash algs. 1245 * probably also need to figure how what 1246 * actual signatures we support in secvfy 1247 * as well. We currently don't look a these 1248 * when choosing hash and signature (hash is 1249 * chosen by the application and signature 1250 * type is chosen by the signing cert/key) */ 1251 smime_unlock_algorithm_list(); 1252 for (i = HASH_AlgNULL + 1; i < hash_count + 1; i++) { 1253 SECOidTag hash_alg = HASH_GetHashOidTagByHashType(i); 1254 1255 if (!smime_allowed_by_policy(hash_alg, 1256 NSS_USE_ALG_IN_SMIME_SIGNATURE | NSS_USE_ALG_IN_SIGNATURE)) { 1257 continue; 1258 } 1259 cap = smime_create_capability(hash_alg); 1260 /* get next SMIME capability */ 1261 if (cap == NULL) 1262 break; 1263 smime_capabilities[capIndex++] = cap; 1264 } 1265 1266 /* add key encipherment algorithms . These are static 1267 * to the s/mime library, so we can just use the table. 1268 * new kea algs should be implemented. We don't use these 1269 * because the senders key pretty much selects what time 1270 * of kea we are going to implement */ 1271 for (i = 0; i < implemented_key_encipherment_len; i++) { 1272 SECOidTag kea_alg = implemented_key_encipherment[i]; 1273 1274 if (!smime_allowed_by_policy(kea_alg, NSS_USE_ALG_IN_SMIME_KX)) { 1275 continue; 1276 } 1277 cap = smime_create_capability(kea_alg); 1278 /* get next SMIME capability */ 1279 if (cap == NULL) 1280 break; 1281 smime_capabilities[capIndex++] = cap; 1282 } 1283 1284 smime_capabilities[capIndex] = NULL; /* last one - now encode */ 1285 dummy = SEC_ASN1EncodeItem(poolp, dest, &smime_capabilities, NSSSMIMECapabilitiesTemplate); 1286 1287 /* now that we have the proper encoded SMIMECapabilities (or not), 1288 * free the work data */ 1289 for (i = 0; smime_capabilities[i] != NULL; i++) { 1290 if (smime_capabilities[i]->parameters.data) { 1291 PORT_Free(smime_capabilities[i]->parameters.data); 1292 } 1293 PORT_Free(smime_capabilities[i]); 1294 } 1295 PORT_Free(smime_capabilities); 1296 1297 return (dummy == NULL) ? SECFailure : SECSuccess; 1298 } 1299 1300 /* 1301 * NSS_SMIMEUtil_CreateSMIMEEncKeyPrefs - create S/MIME encryption key preferences attr value 1302 * 1303 * "poolp" - arena pool to create the attr value on 1304 * "dest" - SECItem to put the data in 1305 * "cert" - certificate that should be marked as preferred encryption key 1306 * cert is expected to have been verified for EmailRecipient usage. 1307 */ 1308 SECStatus 1309 NSS_SMIMEUtil_CreateSMIMEEncKeyPrefs(PLArenaPool *poolp, SECItem *dest, CERTCertificate *cert) 1310 { 1311 NSSSMIMEEncryptionKeyPreference ekp; 1312 SECItem *dummy = NULL; 1313 PLArenaPool *tmppoolp = NULL; 1314 1315 if (cert == NULL) 1316 goto loser; 1317 1318 tmppoolp = PORT_NewArena(1024); 1319 if (tmppoolp == NULL) 1320 goto loser; 1321 1322 /* XXX hardcoded IssuerSN choice for now */ 1323 ekp.selector = NSSSMIMEEncryptionKeyPref_IssuerSN; 1324 ekp.id.issuerAndSN = CERT_GetCertIssuerAndSN(tmppoolp, cert); 1325 if (ekp.id.issuerAndSN == NULL) 1326 goto loser; 1327 1328 dummy = SEC_ASN1EncodeItem(poolp, dest, &ekp, smime_encryptionkeypref_template); 1329 1330 loser: 1331 if (tmppoolp) 1332 PORT_FreeArena(tmppoolp, PR_FALSE); 1333 1334 return (dummy == NULL) ? SECFailure : SECSuccess; 1335 } 1336 1337 /* 1338 * NSS_SMIMEUtil_CreateSMIMEEncKeyPrefs - create S/MIME encryption key preferences attr value using MS oid 1339 * 1340 * "poolp" - arena pool to create the attr value on 1341 * "dest" - SECItem to put the data in 1342 * "cert" - certificate that should be marked as preferred encryption key 1343 * cert is expected to have been verified for EmailRecipient usage. 1344 */ 1345 SECStatus 1346 NSS_SMIMEUtil_CreateMSSMIMEEncKeyPrefs(PLArenaPool *poolp, SECItem *dest, CERTCertificate *cert) 1347 { 1348 SECItem *dummy = NULL; 1349 PLArenaPool *tmppoolp = NULL; 1350 CERTIssuerAndSN *isn; 1351 1352 if (cert == NULL) 1353 goto loser; 1354 1355 tmppoolp = PORT_NewArena(1024); 1356 if (tmppoolp == NULL) 1357 goto loser; 1358 1359 isn = CERT_GetCertIssuerAndSN(tmppoolp, cert); 1360 if (isn == NULL) 1361 goto loser; 1362 1363 dummy = SEC_ASN1EncodeItem(poolp, dest, isn, SEC_ASN1_GET(CERT_IssuerAndSNTemplate)); 1364 1365 loser: 1366 if (tmppoolp) 1367 PORT_FreeArena(tmppoolp, PR_FALSE); 1368 1369 return (dummy == NULL) ? SECFailure : SECSuccess; 1370 } 1371 1372 /* 1373 * NSS_SMIMEUtil_GetCertFromEncryptionKeyPreference - 1374 * find cert marked by EncryptionKeyPreference attribute 1375 * 1376 * "certdb" - handle for the cert database to look in 1377 * "DERekp" - DER-encoded value of S/MIME Encryption Key Preference attribute 1378 * 1379 * if certificate is supposed to be found among the message's included certificates, 1380 * they are assumed to have been imported already. 1381 */ 1382 CERTCertificate * 1383 NSS_SMIMEUtil_GetCertFromEncryptionKeyPreference(CERTCertDBHandle *certdb, SECItem *DERekp) 1384 { 1385 PLArenaPool *tmppoolp = NULL; 1386 CERTCertificate *cert = NULL; 1387 NSSSMIMEEncryptionKeyPreference ekp; 1388 1389 tmppoolp = PORT_NewArena(1024); 1390 if (tmppoolp == NULL) 1391 return NULL; 1392 1393 /* decode DERekp */ 1394 if (SEC_QuickDERDecodeItem(tmppoolp, &ekp, smime_encryptionkeypref_template, 1395 DERekp) != SECSuccess) 1396 goto loser; 1397 1398 /* find cert */ 1399 switch (ekp.selector) { 1400 case NSSSMIMEEncryptionKeyPref_IssuerSN: 1401 cert = CERT_FindCertByIssuerAndSN(certdb, ekp.id.issuerAndSN); 1402 break; 1403 case NSSSMIMEEncryptionKeyPref_RKeyID: 1404 case NSSSMIMEEncryptionKeyPref_SubjectKeyID: 1405 /* XXX not supported yet - we need to be able to look up certs by SubjectKeyID */ 1406 break; 1407 default: 1408 PORT_Assert(0); 1409 } 1410 loser: 1411 if (tmppoolp) 1412 PORT_FreeArena(tmppoolp, PR_FALSE); 1413 1414 return cert; 1415 } 1416 1417 extern const char __nss_smime_version[]; 1418 1419 PRBool 1420 NSSSMIME_VersionCheck(const char *importedVersion) 1421 { 1422 #define NSS_VERSION_VARIABLE __nss_smime_version 1423 #include "verref.h" 1424 /* 1425 * This is the secret handshake algorithm. 1426 * 1427 * This release has a simple version compatibility 1428 * check algorithm. This release is not backward 1429 * compatible with previous major releases. It is 1430 * not compatible with future major, minor, or 1431 * patch releases. 1432 */ 1433 return NSS_VersionCheck(importedVersion); 1434 } 1435 1436 const char * 1437 NSSSMIME_GetVersion(void) 1438 { 1439 return NSS_VERSION; 1440 }