certdb.c (98367B)
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 * Certificate handling code 7 */ 8 9 #include "nssilock.h" 10 #include "prmon.h" 11 #include "prtime.h" 12 #include "cert.h" 13 #include "certi.h" 14 #include "secder.h" 15 #include "secoid.h" 16 #include "secasn1.h" 17 #include "genname.h" 18 #include "keyhi.h" 19 #include "secitem.h" 20 #include "certdb.h" 21 #include "prprf.h" 22 #include "sechash.h" 23 #include "prlong.h" 24 #include "certxutl.h" 25 #include "portreg.h" 26 #include "secerr.h" 27 #include "sslerr.h" 28 #include "pk11func.h" 29 #include "xconst.h" /* for CERT_DecodeAltNameExtension */ 30 31 #include "pki.h" 32 #include "pki3hack.h" 33 34 SEC_ASN1_MKSUB(CERT_TimeChoiceTemplate) 35 SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate) 36 SEC_ASN1_MKSUB(SEC_BitStringTemplate) 37 SEC_ASN1_MKSUB(SEC_IntegerTemplate) 38 SEC_ASN1_MKSUB(SEC_SkipTemplate) 39 40 /* 41 * Certificate database handling code 42 */ 43 44 const SEC_ASN1Template CERT_CertExtensionTemplate[] = { 45 { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CERTCertExtension) }, 46 { SEC_ASN1_OBJECT_ID, offsetof(CERTCertExtension, id) }, 47 { SEC_ASN1_OPTIONAL | SEC_ASN1_BOOLEAN, /* XXX DER_DEFAULT */ 48 offsetof(CERTCertExtension, critical) }, 49 { SEC_ASN1_OCTET_STRING, offsetof(CERTCertExtension, value) }, 50 { 0 } 51 }; 52 53 const SEC_ASN1Template CERT_SequenceOfCertExtensionTemplate[] = { 54 { SEC_ASN1_SEQUENCE_OF, 0, CERT_CertExtensionTemplate } 55 }; 56 57 const SEC_ASN1Template CERT_TimeChoiceTemplate[] = { 58 { SEC_ASN1_CHOICE, offsetof(SECItem, type), 0, sizeof(SECItem) }, 59 { SEC_ASN1_UTC_TIME, 0, 0, siUTCTime }, 60 { SEC_ASN1_GENERALIZED_TIME, 0, 0, siGeneralizedTime }, 61 { 0 } 62 }; 63 64 const SEC_ASN1Template CERT_ValidityTemplate[] = { 65 { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CERTValidity) }, 66 { SEC_ASN1_INLINE | SEC_ASN1_XTRN, offsetof(CERTValidity, notBefore), 67 SEC_ASN1_SUB(CERT_TimeChoiceTemplate), 0 }, 68 { SEC_ASN1_INLINE | SEC_ASN1_XTRN, offsetof(CERTValidity, notAfter), 69 SEC_ASN1_SUB(CERT_TimeChoiceTemplate), 0 }, 70 { 0 } 71 }; 72 73 const SEC_ASN1Template CERT_CertificateTemplate[] = { 74 { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CERTCertificate) }, 75 { SEC_ASN1_EXPLICIT | SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | 76 SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 0, /* XXX DER_DEFAULT */ 77 offsetof(CERTCertificate, version), 78 SEC_ASN1_SUB(SEC_IntegerTemplate) }, 79 { SEC_ASN1_INTEGER, offsetof(CERTCertificate, serialNumber) }, 80 { SEC_ASN1_INLINE | SEC_ASN1_XTRN, offsetof(CERTCertificate, signature), 81 SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) }, 82 { SEC_ASN1_SAVE, offsetof(CERTCertificate, derIssuer) }, 83 { SEC_ASN1_INLINE, offsetof(CERTCertificate, issuer), CERT_NameTemplate }, 84 { SEC_ASN1_INLINE, offsetof(CERTCertificate, validity), 85 CERT_ValidityTemplate }, 86 { SEC_ASN1_SAVE, offsetof(CERTCertificate, derSubject) }, 87 { SEC_ASN1_INLINE, offsetof(CERTCertificate, subject), CERT_NameTemplate }, 88 { SEC_ASN1_SAVE, offsetof(CERTCertificate, derPublicKey) }, 89 { SEC_ASN1_INLINE, offsetof(CERTCertificate, subjectPublicKeyInfo), 90 CERT_SubjectPublicKeyInfoTemplate }, 91 { SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 1, 92 offsetof(CERTCertificate, issuerID), 93 SEC_ASN1_SUB(SEC_BitStringTemplate) }, 94 { SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 2, 95 offsetof(CERTCertificate, subjectID), 96 SEC_ASN1_SUB(SEC_BitStringTemplate) }, 97 { SEC_ASN1_EXPLICIT | SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | 98 SEC_ASN1_CONTEXT_SPECIFIC | 3, 99 offsetof(CERTCertificate, extensions), 100 CERT_SequenceOfCertExtensionTemplate }, 101 { 0 } 102 }; 103 104 const SEC_ASN1Template SEC_SignedCertificateTemplate[] = { 105 { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CERTCertificate) }, 106 { SEC_ASN1_SAVE, offsetof(CERTCertificate, signatureWrap.data) }, 107 { SEC_ASN1_INLINE, 0, CERT_CertificateTemplate }, 108 { SEC_ASN1_INLINE | SEC_ASN1_XTRN, 109 offsetof(CERTCertificate, signatureWrap.signatureAlgorithm), 110 SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) }, 111 { SEC_ASN1_BIT_STRING, offsetof(CERTCertificate, signatureWrap.signature) }, 112 { 0 } 113 }; 114 115 /* 116 * Find the subjectName in a DER encoded certificate 117 */ 118 const SEC_ASN1Template SEC_CertSubjectTemplate[] = { 119 { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SECItem) }, 120 { SEC_ASN1_EXPLICIT | SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | 121 SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 0, 122 0, SEC_ASN1_SUB(SEC_SkipTemplate) }, /* version */ 123 { SEC_ASN1_SKIP }, /* serial number */ 124 { SEC_ASN1_SKIP }, /* signature algorithm */ 125 { SEC_ASN1_SKIP }, /* issuer */ 126 { SEC_ASN1_SKIP }, /* validity */ 127 { SEC_ASN1_ANY, 0, NULL }, /* subject */ 128 { SEC_ASN1_SKIP_REST }, 129 { 0 } 130 }; 131 132 /* 133 * Find the issuerName in a DER encoded certificate 134 */ 135 const SEC_ASN1Template SEC_CertIssuerTemplate[] = { 136 { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SECItem) }, 137 { SEC_ASN1_EXPLICIT | SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | 138 SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 0, 139 0, SEC_ASN1_SUB(SEC_SkipTemplate) }, /* version */ 140 { SEC_ASN1_SKIP }, /* serial number */ 141 { SEC_ASN1_SKIP }, /* signature algorithm */ 142 { SEC_ASN1_ANY, 0, NULL }, /* issuer */ 143 { SEC_ASN1_SKIP_REST }, 144 { 0 } 145 }; 146 /* 147 * Find the subjectName in a DER encoded certificate 148 */ 149 const SEC_ASN1Template SEC_CertSerialNumberTemplate[] = { 150 { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SECItem) }, 151 { SEC_ASN1_EXPLICIT | SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | 152 SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 0, 153 0, SEC_ASN1_SUB(SEC_SkipTemplate) }, /* version */ 154 { SEC_ASN1_ANY, 0, NULL }, /* serial number */ 155 { SEC_ASN1_SKIP_REST }, 156 { 0 } 157 }; 158 159 /* 160 * Find the issuer and serialNumber in a DER encoded certificate. 161 * This data is used as the database lookup key since its the unique 162 * identifier of a certificate. 163 */ 164 const SEC_ASN1Template CERT_CertKeyTemplate[] = { 165 { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CERTCertKey) }, 166 { SEC_ASN1_EXPLICIT | SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | 167 SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 0, 168 0, SEC_ASN1_SUB(SEC_SkipTemplate) }, /* version */ 169 { SEC_ASN1_INTEGER, offsetof(CERTCertKey, serialNumber) }, 170 { SEC_ASN1_SKIP }, /* signature algorithm */ 171 { SEC_ASN1_ANY, offsetof(CERTCertKey, derIssuer) }, 172 { SEC_ASN1_SKIP_REST }, 173 { 0 } 174 }; 175 176 SEC_ASN1_CHOOSER_IMPLEMENT(CERT_TimeChoiceTemplate) 177 SEC_ASN1_CHOOSER_IMPLEMENT(CERT_CertificateTemplate) 178 SEC_ASN1_CHOOSER_IMPLEMENT(SEC_SignedCertificateTemplate) 179 SEC_ASN1_CHOOSER_IMPLEMENT(CERT_SequenceOfCertExtensionTemplate) 180 181 SECStatus 182 CERT_KeyFromIssuerAndSN(PLArenaPool *arena, SECItem *issuer, SECItem *sn, 183 SECItem *key) 184 { 185 key->len = sn->len + issuer->len; 186 187 if ((sn->data == NULL) || (issuer->data == NULL)) { 188 goto loser; 189 } 190 191 key->data = (unsigned char *)PORT_ArenaAlloc(arena, key->len); 192 if (!key->data) { 193 goto loser; 194 } 195 196 /* copy the serialNumber */ 197 PORT_Memcpy(key->data, sn->data, sn->len); 198 199 /* copy the issuer */ 200 PORT_Memcpy(&key->data[sn->len], issuer->data, issuer->len); 201 202 return (SECSuccess); 203 204 loser: 205 return (SECFailure); 206 } 207 208 /* 209 * Extract the subject name from a DER certificate 210 */ 211 SECStatus 212 CERT_NameFromDERCert(SECItem *derCert, SECItem *derName) 213 { 214 int rv; 215 PLArenaPool *arena; 216 CERTSignedData sd; 217 void *tmpptr; 218 219 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 220 221 if (!arena) { 222 return (SECFailure); 223 } 224 225 PORT_Memset(&sd, 0, sizeof(CERTSignedData)); 226 rv = SEC_QuickDERDecodeItem(arena, &sd, CERT_SignedDataTemplate, derCert); 227 228 if (rv) { 229 goto loser; 230 } 231 232 PORT_Memset(derName, 0, sizeof(SECItem)); 233 rv = SEC_QuickDERDecodeItem(arena, derName, SEC_CertSubjectTemplate, 234 &sd.data); 235 236 if (rv) { 237 goto loser; 238 } 239 240 tmpptr = derName->data; 241 derName->data = (unsigned char *)PORT_Alloc(derName->len); 242 if (derName->data == NULL) { 243 goto loser; 244 } 245 246 PORT_Memcpy(derName->data, tmpptr, derName->len); 247 248 PORT_FreeArena(arena, PR_FALSE); 249 return (SECSuccess); 250 251 loser: 252 PORT_FreeArena(arena, PR_FALSE); 253 return (SECFailure); 254 } 255 256 SECStatus 257 CERT_IssuerNameFromDERCert(SECItem *derCert, SECItem *derName) 258 { 259 int rv; 260 PORTCheapArenaPool tmpArena; 261 CERTSignedData sd; 262 void *tmpptr; 263 264 PORT_InitCheapArena(&tmpArena, DER_DEFAULT_CHUNKSIZE); 265 266 PORT_Memset(&sd, 0, sizeof(CERTSignedData)); 267 rv = SEC_QuickDERDecodeItem(&tmpArena.arena, &sd, CERT_SignedDataTemplate, 268 derCert); 269 if (rv) { 270 goto loser; 271 } 272 273 PORT_Memset(derName, 0, sizeof(SECItem)); 274 rv = SEC_QuickDERDecodeItem(&tmpArena.arena, derName, 275 SEC_CertIssuerTemplate, &sd.data); 276 if (rv) { 277 goto loser; 278 } 279 280 tmpptr = derName->data; 281 derName->data = (unsigned char *)PORT_Alloc(derName->len); 282 if (derName->data == NULL) { 283 goto loser; 284 } 285 286 PORT_Memcpy(derName->data, tmpptr, derName->len); 287 288 PORT_DestroyCheapArena(&tmpArena); 289 return (SECSuccess); 290 291 loser: 292 PORT_DestroyCheapArena(&tmpArena); 293 return (SECFailure); 294 } 295 296 SECStatus 297 CERT_SerialNumberFromDERCert(SECItem *derCert, SECItem *derName) 298 { 299 int rv; 300 PORTCheapArenaPool tmpArena; 301 CERTSignedData sd; 302 void *tmpptr; 303 304 PORT_InitCheapArena(&tmpArena, DER_DEFAULT_CHUNKSIZE); 305 306 PORT_Memset(&sd, 0, sizeof(CERTSignedData)); 307 rv = SEC_QuickDERDecodeItem(&tmpArena.arena, &sd, CERT_SignedDataTemplate, 308 derCert); 309 if (rv) { 310 goto loser; 311 } 312 313 PORT_Memset(derName, 0, sizeof(SECItem)); 314 rv = SEC_QuickDERDecodeItem(&tmpArena.arena, derName, 315 SEC_CertSerialNumberTemplate, &sd.data); 316 if (rv) { 317 goto loser; 318 } 319 320 tmpptr = derName->data; 321 derName->data = (unsigned char *)PORT_Alloc(derName->len); 322 if (derName->data == NULL) { 323 goto loser; 324 } 325 326 PORT_Memcpy(derName->data, tmpptr, derName->len); 327 328 PORT_DestroyCheapArena(&tmpArena); 329 return (SECSuccess); 330 331 loser: 332 PORT_DestroyCheapArena(&tmpArena); 333 return (SECFailure); 334 } 335 336 /* 337 * Generate a database key, based on serial number and issuer, from a 338 * DER certificate. 339 */ 340 SECStatus 341 CERT_KeyFromDERCert(PLArenaPool *reqArena, SECItem *derCert, SECItem *key) 342 { 343 int rv; 344 CERTSignedData sd; 345 CERTCertKey certkey; 346 347 if (!reqArena) { 348 PORT_SetError(SEC_ERROR_INVALID_ARGS); 349 return SECFailure; 350 } 351 352 PORT_Memset(&sd, 0, sizeof(CERTSignedData)); 353 rv = 354 SEC_QuickDERDecodeItem(reqArena, &sd, CERT_SignedDataTemplate, derCert); 355 356 if (rv) { 357 goto loser; 358 } 359 360 PORT_Memset(&certkey, 0, sizeof(CERTCertKey)); 361 rv = SEC_QuickDERDecodeItem(reqArena, &certkey, CERT_CertKeyTemplate, 362 &sd.data); 363 364 if (rv) { 365 goto loser; 366 } 367 368 return (CERT_KeyFromIssuerAndSN(reqArena, &certkey.derIssuer, 369 &certkey.serialNumber, key)); 370 loser: 371 return (SECFailure); 372 } 373 374 /* 375 * fill in keyUsage field of the cert based on the cert extension 376 * if the extension is not critical, then we allow all uses 377 */ 378 static SECStatus 379 GetKeyUsage(CERTCertificate *cert) 380 { 381 SECStatus rv; 382 SECItem tmpitem; 383 384 rv = CERT_FindKeyUsageExtension(cert, &tmpitem); 385 if (rv == SECSuccess) { 386 /* remember the actual value of the extension */ 387 cert->rawKeyUsage = tmpitem.len ? tmpitem.data[0] : 0; 388 cert->keyUsagePresent = PR_TRUE; 389 cert->keyUsage = cert->rawKeyUsage; 390 391 PORT_Free(tmpitem.data); 392 tmpitem.data = NULL; 393 } else { 394 /* if the extension is not present, then we allow all uses */ 395 cert->keyUsage = KU_ALL; 396 cert->rawKeyUsage = KU_ALL; 397 cert->keyUsagePresent = PR_FALSE; 398 } 399 400 if (CERT_GovtApprovedBitSet(cert)) { 401 cert->keyUsage |= KU_NS_GOVT_APPROVED; 402 cert->rawKeyUsage |= KU_NS_GOVT_APPROVED; 403 } 404 405 return (SECSuccess); 406 } 407 408 static SECStatus 409 findOIDinOIDSeqByTagNum(CERTOidSequence *seq, SECOidTag tagnum) 410 { 411 SECItem **oids; 412 SECItem *oid; 413 SECStatus rv = SECFailure; 414 415 if (seq != NULL) { 416 oids = seq->oids; 417 while (oids != NULL && *oids != NULL) { 418 oid = *oids; 419 if (SECOID_FindOIDTag(oid) == tagnum) { 420 rv = SECSuccess; 421 break; 422 } 423 oids++; 424 } 425 } 426 return rv; 427 } 428 429 /* 430 * fill in nsCertType field of the cert based on the cert extension 431 */ 432 SECStatus 433 cert_GetCertType(CERTCertificate *cert) 434 { 435 PRUint32 nsCertType; 436 437 if (cert->nsCertType) { 438 /* once set, no need to recalculate */ 439 return SECSuccess; 440 } 441 nsCertType = cert_ComputeCertType(cert); 442 443 /* Assert that it is safe to cast &cert->nsCertType to "PRInt32 *" */ 444 PORT_Assert(sizeof(cert->nsCertType) == sizeof(PRInt32)); 445 PR_ATOMIC_SET((PRInt32 *)&cert->nsCertType, nsCertType); 446 return SECSuccess; 447 } 448 449 PRBool 450 cert_IsIPsecOID(CERTOidSequence *extKeyUsage) 451 { 452 if (findOIDinOIDSeqByTagNum( 453 extKeyUsage, SEC_OID_EXT_KEY_USAGE_IPSEC_IKE) == SECSuccess) { 454 return PR_TRUE; 455 } 456 if (findOIDinOIDSeqByTagNum( 457 extKeyUsage, SEC_OID_IPSEC_IKE_END) == SECSuccess) { 458 return PR_TRUE; 459 } 460 if (findOIDinOIDSeqByTagNum( 461 extKeyUsage, SEC_OID_IPSEC_IKE_INTERMEDIATE) == SECSuccess) { 462 return PR_TRUE; 463 } 464 /* these are now deprecated, but may show up. Treat them the same as IKE */ 465 if (findOIDinOIDSeqByTagNum( 466 extKeyUsage, SEC_OID_EXT_KEY_USAGE_IPSEC_END) == SECSuccess) { 467 return PR_TRUE; 468 } 469 if (findOIDinOIDSeqByTagNum( 470 extKeyUsage, SEC_OID_EXT_KEY_USAGE_IPSEC_TUNNEL) == SECSuccess) { 471 return PR_TRUE; 472 } 473 if (findOIDinOIDSeqByTagNum( 474 extKeyUsage, SEC_OID_EXT_KEY_USAGE_IPSEC_USER) == SECSuccess) { 475 return PR_TRUE; 476 } 477 /* this one should probably be in cert_ComputeCertType and set all usages? */ 478 if (findOIDinOIDSeqByTagNum( 479 extKeyUsage, SEC_OID_X509_ANY_EXT_KEY_USAGE) == SECSuccess) { 480 return PR_TRUE; 481 } 482 return PR_FALSE; 483 } 484 485 PRUint32 486 cert_ComputeCertType(CERTCertificate *cert) 487 { 488 SECStatus rv; 489 SECItem tmpitem; 490 SECItem encodedExtKeyUsage; 491 CERTOidSequence *extKeyUsage = NULL; 492 CERTBasicConstraints basicConstraint; 493 PRUint32 nsCertType = 0; 494 PRBool isCA = PR_FALSE; 495 496 tmpitem.data = NULL; 497 CERT_FindNSCertTypeExtension(cert, &tmpitem); 498 encodedExtKeyUsage.data = NULL; 499 rv = CERT_FindCertExtension(cert, SEC_OID_X509_EXT_KEY_USAGE, 500 &encodedExtKeyUsage); 501 if (rv == SECSuccess) { 502 extKeyUsage = CERT_DecodeOidSequence(&encodedExtKeyUsage); 503 } 504 rv = CERT_FindBasicConstraintExten(cert, &basicConstraint); 505 if (rv == SECSuccess) { 506 isCA = basicConstraint.isCA; 507 } 508 if (tmpitem.data != NULL || extKeyUsage != NULL) { 509 if (tmpitem.data == NULL || tmpitem.len == 0) { 510 nsCertType = 0; 511 } else { 512 nsCertType = tmpitem.data[0]; 513 } 514 515 /* free tmpitem data pointer to avoid memory leak */ 516 PORT_Free(tmpitem.data); 517 tmpitem.data = NULL; 518 519 /* 520 * for this release, we will allow SSL certs with an email address 521 * to be used for email 522 */ 523 if ((nsCertType & NS_CERT_TYPE_SSL_CLIENT) && cert->emailAddr && 524 cert->emailAddr[0]) { 525 nsCertType |= NS_CERT_TYPE_EMAIL; 526 } 527 /* 528 * for this release, we will allow SSL intermediate CAs to be 529 * email intermediate CAs too. 530 */ 531 if (nsCertType & NS_CERT_TYPE_SSL_CA) { 532 nsCertType |= NS_CERT_TYPE_EMAIL_CA; 533 } 534 /* 535 * allow a cert with the extended key usage of EMail Protect 536 * to be used for email or as an email CA, if basic constraints 537 * indicates that it is a CA. 538 */ 539 if (findOIDinOIDSeqByTagNum(extKeyUsage, 540 SEC_OID_EXT_KEY_USAGE_EMAIL_PROTECT) == 541 SECSuccess) { 542 nsCertType |= isCA ? NS_CERT_TYPE_EMAIL_CA : NS_CERT_TYPE_EMAIL; 543 } 544 if (findOIDinOIDSeqByTagNum( 545 extKeyUsage, SEC_OID_EXT_KEY_USAGE_SERVER_AUTH) == SECSuccess) { 546 nsCertType |= isCA ? NS_CERT_TYPE_SSL_CA : NS_CERT_TYPE_SSL_SERVER; 547 } 548 /* 549 * Treat certs with step-up OID as also having SSL server type. 550 * COMODO needs this behaviour until June 2020. See Bug 737802. 551 */ 552 if (findOIDinOIDSeqByTagNum(extKeyUsage, 553 SEC_OID_NS_KEY_USAGE_GOVT_APPROVED) == 554 SECSuccess) { 555 nsCertType |= isCA ? NS_CERT_TYPE_SSL_CA : NS_CERT_TYPE_SSL_SERVER; 556 } 557 if (findOIDinOIDSeqByTagNum( 558 extKeyUsage, SEC_OID_EXT_KEY_USAGE_CLIENT_AUTH) == SECSuccess) { 559 nsCertType |= isCA ? NS_CERT_TYPE_SSL_CA : NS_CERT_TYPE_SSL_CLIENT; 560 } 561 if (cert_IsIPsecOID(extKeyUsage)) { 562 nsCertType |= isCA ? NS_CERT_TYPE_IPSEC_CA : NS_CERT_TYPE_IPSEC; 563 } 564 if (findOIDinOIDSeqByTagNum( 565 extKeyUsage, SEC_OID_EXT_KEY_USAGE_CODE_SIGN) == SECSuccess) { 566 nsCertType |= isCA ? NS_CERT_TYPE_OBJECT_SIGNING_CA : NS_CERT_TYPE_OBJECT_SIGNING; 567 } 568 if (findOIDinOIDSeqByTagNum( 569 extKeyUsage, SEC_OID_EXT_KEY_USAGE_TIME_STAMP) == SECSuccess) { 570 nsCertType |= EXT_KEY_USAGE_TIME_STAMP; 571 } 572 if (findOIDinOIDSeqByTagNum(extKeyUsage, SEC_OID_OCSP_RESPONDER) == 573 SECSuccess) { 574 nsCertType |= EXT_KEY_USAGE_STATUS_RESPONDER; 575 } 576 } else { 577 /* If no NS Cert Type extension and no EKU extension, then */ 578 nsCertType = 0; 579 if (CERT_IsCACert(cert, &nsCertType)) 580 nsCertType |= EXT_KEY_USAGE_STATUS_RESPONDER; 581 /* if the basic constraint extension says the cert is a CA, then 582 allow SSL CA and EMAIL CA and Status Responder */ 583 if (isCA) { 584 nsCertType |= (NS_CERT_TYPE_SSL_CA | NS_CERT_TYPE_EMAIL_CA | 585 EXT_KEY_USAGE_STATUS_RESPONDER); 586 } 587 /* allow any ssl or email (no ca or object signing. */ 588 nsCertType |= NS_CERT_TYPE_SSL_CLIENT | NS_CERT_TYPE_SSL_SERVER | 589 NS_CERT_TYPE_EMAIL; 590 } 591 592 /* IPSEC is allowed to use SSL client and server certs as well as email certs */ 593 if (nsCertType & (NS_CERT_TYPE_SSL_CLIENT | NS_CERT_TYPE_SSL_SERVER | NS_CERT_TYPE_EMAIL)) { 594 nsCertType |= NS_CERT_TYPE_IPSEC; 595 } 596 if (nsCertType & (NS_CERT_TYPE_SSL_CA | NS_CERT_TYPE_EMAIL_CA)) { 597 nsCertType |= NS_CERT_TYPE_IPSEC_CA; 598 } 599 600 if (encodedExtKeyUsage.data != NULL) { 601 PORT_Free(encodedExtKeyUsage.data); 602 } 603 if (extKeyUsage != NULL) { 604 CERT_DestroyOidSequence(extKeyUsage); 605 } 606 return nsCertType; 607 } 608 609 /* 610 * cert_GetKeyID() - extract or generate the subjectKeyID from a certificate 611 */ 612 SECStatus 613 cert_GetKeyID(CERTCertificate *cert) 614 { 615 SECItem tmpitem; 616 SECStatus rv; 617 618 cert->subjectKeyID.len = 0; 619 620 /* see of the cert has a key identifier extension */ 621 rv = CERT_FindSubjectKeyIDExtension(cert, &tmpitem); 622 if (rv == SECSuccess) { 623 cert->subjectKeyID.data = 624 (unsigned char *)PORT_ArenaAlloc(cert->arena, tmpitem.len); 625 if (cert->subjectKeyID.data != NULL) { 626 PORT_Memcpy(cert->subjectKeyID.data, tmpitem.data, tmpitem.len); 627 cert->subjectKeyID.len = tmpitem.len; 628 cert->keyIDGenerated = PR_FALSE; 629 } 630 631 PORT_Free(tmpitem.data); 632 } 633 634 /* if the cert doesn't have a key identifier extension, then generate one*/ 635 if (cert->subjectKeyID.len == 0) { 636 /* 637 * pkix says that if the subjectKeyID is not present, then we should 638 * use the SHA-1 hash of the DER-encoded publicKeyInfo from the cert 639 */ 640 cert->subjectKeyID.data = 641 (unsigned char *)PORT_ArenaAlloc(cert->arena, SHA1_LENGTH); 642 if (cert->subjectKeyID.data != NULL) { 643 rv = PK11_HashBuf(SEC_OID_SHA1, cert->subjectKeyID.data, 644 cert->derPublicKey.data, cert->derPublicKey.len); 645 if (rv == SECSuccess) { 646 cert->subjectKeyID.len = SHA1_LENGTH; 647 } 648 } 649 } 650 651 if (cert->subjectKeyID.len == 0) { 652 return (SECFailure); 653 } 654 return (SECSuccess); 655 } 656 657 static PRBool 658 cert_IsRootCert(CERTCertificate *cert) 659 { 660 SECStatus rv; 661 SECItem tmpitem; 662 663 /* cache the authKeyID extension, if present */ 664 cert->authKeyID = CERT_FindAuthKeyIDExten(cert->arena, cert); 665 666 /* it MUST be self-issued to be a root */ 667 if (cert->derIssuer.len == 0 || 668 !SECITEM_ItemsAreEqual(&cert->derIssuer, &cert->derSubject)) { 669 return PR_FALSE; 670 } 671 672 /* check the authKeyID extension */ 673 if (cert->authKeyID) { 674 /* authority key identifier is present */ 675 if (cert->authKeyID->keyID.len > 0) { 676 /* the keyIdentifier field is set, look for subjectKeyID */ 677 rv = CERT_FindSubjectKeyIDExtension(cert, &tmpitem); 678 if (rv == SECSuccess) { 679 PRBool match; 680 /* also present, they MUST match for it to be a root */ 681 match = 682 SECITEM_ItemsAreEqual(&cert->authKeyID->keyID, &tmpitem); 683 PORT_Free(tmpitem.data); 684 if (!match) 685 return PR_FALSE; /* else fall through */ 686 } else { 687 /* the subject key ID is required when AKI is present */ 688 return PR_FALSE; 689 } 690 } 691 if (cert->authKeyID->authCertIssuer) { 692 SECItem *caName; 693 caName = (SECItem *)CERT_GetGeneralNameByType( 694 cert->authKeyID->authCertIssuer, certDirectoryName, PR_TRUE); 695 if (caName) { 696 if (!SECITEM_ItemsAreEqual(&cert->derIssuer, caName)) { 697 return PR_FALSE; 698 } /* else fall through */ 699 } /* else ??? could not get general name as directory name? */ 700 } 701 if (cert->authKeyID->authCertSerialNumber.len > 0) { 702 if (!SECITEM_ItemsAreEqual( 703 &cert->serialNumber, 704 &cert->authKeyID->authCertSerialNumber)) { 705 return PR_FALSE; 706 } /* else fall through */ 707 } 708 /* all of the AKI fields that were present passed the test */ 709 return PR_TRUE; 710 } 711 /* else the AKI was not present, so this is a root */ 712 return PR_TRUE; 713 } 714 715 /* 716 * take a DER certificate and decode it into a certificate structure 717 */ 718 CERTCertificate * 719 CERT_DecodeDERCertificate(SECItem *derSignedCert, PRBool copyDER, 720 char *nickname) 721 { 722 CERTCertificate *cert; 723 PLArenaPool *arena; 724 void *data; 725 int rv; 726 int len; 727 char *tmpname; 728 729 /* make a new arena */ 730 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 731 732 if (!arena) { 733 return 0; 734 } 735 736 /* allocate the certificate structure */ 737 cert = (CERTCertificate *)PORT_ArenaZAlloc(arena, sizeof(CERTCertificate)); 738 739 if (!cert) { 740 goto loser; 741 } 742 743 cert->arena = arena; 744 745 if (copyDER) { 746 /* copy the DER data for the cert into this arena */ 747 data = (void *)PORT_ArenaAlloc(arena, derSignedCert->len); 748 if (!data) { 749 goto loser; 750 } 751 cert->derCert.data = (unsigned char *)data; 752 cert->derCert.len = derSignedCert->len; 753 PORT_Memcpy(data, derSignedCert->data, derSignedCert->len); 754 } else { 755 /* point to passed in DER data */ 756 cert->derCert = *derSignedCert; 757 } 758 759 /* decode the certificate info */ 760 rv = SEC_QuickDERDecodeItem(arena, cert, SEC_SignedCertificateTemplate, 761 &cert->derCert); 762 763 if (rv) { 764 goto loser; 765 } 766 767 if (cert_HasUnknownCriticalExten(cert->extensions) == PR_TRUE) { 768 cert->options.bits.hasUnsupportedCriticalExt = PR_TRUE; 769 } 770 771 /* generate and save the database key for the cert */ 772 rv = CERT_KeyFromIssuerAndSN(arena, &cert->derIssuer, &cert->serialNumber, 773 &cert->certKey); 774 if (rv) { 775 goto loser; 776 } 777 778 /* set the nickname */ 779 if (nickname == NULL) { 780 cert->nickname = NULL; 781 } else { 782 /* copy and install the nickname */ 783 len = PORT_Strlen(nickname) + 1; 784 cert->nickname = (char *)PORT_ArenaAlloc(arena, len); 785 if (cert->nickname == NULL) { 786 goto loser; 787 } 788 789 PORT_Memcpy(cert->nickname, nickname, len); 790 } 791 792 /* set the email address */ 793 cert->emailAddr = cert_GetCertificateEmailAddresses(cert); 794 795 /* initialize the subjectKeyID */ 796 rv = cert_GetKeyID(cert); 797 if (rv != SECSuccess) { 798 goto loser; 799 } 800 801 /* initialize keyUsage */ 802 rv = GetKeyUsage(cert); 803 if (rv != SECSuccess) { 804 goto loser; 805 } 806 807 /* determine if this is a root cert */ 808 cert->isRoot = cert_IsRootCert(cert); 809 810 /* initialize the certType */ 811 rv = cert_GetCertType(cert); 812 if (rv != SECSuccess) { 813 goto loser; 814 } 815 816 tmpname = CERT_NameToAscii(&cert->subject); 817 if (tmpname != NULL) { 818 cert->subjectName = PORT_ArenaStrdup(cert->arena, tmpname); 819 PORT_Free(tmpname); 820 } 821 822 tmpname = CERT_NameToAscii(&cert->issuer); 823 if (tmpname != NULL) { 824 cert->issuerName = PORT_ArenaStrdup(cert->arena, tmpname); 825 PORT_Free(tmpname); 826 } 827 828 cert->referenceCount = 1; 829 cert->slot = NULL; 830 cert->pkcs11ID = CK_INVALID_HANDLE; 831 cert->dbnickname = NULL; 832 833 return (cert); 834 835 loser: 836 837 if (arena) { 838 PORT_FreeArena(arena, PR_FALSE); 839 } 840 841 return (0); 842 } 843 844 CERTCertificate * 845 __CERT_DecodeDERCertificate(SECItem *derSignedCert, PRBool copyDER, 846 char *nickname) 847 { 848 return CERT_DecodeDERCertificate(derSignedCert, copyDER, nickname); 849 } 850 851 CERTValidity * 852 CERT_CreateValidity(PRTime notBefore, PRTime notAfter) 853 { 854 CERTValidity *v; 855 int rv; 856 PLArenaPool *arena; 857 858 if (notBefore > notAfter) { 859 PORT_SetError(SEC_ERROR_INVALID_ARGS); 860 return NULL; 861 } 862 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 863 864 if (!arena) { 865 return (0); 866 } 867 868 v = (CERTValidity *)PORT_ArenaZAlloc(arena, sizeof(CERTValidity)); 869 if (v) { 870 v->arena = arena; 871 rv = DER_EncodeTimeChoice(arena, &v->notBefore, notBefore); 872 if (rv) 873 goto loser; 874 rv = DER_EncodeTimeChoice(arena, &v->notAfter, notAfter); 875 if (rv) 876 goto loser; 877 } 878 return v; 879 880 loser: 881 CERT_DestroyValidity(v); 882 return 0; 883 } 884 885 SECStatus 886 CERT_CopyValidity(PLArenaPool *arena, CERTValidity *to, CERTValidity *from) 887 { 888 SECStatus rv; 889 890 CERT_DestroyValidity(to); 891 to->arena = arena; 892 893 rv = SECITEM_CopyItem(arena, &to->notBefore, &from->notBefore); 894 if (rv) 895 return rv; 896 rv = SECITEM_CopyItem(arena, &to->notAfter, &from->notAfter); 897 return rv; 898 } 899 900 void 901 CERT_DestroyValidity(CERTValidity *v) 902 { 903 if (v && v->arena) { 904 PORT_FreeArena(v->arena, PR_FALSE); 905 } 906 return; 907 } 908 909 /* 910 ** Amount of time that a certifiate is allowed good before it is actually 911 ** good. This is used for pending certificates, ones that are about to be 912 ** valid. The slop is designed to allow for some variance in the clocks 913 ** of the machine checking the certificate. 914 */ 915 #define PENDING_SLOP (24L * 60L * 60L) /* seconds per day */ 916 static PRInt32 pendingSlop = PENDING_SLOP; /* seconds */ 917 918 PRInt32 919 CERT_GetSlopTime(void) 920 { 921 return pendingSlop; /* seconds */ 922 } 923 924 SECStatus 925 CERT_SetSlopTime(PRInt32 slop) /* seconds */ 926 { 927 if (slop < 0) 928 return SECFailure; 929 pendingSlop = slop; 930 return SECSuccess; 931 } 932 933 SECStatus 934 CERT_GetCertTimes(const CERTCertificate *c, PRTime *notBefore, PRTime *notAfter) 935 { 936 SECStatus rv; 937 938 if (!c || !notBefore || !notAfter) { 939 PORT_SetError(SEC_ERROR_INVALID_ARGS); 940 return SECFailure; 941 } 942 943 /* convert DER not-before time */ 944 rv = DER_DecodeTimeChoice(notBefore, &c->validity.notBefore); 945 if (rv) { 946 return (SECFailure); 947 } 948 949 /* convert DER not-after time */ 950 rv = DER_DecodeTimeChoice(notAfter, &c->validity.notAfter); 951 if (rv) { 952 return (SECFailure); 953 } 954 955 return (SECSuccess); 956 } 957 958 /* 959 * Check the validity times of a certificate 960 */ 961 SECCertTimeValidity 962 CERT_CheckCertValidTimes(const CERTCertificate *c, PRTime t, 963 PRBool allowOverride) 964 { 965 PRTime notBefore, notAfter, llPendingSlop, tmp1; 966 SECStatus rv; 967 968 if (!c) { 969 PORT_SetError(SEC_ERROR_INVALID_ARGS); 970 return (secCertTimeUndetermined); 971 } 972 /* if cert is already marked OK, then don't bother to check */ 973 if (allowOverride && c->timeOK) { 974 return (secCertTimeValid); 975 } 976 977 rv = CERT_GetCertTimes(c, ¬Before, ¬After); 978 979 if (rv) { 980 return (secCertTimeExpired); /*XXX is this the right thing to do here?*/ 981 } 982 983 LL_I2L(llPendingSlop, pendingSlop); 984 /* convert to micro seconds */ 985 LL_UI2L(tmp1, PR_USEC_PER_SEC); 986 LL_MUL(llPendingSlop, llPendingSlop, tmp1); 987 LL_SUB(notBefore, notBefore, llPendingSlop); 988 if (LL_CMP(t, <, notBefore)) { 989 PORT_SetError(SEC_ERROR_EXPIRED_CERTIFICATE); 990 return (secCertTimeNotValidYet); 991 } 992 if (LL_CMP(t, >, notAfter)) { 993 PORT_SetError(SEC_ERROR_EXPIRED_CERTIFICATE); 994 return (secCertTimeExpired); 995 } 996 997 return (secCertTimeValid); 998 } 999 1000 SECStatus 1001 SEC_GetCrlTimes(CERTCrl *date, PRTime *notBefore, PRTime *notAfter) 1002 { 1003 int rv; 1004 1005 /* convert DER not-before time */ 1006 rv = DER_DecodeTimeChoice(notBefore, &date->lastUpdate); 1007 if (rv) { 1008 return (SECFailure); 1009 } 1010 1011 /* convert DER not-after time */ 1012 if (date->nextUpdate.data) { 1013 rv = DER_DecodeTimeChoice(notAfter, &date->nextUpdate); 1014 if (rv) { 1015 return (SECFailure); 1016 } 1017 } else { 1018 LL_I2L(*notAfter, 0L); 1019 } 1020 return (SECSuccess); 1021 } 1022 1023 /* These routines should probably be combined with the cert 1024 * routines using an common extraction routine. 1025 */ 1026 SECCertTimeValidity 1027 SEC_CheckCrlTimes(CERTCrl *crl, PRTime t) 1028 { 1029 PRTime notBefore, notAfter, llPendingSlop, tmp1; 1030 SECStatus rv; 1031 1032 if (!crl) { 1033 PORT_SetError(SEC_ERROR_INVALID_ARGS); 1034 return (secCertTimeUndetermined); 1035 } 1036 1037 rv = SEC_GetCrlTimes(crl, ¬Before, ¬After); 1038 1039 if (rv) { 1040 return (secCertTimeExpired); 1041 } 1042 1043 LL_I2L(llPendingSlop, pendingSlop); 1044 /* convert to micro seconds */ 1045 LL_I2L(tmp1, PR_USEC_PER_SEC); 1046 LL_MUL(llPendingSlop, llPendingSlop, tmp1); 1047 LL_SUB(notBefore, notBefore, llPendingSlop); 1048 if (LL_CMP(t, <, notBefore)) { 1049 PORT_SetError(SEC_ERROR_CRL_EXPIRED); 1050 return (secCertTimeNotValidYet); 1051 } 1052 1053 /* If next update is omitted and the test for notBefore passes, then 1054 we assume that the crl is up to date. 1055 */ 1056 if (LL_IS_ZERO(notAfter)) { 1057 return (secCertTimeValid); 1058 } 1059 1060 if (LL_CMP(t, >, notAfter)) { 1061 PORT_SetError(SEC_ERROR_CRL_EXPIRED); 1062 return (secCertTimeExpired); 1063 } 1064 1065 return (secCertTimeValid); 1066 } 1067 1068 PRBool 1069 SEC_CrlIsNewer(CERTCrl *inNew, CERTCrl *old) 1070 { 1071 PRTime newNotBefore, newNotAfter; 1072 PRTime oldNotBefore, oldNotAfter; 1073 SECStatus rv; 1074 1075 /* problems with the new CRL? reject it */ 1076 rv = SEC_GetCrlTimes(inNew, &newNotBefore, &newNotAfter); 1077 if (rv) 1078 return PR_FALSE; 1079 1080 /* problems with the old CRL? replace it */ 1081 rv = SEC_GetCrlTimes(old, &oldNotBefore, &oldNotAfter); 1082 if (rv) 1083 return PR_TRUE; 1084 1085 /* Question: what about the notAfter's? */ 1086 return ((PRBool)LL_CMP(oldNotBefore, <, newNotBefore)); 1087 } 1088 1089 /* 1090 * return required key usage and cert type based on cert usage 1091 */ 1092 SECStatus 1093 CERT_KeyUsageAndTypeForCertUsage(SECCertUsage usage, PRBool ca, 1094 unsigned int *retKeyUsage, 1095 unsigned int *retCertType) 1096 { 1097 unsigned int requiredKeyUsage = 0; 1098 unsigned int requiredCertType = 0; 1099 1100 if (ca) { 1101 switch (usage) { 1102 case certUsageSSLServerWithStepUp: 1103 requiredKeyUsage = KU_NS_GOVT_APPROVED | KU_KEY_CERT_SIGN; 1104 requiredCertType = NS_CERT_TYPE_SSL_CA; 1105 break; 1106 case certUsageSSLClient: 1107 requiredKeyUsage = KU_KEY_CERT_SIGN; 1108 requiredCertType = NS_CERT_TYPE_SSL_CA; 1109 break; 1110 case certUsageSSLServer: 1111 requiredKeyUsage = KU_KEY_CERT_SIGN; 1112 requiredCertType = NS_CERT_TYPE_SSL_CA; 1113 break; 1114 case certUsageIPsec: 1115 requiredKeyUsage = KU_KEY_CERT_SIGN; 1116 requiredCertType = NS_CERT_TYPE_IPSEC_CA; 1117 break; 1118 case certUsageSSLCA: 1119 requiredKeyUsage = KU_KEY_CERT_SIGN; 1120 requiredCertType = NS_CERT_TYPE_SSL_CA; 1121 break; 1122 case certUsageEmailSigner: 1123 requiredKeyUsage = KU_KEY_CERT_SIGN; 1124 requiredCertType = NS_CERT_TYPE_EMAIL_CA; 1125 break; 1126 case certUsageEmailRecipient: 1127 requiredKeyUsage = KU_KEY_CERT_SIGN; 1128 requiredCertType = NS_CERT_TYPE_EMAIL_CA; 1129 break; 1130 case certUsageObjectSigner: 1131 requiredKeyUsage = KU_KEY_CERT_SIGN; 1132 requiredCertType = NS_CERT_TYPE_OBJECT_SIGNING_CA; 1133 break; 1134 case certUsageAnyCA: 1135 case certUsageVerifyCA: 1136 case certUsageStatusResponder: 1137 requiredKeyUsage = KU_KEY_CERT_SIGN; 1138 requiredCertType = NS_CERT_TYPE_OBJECT_SIGNING_CA | 1139 NS_CERT_TYPE_EMAIL_CA | NS_CERT_TYPE_SSL_CA; 1140 break; 1141 default: 1142 PORT_Assert(0); 1143 goto loser; 1144 } 1145 } else { 1146 switch (usage) { 1147 case certUsageSSLClient: 1148 /* 1149 * RFC 5280 lists digitalSignature and keyAgreement for 1150 * id-kp-clientAuth. NSS does not support the *_fixed_dh and 1151 * *_fixed_ecdh client certificate types. 1152 */ 1153 requiredKeyUsage = KU_DIGITAL_SIGNATURE; 1154 requiredCertType = NS_CERT_TYPE_SSL_CLIENT; 1155 break; 1156 case certUsageSSLServer: 1157 requiredKeyUsage = KU_KEY_AGREEMENT_OR_ENCIPHERMENT; 1158 requiredCertType = NS_CERT_TYPE_SSL_SERVER; 1159 break; 1160 case certUsageIPsec: 1161 /* RFC 4945 Section 5.1.3.2 */ 1162 requiredKeyUsage = KU_DIGITAL_SIGNATURE_OR_NON_REPUDIATION; 1163 requiredCertType = NS_CERT_TYPE_IPSEC; 1164 break; 1165 case certUsageSSLServerWithStepUp: 1166 requiredKeyUsage = 1167 KU_KEY_AGREEMENT_OR_ENCIPHERMENT | KU_NS_GOVT_APPROVED; 1168 requiredCertType = NS_CERT_TYPE_SSL_SERVER; 1169 break; 1170 case certUsageSSLCA: 1171 requiredKeyUsage = KU_KEY_CERT_SIGN; 1172 requiredCertType = NS_CERT_TYPE_SSL_CA; 1173 break; 1174 case certUsageEmailSigner: 1175 requiredKeyUsage = KU_DIGITAL_SIGNATURE_OR_NON_REPUDIATION; 1176 requiredCertType = NS_CERT_TYPE_EMAIL; 1177 break; 1178 case certUsageEmailRecipient: 1179 requiredKeyUsage = KU_KEY_AGREEMENT_OR_ENCIPHERMENT; 1180 requiredCertType = NS_CERT_TYPE_EMAIL; 1181 break; 1182 case certUsageObjectSigner: 1183 /* RFC 5280 lists only digitalSignature for id-kp-codeSigning. 1184 */ 1185 requiredKeyUsage = KU_DIGITAL_SIGNATURE; 1186 requiredCertType = NS_CERT_TYPE_OBJECT_SIGNING; 1187 break; 1188 case certUsageStatusResponder: 1189 requiredKeyUsage = KU_DIGITAL_SIGNATURE_OR_NON_REPUDIATION; 1190 requiredCertType = EXT_KEY_USAGE_STATUS_RESPONDER; 1191 break; 1192 default: 1193 PORT_Assert(0); 1194 goto loser; 1195 } 1196 } 1197 1198 if (retKeyUsage != NULL) { 1199 *retKeyUsage = requiredKeyUsage; 1200 } 1201 if (retCertType != NULL) { 1202 *retCertType = requiredCertType; 1203 } 1204 1205 return (SECSuccess); 1206 loser: 1207 return (SECFailure); 1208 } 1209 1210 /* 1211 * check the key usage of a cert against a set of required values 1212 */ 1213 SECStatus 1214 CERT_CheckKeyUsage(CERTCertificate *cert, unsigned int requiredUsage) 1215 { 1216 if (!cert) { 1217 PORT_SetError(SEC_ERROR_INVALID_ARGS); 1218 return SECFailure; 1219 } 1220 /* choose between key agreement or key encipherment based on key 1221 * type in cert 1222 */ 1223 if (requiredUsage & KU_KEY_AGREEMENT_OR_ENCIPHERMENT) { 1224 KeyType keyType = CERT_GetCertKeyType(&cert->subjectPublicKeyInfo); 1225 /* turn off the special bit */ 1226 requiredUsage &= (~KU_KEY_AGREEMENT_OR_ENCIPHERMENT); 1227 1228 switch (keyType) { 1229 case rsaKey: 1230 requiredUsage |= KU_KEY_ENCIPHERMENT; 1231 break; 1232 case rsaPssKey: 1233 case dsaKey: 1234 case mldsaKey: 1235 requiredUsage |= KU_DIGITAL_SIGNATURE; 1236 break; 1237 case dhKey: 1238 requiredUsage |= KU_KEY_AGREEMENT; 1239 break; 1240 case ecKey: 1241 /* Accept either signature or agreement. */ 1242 if (!(cert->keyUsage & 1243 (KU_DIGITAL_SIGNATURE | KU_KEY_AGREEMENT))) 1244 goto loser; 1245 break; 1246 default: 1247 goto loser; 1248 } 1249 } 1250 1251 /* Allow either digital signature or non-repudiation */ 1252 if (requiredUsage & KU_DIGITAL_SIGNATURE_OR_NON_REPUDIATION) { 1253 /* turn off the special bit */ 1254 requiredUsage &= (~KU_DIGITAL_SIGNATURE_OR_NON_REPUDIATION); 1255 1256 if (!(cert->keyUsage & (KU_DIGITAL_SIGNATURE | KU_NON_REPUDIATION))) 1257 goto loser; 1258 } 1259 1260 if ((cert->keyUsage & requiredUsage) == requiredUsage) 1261 return SECSuccess; 1262 1263 loser: 1264 PORT_SetError(SEC_ERROR_INADEQUATE_KEY_USAGE); 1265 return SECFailure; 1266 } 1267 1268 CERTCertificate * 1269 CERT_DupCertificate(CERTCertificate *c) 1270 { 1271 if (c) { 1272 NSSCertificate *tmp = STAN_GetNSSCertificate(c); 1273 nssCertificate_AddRef(tmp); 1274 } 1275 return c; 1276 } 1277 1278 SECStatus 1279 CERT_GetCertificateDer(const CERTCertificate *c, SECItem *der) 1280 { 1281 if (!c || !der) { 1282 PORT_SetError(SEC_ERROR_INVALID_ARGS); 1283 return SECFailure; 1284 } 1285 *der = c->derCert; 1286 return SECSuccess; 1287 } 1288 1289 /* 1290 * Allow use of default cert database, so that apps(such as mozilla) don't 1291 * have to pass the handle all over the place. 1292 */ 1293 static CERTCertDBHandle *default_cert_db_handle = 0; 1294 1295 void 1296 CERT_SetDefaultCertDB(CERTCertDBHandle *handle) 1297 { 1298 default_cert_db_handle = handle; 1299 1300 return; 1301 } 1302 1303 CERTCertDBHandle * 1304 CERT_GetDefaultCertDB(void) 1305 { 1306 return (default_cert_db_handle); 1307 } 1308 1309 /* XXX this would probably be okay/better as an xp routine? */ 1310 static void 1311 sec_lower_string(char *s) 1312 { 1313 if (s == NULL) { 1314 return; 1315 } 1316 1317 while (*s) { 1318 *s = PORT_Tolower((unsigned char)*s); 1319 s++; 1320 } 1321 1322 return; 1323 } 1324 1325 static PRBool 1326 cert_IsIPAddr(const char *hn) 1327 { 1328 PRBool isIPaddr = PR_FALSE; 1329 PRNetAddr netAddr; 1330 isIPaddr = (PR_SUCCESS == PR_StringToNetAddr(hn, &netAddr)); 1331 return isIPaddr; 1332 } 1333 1334 /* 1335 ** Add a domain name to the list of names that the user has explicitly 1336 ** allowed (despite cert name mismatches) for use with a server cert. 1337 */ 1338 SECStatus 1339 CERT_AddOKDomainName(CERTCertificate *cert, const char *hn) 1340 { 1341 CERTOKDomainName *domainOK; 1342 int newNameLen; 1343 1344 if (!hn || !(newNameLen = strlen(hn))) { 1345 PORT_SetError(SEC_ERROR_INVALID_ARGS); 1346 return SECFailure; 1347 } 1348 domainOK = (CERTOKDomainName *)PORT_ArenaZAlloc(cert->arena, sizeof(*domainOK)); 1349 if (!domainOK) { 1350 return SECFailure; /* error code is already set. */ 1351 } 1352 domainOK->name = (char *)PORT_ArenaZAlloc(cert->arena, newNameLen + 1); 1353 if (!domainOK->name) { 1354 return SECFailure; /* error code is already set. */ 1355 } 1356 1357 PORT_Strncpy(domainOK->name, hn, newNameLen + 1); 1358 sec_lower_string(domainOK->name); 1359 1360 /* put at head of list. */ 1361 domainOK->next = cert->domainOK; 1362 cert->domainOK = domainOK; 1363 return SECSuccess; 1364 } 1365 1366 /* returns SECSuccess if hn matches pattern cn, 1367 ** returns SECFailure with SSL_ERROR_BAD_CERT_DOMAIN if no match, 1368 ** returns SECFailure with some other error code if another error occurs. 1369 ** 1370 ** This function may modify string cn, so caller must pass a modifiable copy. 1371 */ 1372 static SECStatus 1373 cert_TestHostName(char *cn, const char *hn) 1374 { 1375 static int useShellExp = -1; 1376 1377 if (useShellExp < 0) { 1378 useShellExp = (NULL != PR_GetEnvSecure("NSS_USE_SHEXP_IN_CERT_NAME")); 1379 } 1380 if (useShellExp) { 1381 /* Backward compatible code, uses Shell Expressions (SHEXP). */ 1382 int regvalid = PORT_RegExpValid(cn); 1383 if (regvalid != NON_SXP) { 1384 SECStatus rv; 1385 /* cn is a regular expression, try to match the shexp */ 1386 int match = PORT_RegExpCaseSearch(hn, cn); 1387 1388 if (match == 0) { 1389 rv = SECSuccess; 1390 } else { 1391 PORT_SetError(SSL_ERROR_BAD_CERT_DOMAIN); 1392 rv = SECFailure; 1393 } 1394 return rv; 1395 } 1396 } else { 1397 /* New approach conforms to RFC 6125. */ 1398 char *wildcard = PORT_Strchr(cn, '*'); 1399 char *firstcndot = PORT_Strchr(cn, '.'); 1400 char *secondcndot = 1401 firstcndot ? PORT_Strchr(firstcndot + 1, '.') : NULL; 1402 char *firsthndot = PORT_Strchr(hn, '.'); 1403 1404 /* For a cn pattern to be considered valid, the wildcard character... 1405 * - may occur only in a DNS name with at least 3 components, and 1406 * - may occur only as last character in the first component, and 1407 * - may be preceded by additional characters, and 1408 * - must not be preceded by an IDNA ACE prefix (xn--) 1409 */ 1410 if (wildcard && secondcndot && secondcndot[1] && firsthndot && 1411 firstcndot - wildcard == 1 /* wildcard is last char in first component */ 1412 && secondcndot - firstcndot > 1 /* second component is non-empty */ 1413 && PORT_Strrchr(cn, '*') == wildcard /* only one wildcard in cn */ 1414 && !PORT_Strncasecmp(cn, hn, wildcard - cn) && 1415 !PORT_Strcasecmp(firstcndot, firsthndot) 1416 /* If hn starts with xn--, then cn must start with wildcard */ 1417 && (PORT_Strncasecmp(hn, "xn--", 4) || wildcard == cn)) { 1418 /* valid wildcard pattern match */ 1419 return SECSuccess; 1420 } 1421 } 1422 /* String cn has no wildcard or shell expression. 1423 * Compare entire string hn with cert name. 1424 */ 1425 if (PORT_Strcasecmp(hn, cn) == 0) { 1426 return SECSuccess; 1427 } 1428 1429 PORT_SetError(SSL_ERROR_BAD_CERT_DOMAIN); 1430 return SECFailure; 1431 } 1432 1433 SECStatus 1434 cert_VerifySubjectAltName(const CERTCertificate *cert, const char *hn) 1435 { 1436 PLArenaPool *arena = NULL; 1437 CERTGeneralName *nameList = NULL; 1438 CERTGeneralName *current; 1439 char *cn; 1440 int cnBufLen; 1441 int DNSextCount = 0; 1442 int IPextCount = 0; 1443 PRBool isIPaddr = PR_FALSE; 1444 SECStatus rv = SECFailure; 1445 SECItem subAltName; 1446 PRNetAddr netAddr; 1447 char cnbuf[128]; 1448 1449 subAltName.data = NULL; 1450 cn = cnbuf; 1451 cnBufLen = sizeof cnbuf; 1452 1453 rv = CERT_FindCertExtension(cert, SEC_OID_X509_SUBJECT_ALT_NAME, 1454 &subAltName); 1455 if (rv != SECSuccess) { 1456 goto fail; 1457 } 1458 isIPaddr = (PR_SUCCESS == PR_StringToNetAddr(hn, &netAddr)); 1459 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1460 if (!arena) 1461 goto fail; 1462 1463 nameList = current = CERT_DecodeAltNameExtension(arena, &subAltName); 1464 if (!current) 1465 goto fail; 1466 1467 do { 1468 switch (current->type) { 1469 case certDNSName: 1470 if (!isIPaddr) { 1471 /* DNS name current->name.other.data is not null terminated. 1472 ** so must copy it. 1473 */ 1474 int cnLen = current->name.other.len; 1475 rv = CERT_RFC1485_EscapeAndQuote( 1476 cn, cnBufLen, (char *)current->name.other.data, cnLen); 1477 if (rv != SECSuccess && 1478 PORT_GetError() == SEC_ERROR_OUTPUT_LEN) { 1479 cnBufLen = 1480 cnLen * 3 + 3; /* big enough for worst case */ 1481 cn = (char *)PORT_ArenaAlloc(arena, cnBufLen); 1482 if (!cn) 1483 goto fail; 1484 rv = CERT_RFC1485_EscapeAndQuote( 1485 cn, cnBufLen, (char *)current->name.other.data, 1486 cnLen); 1487 } 1488 if (rv == SECSuccess) 1489 rv = cert_TestHostName(cn, hn); 1490 if (rv == SECSuccess) 1491 goto finish; 1492 } 1493 DNSextCount++; 1494 break; 1495 case certIPAddress: 1496 if (isIPaddr) { 1497 int match = 0; 1498 PRIPv6Addr v6Addr; 1499 if (current->name.other.len == 4 && /* IP v4 address */ 1500 netAddr.inet.family == PR_AF_INET) { 1501 match = !memcmp(&netAddr.inet.ip, 1502 current->name.other.data, 4); 1503 } else if (current->name.other.len == 1504 16 && /* IP v6 address */ 1505 netAddr.ipv6.family == PR_AF_INET6) { 1506 match = !memcmp(&netAddr.ipv6.ip, 1507 current->name.other.data, 16); 1508 } else if (current->name.other.len == 1509 16 && /* IP v6 address */ 1510 netAddr.inet.family == PR_AF_INET) { 1511 /* convert netAddr to ipv6, then compare. */ 1512 /* ipv4 must be in Network Byte Order on input. */ 1513 PR_ConvertIPv4AddrToIPv6(netAddr.inet.ip, &v6Addr); 1514 match = !memcmp(&v6Addr, current->name.other.data, 16); 1515 } else if (current->name.other.len == 4 && /* IP v4 address */ 1516 netAddr.inet.family == PR_AF_INET6) { 1517 /* convert netAddr to ipv6, then compare. */ 1518 PRUint32 ipv4 = (current->name.other.data[0] << 24) | 1519 (current->name.other.data[1] << 16) | 1520 (current->name.other.data[2] << 8) | 1521 current->name.other.data[3]; 1522 /* ipv4 must be in Network Byte Order on input. */ 1523 PR_ConvertIPv4AddrToIPv6(PR_htonl(ipv4), &v6Addr); 1524 match = !memcmp(&netAddr.ipv6.ip, &v6Addr, 16); 1525 } 1526 if (match) { 1527 rv = SECSuccess; 1528 goto finish; 1529 } 1530 } 1531 IPextCount++; 1532 break; 1533 default: 1534 break; 1535 } 1536 current = CERT_GetNextGeneralName(current); 1537 } while (current != nameList); 1538 1539 fail: 1540 1541 if (!(isIPaddr ? IPextCount : DNSextCount)) { 1542 /* no relevant value in the extension was found. */ 1543 PORT_SetError(SEC_ERROR_EXTENSION_NOT_FOUND); 1544 } else { 1545 PORT_SetError(SSL_ERROR_BAD_CERT_DOMAIN); 1546 } 1547 rv = SECFailure; 1548 1549 finish: 1550 1551 /* Don't free nameList, it's part of the arena. */ 1552 if (arena) { 1553 PORT_FreeArena(arena, PR_FALSE); 1554 } 1555 1556 if (subAltName.data) { 1557 SECITEM_FreeItem(&subAltName, PR_FALSE); 1558 } 1559 1560 return rv; 1561 } 1562 1563 /* 1564 * If found: 1565 * - subAltName contains the extension (caller must free) 1566 * - return value is the decoded namelist (allocated off arena) 1567 * if not found, or if failure to decode: 1568 * - return value is NULL 1569 */ 1570 CERTGeneralName * 1571 cert_GetSubjectAltNameList(const CERTCertificate *cert, PLArenaPool *arena) 1572 { 1573 CERTGeneralName *nameList = NULL; 1574 SECStatus rv = SECFailure; 1575 SECItem subAltName; 1576 1577 if (!cert || !arena) 1578 return NULL; 1579 1580 subAltName.data = NULL; 1581 1582 rv = CERT_FindCertExtension(cert, SEC_OID_X509_SUBJECT_ALT_NAME, 1583 &subAltName); 1584 if (rv != SECSuccess) 1585 return NULL; 1586 1587 nameList = CERT_DecodeAltNameExtension(arena, &subAltName); 1588 SECITEM_FreeItem(&subAltName, PR_FALSE); 1589 return nameList; 1590 } 1591 1592 PRUint32 1593 cert_CountDNSPatterns(CERTGeneralName *firstName) 1594 { 1595 CERTGeneralName *current; 1596 PRUint32 count = 0; 1597 1598 if (!firstName) 1599 return 0; 1600 1601 current = firstName; 1602 do { 1603 switch (current->type) { 1604 case certDNSName: 1605 case certIPAddress: 1606 ++count; 1607 break; 1608 default: 1609 break; 1610 } 1611 current = CERT_GetNextGeneralName(current); 1612 } while (current != firstName); 1613 1614 return count; 1615 } 1616 1617 #ifndef INET6_ADDRSTRLEN 1618 #define INET6_ADDRSTRLEN 46 1619 #endif 1620 1621 /* will fill nickNames, 1622 * will allocate all data from nickNames->arena, 1623 * numberOfGeneralNames should have been obtained from cert_CountDNSPatterns, 1624 * will ensure the numberOfGeneralNames matches the number of output entries. 1625 */ 1626 SECStatus 1627 cert_GetDNSPatternsFromGeneralNames(CERTGeneralName *firstName, 1628 PRUint32 numberOfGeneralNames, 1629 CERTCertNicknames *nickNames) 1630 { 1631 CERTGeneralName *currentInput; 1632 char **currentOutput; 1633 1634 if (!firstName || !nickNames || !numberOfGeneralNames) 1635 return SECFailure; 1636 1637 nickNames->numnicknames = numberOfGeneralNames; 1638 nickNames->nicknames = PORT_ArenaAlloc( 1639 nickNames->arena, sizeof(char *) * numberOfGeneralNames); 1640 if (!nickNames->nicknames) 1641 return SECFailure; 1642 1643 currentInput = firstName; 1644 currentOutput = nickNames->nicknames; 1645 do { 1646 char *cn = NULL; 1647 char ipbuf[INET6_ADDRSTRLEN]; 1648 PRNetAddr addr; 1649 1650 if (numberOfGeneralNames < 1) { 1651 /* internal consistency error */ 1652 return SECFailure; 1653 } 1654 1655 switch (currentInput->type) { 1656 case certDNSName: 1657 /* DNS name currentInput->name.other.data is not null 1658 *terminated. 1659 ** so must copy it. 1660 */ 1661 cn = (char *)PORT_ArenaAlloc(nickNames->arena, 1662 currentInput->name.other.len + 1); 1663 if (!cn) 1664 return SECFailure; 1665 PORT_Memcpy(cn, currentInput->name.other.data, 1666 currentInput->name.other.len); 1667 cn[currentInput->name.other.len] = 0; 1668 break; 1669 case certIPAddress: 1670 if (currentInput->name.other.len == 4) { 1671 addr.inet.family = PR_AF_INET; 1672 memcpy(&addr.inet.ip, currentInput->name.other.data, 1673 currentInput->name.other.len); 1674 } else if (currentInput->name.other.len == 16) { 1675 addr.ipv6.family = PR_AF_INET6; 1676 memcpy(&addr.ipv6.ip, currentInput->name.other.data, 1677 currentInput->name.other.len); 1678 } 1679 if (PR_NetAddrToString(&addr, ipbuf, sizeof(ipbuf)) == 1680 PR_FAILURE) 1681 return SECFailure; 1682 cn = PORT_ArenaStrdup(nickNames->arena, ipbuf); 1683 if (!cn) 1684 return SECFailure; 1685 break; 1686 default: 1687 break; 1688 } 1689 if (cn) { 1690 *currentOutput = cn; 1691 nickNames->totallen += PORT_Strlen(cn); 1692 ++currentOutput; 1693 --numberOfGeneralNames; 1694 } 1695 currentInput = CERT_GetNextGeneralName(currentInput); 1696 } while (currentInput != firstName); 1697 1698 return (numberOfGeneralNames == 0) ? SECSuccess : SECFailure; 1699 } 1700 1701 /* 1702 * Collect all valid DNS names from the given cert. 1703 * The output arena will reference some temporaray data, 1704 * but this saves us from dealing with two arenas. 1705 * The caller may free all data by freeing CERTCertNicknames->arena. 1706 */ 1707 CERTCertNicknames * 1708 CERT_GetValidDNSPatternsFromCert(CERTCertificate *cert) 1709 { 1710 CERTGeneralName *generalNames; 1711 CERTCertNicknames *nickNames; 1712 PLArenaPool *arena; 1713 char *singleName; 1714 1715 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1716 if (!arena) { 1717 return NULL; 1718 } 1719 1720 nickNames = PORT_ArenaAlloc(arena, sizeof(CERTCertNicknames)); 1721 if (!nickNames) { 1722 PORT_FreeArena(arena, PR_FALSE); 1723 return NULL; 1724 } 1725 1726 /* init the structure */ 1727 nickNames->arena = arena; 1728 nickNames->head = NULL; 1729 nickNames->numnicknames = 0; 1730 nickNames->nicknames = NULL; 1731 nickNames->totallen = 0; 1732 1733 generalNames = cert_GetSubjectAltNameList(cert, arena); 1734 if (generalNames) { 1735 SECStatus rv_getnames = SECFailure; 1736 PRUint32 numNames = cert_CountDNSPatterns(generalNames); 1737 1738 if (numNames) { 1739 rv_getnames = cert_GetDNSPatternsFromGeneralNames( 1740 generalNames, numNames, nickNames); 1741 } 1742 1743 /* if there were names, we'll exit now, either with success or failure 1744 */ 1745 if (numNames) { 1746 if (rv_getnames == SECSuccess) { 1747 return nickNames; 1748 } 1749 1750 /* failure to produce output */ 1751 PORT_FreeArena(arena, PR_FALSE); 1752 return NULL; 1753 } 1754 } 1755 1756 /* no SAN extension or no names found in extension */ 1757 singleName = CERT_GetCommonName(&cert->subject); 1758 if (singleName) { 1759 nickNames->numnicknames = 1; 1760 nickNames->nicknames = PORT_ArenaAlloc(arena, sizeof(char *)); 1761 if (nickNames->nicknames) { 1762 *nickNames->nicknames = PORT_ArenaStrdup(arena, singleName); 1763 } 1764 PORT_Free(singleName); 1765 1766 /* Did we allocate both the buffer of pointers and the string? */ 1767 if (nickNames->nicknames && *nickNames->nicknames) { 1768 return nickNames; 1769 } 1770 } 1771 1772 PORT_FreeArena(arena, PR_FALSE); 1773 return NULL; 1774 } 1775 1776 /* Make sure that the name of the host we are connecting to matches the 1777 * name that is incoded in the common-name component of the certificate 1778 * that they are using. 1779 */ 1780 SECStatus 1781 CERT_VerifyCertName(const CERTCertificate *cert, const char *hn) 1782 { 1783 char *cn; 1784 SECStatus rv; 1785 CERTOKDomainName *domainOK; 1786 1787 if (!hn || !strlen(hn)) { 1788 PORT_SetError(SEC_ERROR_INVALID_ARGS); 1789 return SECFailure; 1790 } 1791 1792 /* if the name is one that the user has already approved, it's OK. */ 1793 for (domainOK = cert->domainOK; domainOK; domainOK = domainOK->next) { 1794 if (0 == PORT_Strcasecmp(hn, domainOK->name)) { 1795 return SECSuccess; 1796 } 1797 } 1798 1799 /* Per RFC 2818, if the SubjectAltName extension is present, it must 1800 ** be used as the cert's identity. 1801 */ 1802 rv = cert_VerifySubjectAltName(cert, hn); 1803 if (rv == SECSuccess || PORT_GetError() != SEC_ERROR_EXTENSION_NOT_FOUND) 1804 return rv; 1805 1806 cn = CERT_GetCommonName(&cert->subject); 1807 if (cn) { 1808 PRBool isIPaddr = cert_IsIPAddr(hn); 1809 if (isIPaddr) { 1810 if (PORT_Strcasecmp(hn, cn) == 0) { 1811 rv = SECSuccess; 1812 } else { 1813 PORT_SetError(SSL_ERROR_BAD_CERT_DOMAIN); 1814 rv = SECFailure; 1815 } 1816 } else { 1817 rv = cert_TestHostName(cn, hn); 1818 } 1819 PORT_Free(cn); 1820 } else 1821 PORT_SetError(SSL_ERROR_BAD_CERT_DOMAIN); 1822 return rv; 1823 } 1824 1825 PRBool 1826 CERT_CompareCerts(const CERTCertificate *c1, const CERTCertificate *c2) 1827 { 1828 SECComparison comp; 1829 1830 comp = SECITEM_CompareItem(&c1->derCert, &c2->derCert); 1831 if (comp == SECEqual) { /* certs are the same */ 1832 return (PR_TRUE); 1833 } else { 1834 return (PR_FALSE); 1835 } 1836 } 1837 1838 static SECStatus 1839 StringsEqual(char *s1, char *s2) 1840 { 1841 if ((s1 == NULL) || (s2 == NULL)) { 1842 if (s1 != s2) { /* only one is null */ 1843 return (SECFailure); 1844 } 1845 return (SECSuccess); /* both are null */ 1846 } 1847 1848 if (PORT_Strcmp(s1, s2) != 0) { 1849 return (SECFailure); /* not equal */ 1850 } 1851 1852 return (SECSuccess); /* strings are equal */ 1853 } 1854 1855 PRBool 1856 CERT_CompareCertsForRedirection(CERTCertificate *c1, CERTCertificate *c2) 1857 { 1858 SECComparison comp; 1859 char *c1str, *c2str; 1860 SECStatus eq; 1861 1862 comp = SECITEM_CompareItem(&c1->derCert, &c2->derCert); 1863 if (comp == SECEqual) { /* certs are the same */ 1864 return (PR_TRUE); 1865 } 1866 1867 /* check if they are issued by the same CA */ 1868 comp = SECITEM_CompareItem(&c1->derIssuer, &c2->derIssuer); 1869 if (comp != SECEqual) { /* different issuer */ 1870 return (PR_FALSE); 1871 } 1872 1873 /* check country name */ 1874 c1str = CERT_GetCountryName(&c1->subject); 1875 c2str = CERT_GetCountryName(&c2->subject); 1876 eq = StringsEqual(c1str, c2str); 1877 PORT_Free(c1str); 1878 PORT_Free(c2str); 1879 if (eq != SECSuccess) { 1880 return (PR_FALSE); 1881 } 1882 1883 /* check locality name */ 1884 c1str = CERT_GetLocalityName(&c1->subject); 1885 c2str = CERT_GetLocalityName(&c2->subject); 1886 eq = StringsEqual(c1str, c2str); 1887 PORT_Free(c1str); 1888 PORT_Free(c2str); 1889 if (eq != SECSuccess) { 1890 return (PR_FALSE); 1891 } 1892 1893 /* check state name */ 1894 c1str = CERT_GetStateName(&c1->subject); 1895 c2str = CERT_GetStateName(&c2->subject); 1896 eq = StringsEqual(c1str, c2str); 1897 PORT_Free(c1str); 1898 PORT_Free(c2str); 1899 if (eq != SECSuccess) { 1900 return (PR_FALSE); 1901 } 1902 1903 /* check org name */ 1904 c1str = CERT_GetOrgName(&c1->subject); 1905 c2str = CERT_GetOrgName(&c2->subject); 1906 eq = StringsEqual(c1str, c2str); 1907 PORT_Free(c1str); 1908 PORT_Free(c2str); 1909 if (eq != SECSuccess) { 1910 return (PR_FALSE); 1911 } 1912 1913 #ifdef NOTDEF 1914 /* check orgUnit name */ 1915 /* 1916 * We need to revisit this and decide which fields should be allowed to be 1917 * different 1918 */ 1919 c1str = CERT_GetOrgUnitName(&c1->subject); 1920 c2str = CERT_GetOrgUnitName(&c2->subject); 1921 eq = StringsEqual(c1str, c2str); 1922 PORT_Free(c1str); 1923 PORT_Free(c2str); 1924 if (eq != SECSuccess) { 1925 return (PR_FALSE); 1926 } 1927 #endif 1928 1929 return (PR_TRUE); /* all fields but common name are the same */ 1930 } 1931 1932 /* CERT_CertChainFromCert and CERT_DestroyCertificateList moved 1933 to certhigh.c */ 1934 1935 CERTIssuerAndSN * 1936 CERT_GetCertIssuerAndSN(PLArenaPool *arena, CERTCertificate *cert) 1937 { 1938 CERTIssuerAndSN *result; 1939 SECStatus rv; 1940 1941 if (arena == NULL) { 1942 arena = cert->arena; 1943 } 1944 1945 result = (CERTIssuerAndSN *)PORT_ArenaZAlloc(arena, sizeof(*result)); 1946 if (result == NULL) { 1947 PORT_SetError(SEC_ERROR_NO_MEMORY); 1948 return NULL; 1949 } 1950 1951 rv = SECITEM_CopyItem(arena, &result->derIssuer, &cert->derIssuer); 1952 if (rv != SECSuccess) 1953 return NULL; 1954 1955 rv = CERT_CopyName(arena, &result->issuer, &cert->issuer); 1956 if (rv != SECSuccess) 1957 return NULL; 1958 1959 rv = SECITEM_CopyItem(arena, &result->serialNumber, &cert->serialNumber); 1960 if (rv != SECSuccess) 1961 return NULL; 1962 1963 return result; 1964 } 1965 1966 char * 1967 CERT_MakeCANickname(CERTCertificate *cert) 1968 { 1969 char *firstname = NULL; 1970 char *org = NULL; 1971 char *nickname = NULL; 1972 int count; 1973 CERTCertificate *dummycert; 1974 1975 firstname = CERT_GetCommonName(&cert->subject); 1976 if (firstname == NULL) { 1977 firstname = CERT_GetOrgUnitName(&cert->subject); 1978 } 1979 1980 org = CERT_GetOrgName(&cert->issuer); 1981 if (org == NULL) { 1982 org = CERT_GetDomainComponentName(&cert->issuer); 1983 if (org == NULL) { 1984 if (firstname) { 1985 org = firstname; 1986 firstname = NULL; 1987 } else { 1988 org = PORT_Strdup("Unknown CA"); 1989 } 1990 } 1991 } 1992 1993 /* can only fail if PORT_Strdup fails, in which case 1994 * we're having memory problems. */ 1995 if (org == NULL) { 1996 goto done; 1997 } 1998 1999 count = 1; 2000 while (1) { 2001 2002 if (firstname) { 2003 if (count == 1) { 2004 nickname = PR_smprintf("%s - %s", firstname, org); 2005 } else { 2006 nickname = PR_smprintf("%s - %s #%d", firstname, org, count); 2007 } 2008 } else { 2009 if (count == 1) { 2010 nickname = PR_smprintf("%s", org); 2011 } else { 2012 nickname = PR_smprintf("%s #%d", org, count); 2013 } 2014 } 2015 if (nickname == NULL) { 2016 goto done; 2017 } 2018 2019 /* look up the nickname to make sure it isn't in use already */ 2020 dummycert = CERT_FindCertByNickname(cert->dbhandle, nickname); 2021 2022 if (dummycert == NULL) { 2023 goto done; 2024 } 2025 2026 /* found a cert, destroy it and loop */ 2027 CERT_DestroyCertificate(dummycert); 2028 2029 /* free the nickname */ 2030 PORT_Free(nickname); 2031 2032 count++; 2033 } 2034 2035 done: 2036 if (firstname) { 2037 PORT_Free(firstname); 2038 } 2039 if (org) { 2040 PORT_Free(org); 2041 } 2042 2043 return (nickname); 2044 } 2045 2046 /* CERT_Import_CAChain moved to certhigh.c */ 2047 2048 void 2049 CERT_DestroyCrl(CERTSignedCrl *crl) 2050 { 2051 SEC_DestroyCrl(crl); 2052 } 2053 2054 static int 2055 cert_Version(CERTCertificate *cert) 2056 { 2057 int version = 0; 2058 if (cert && cert->version.data && cert->version.len) { 2059 version = DER_GetInteger(&cert->version); 2060 if (version < 0) 2061 version = 0; 2062 } 2063 return version; 2064 } 2065 2066 static unsigned int 2067 cert_ComputeTrustOverrides(CERTCertificate *cert, unsigned int cType) 2068 { 2069 CERTCertTrust trust; 2070 SECStatus rv = SECFailure; 2071 2072 rv = CERT_GetCertTrust(cert, &trust); 2073 2074 if (rv == SECSuccess && 2075 (trust.sslFlags | trust.emailFlags | trust.objectSigningFlags)) { 2076 2077 if (trust.sslFlags & (CERTDB_TERMINAL_RECORD | CERTDB_TRUSTED)) 2078 cType |= NS_CERT_TYPE_SSL_SERVER | NS_CERT_TYPE_SSL_CLIENT; 2079 if (trust.sslFlags & (CERTDB_VALID_CA | CERTDB_TRUSTED_CA)) 2080 cType |= NS_CERT_TYPE_SSL_CA; 2081 #if defined(CERTDB_NOT_TRUSTED) 2082 if (trust.sslFlags & CERTDB_NOT_TRUSTED) 2083 cType &= ~(NS_CERT_TYPE_SSL_SERVER | NS_CERT_TYPE_SSL_CLIENT | 2084 NS_CERT_TYPE_SSL_CA); 2085 #endif 2086 if (trust.emailFlags & (CERTDB_TERMINAL_RECORD | CERTDB_TRUSTED)) 2087 cType |= NS_CERT_TYPE_EMAIL; 2088 if (trust.emailFlags & (CERTDB_VALID_CA | CERTDB_TRUSTED_CA)) 2089 cType |= NS_CERT_TYPE_EMAIL_CA; 2090 #if defined(CERTDB_NOT_TRUSTED) 2091 if (trust.emailFlags & CERTDB_NOT_TRUSTED) 2092 cType &= ~(NS_CERT_TYPE_EMAIL | NS_CERT_TYPE_EMAIL_CA); 2093 #endif 2094 if (trust.objectSigningFlags & 2095 (CERTDB_TERMINAL_RECORD | CERTDB_TRUSTED)) 2096 cType |= NS_CERT_TYPE_OBJECT_SIGNING; 2097 if (trust.objectSigningFlags & (CERTDB_VALID_CA | CERTDB_TRUSTED_CA)) 2098 cType |= NS_CERT_TYPE_OBJECT_SIGNING_CA; 2099 #if defined(CERTDB_NOT_TRUSTED) 2100 if (trust.objectSigningFlags & CERTDB_NOT_TRUSTED) 2101 cType &= 2102 ~(NS_CERT_TYPE_OBJECT_SIGNING | NS_CERT_TYPE_OBJECT_SIGNING_CA); 2103 #endif 2104 } 2105 return cType; 2106 } 2107 2108 /* 2109 * Does a cert belong to a CA? We decide based on perm database trust 2110 * flags, Netscape Cert Type Extension, and KeyUsage Extension. 2111 */ 2112 PRBool 2113 CERT_IsCACert(CERTCertificate *cert, unsigned int *rettype) 2114 { 2115 unsigned int cType = cert->nsCertType; 2116 PRBool ret = PR_FALSE; 2117 2118 /* 2119 * Check if the constraints are available and it's a CA, OR if it's 2120 * a X.509 v1 Root CA. 2121 */ 2122 CERTBasicConstraints constraints; 2123 if ((CERT_FindBasicConstraintExten(cert, &constraints) == SECSuccess && 2124 constraints.isCA) || 2125 (cert->isRoot && cert_Version(cert) < SEC_CERTIFICATE_VERSION_3)) 2126 cType |= (NS_CERT_TYPE_SSL_CA | NS_CERT_TYPE_EMAIL_CA); 2127 2128 /* 2129 * Apply trust overrides, if any. 2130 */ 2131 cType = cert_ComputeTrustOverrides(cert, cType); 2132 ret = (cType & (NS_CERT_TYPE_SSL_CA | NS_CERT_TYPE_EMAIL_CA | 2133 NS_CERT_TYPE_OBJECT_SIGNING_CA)) 2134 ? PR_TRUE 2135 : PR_FALSE; 2136 2137 if (rettype) { 2138 *rettype = cType; 2139 } 2140 2141 return ret; 2142 } 2143 2144 PRBool 2145 CERT_IsCADERCert(SECItem *derCert, unsigned int *type) 2146 { 2147 CERTCertificate *cert; 2148 PRBool isCA; 2149 2150 /* This is okay -- only looks at extensions */ 2151 cert = CERT_DecodeDERCertificate(derCert, PR_FALSE, NULL); 2152 if (cert == NULL) 2153 return PR_FALSE; 2154 2155 isCA = CERT_IsCACert(cert, type); 2156 CERT_DestroyCertificate(cert); 2157 return isCA; 2158 } 2159 2160 PRBool 2161 CERT_IsRootDERCert(SECItem *derCert) 2162 { 2163 CERTCertificate *cert; 2164 PRBool isRoot; 2165 2166 /* This is okay -- only looks at extensions */ 2167 cert = CERT_DecodeDERCertificate(derCert, PR_FALSE, NULL); 2168 if (cert == NULL) 2169 return PR_FALSE; 2170 2171 isRoot = cert->isRoot; 2172 CERT_DestroyCertificate(cert); 2173 return isRoot; 2174 } 2175 2176 CERTCompareValidityStatus 2177 CERT_CompareValidityTimes(CERTValidity *val_a, CERTValidity *val_b) 2178 { 2179 PRTime notBeforeA, notBeforeB, notAfterA, notAfterB; 2180 2181 if (!val_a || !val_b) { 2182 PORT_SetError(SEC_ERROR_INVALID_ARGS); 2183 return certValidityUndetermined; 2184 } 2185 2186 if (SECSuccess != DER_DecodeTimeChoice(¬BeforeA, &val_a->notBefore) || 2187 SECSuccess != DER_DecodeTimeChoice(¬BeforeB, &val_b->notBefore) || 2188 SECSuccess != DER_DecodeTimeChoice(¬AfterA, &val_a->notAfter) || 2189 SECSuccess != DER_DecodeTimeChoice(¬AfterB, &val_b->notAfter)) { 2190 return certValidityUndetermined; 2191 } 2192 2193 /* sanity check */ 2194 if (LL_CMP(notBeforeA, >, notAfterA) || LL_CMP(notBeforeB, >, notAfterB)) { 2195 PORT_SetError(SEC_ERROR_INVALID_TIME); 2196 return certValidityUndetermined; 2197 } 2198 2199 if (LL_CMP(notAfterA, !=, notAfterB)) { 2200 /* one cert validity goes farther into the future, select it */ 2201 return LL_CMP(notAfterA, <, notAfterB) ? certValidityChooseB 2202 : certValidityChooseA; 2203 } 2204 /* the two certs have the same expiration date */ 2205 PORT_Assert(LL_CMP(notAfterA, ==, notAfterB)); 2206 /* do they also have the same start date ? */ 2207 if (LL_CMP(notBeforeA, ==, notBeforeB)) { 2208 return certValidityEqual; 2209 } 2210 /* choose cert with the later start date */ 2211 return LL_CMP(notBeforeA, <, notBeforeB) ? certValidityChooseB 2212 : certValidityChooseA; 2213 } 2214 2215 /* 2216 * is certa newer than certb? If one is expired, pick the other one. 2217 */ 2218 PRBool 2219 CERT_IsNewer(CERTCertificate *certa, CERTCertificate *certb) 2220 { 2221 PRTime notBeforeA, notAfterA, notBeforeB, notAfterB, now; 2222 SECStatus rv; 2223 PRBool newerbefore, newerafter; 2224 2225 rv = CERT_GetCertTimes(certa, ¬BeforeA, ¬AfterA); 2226 if (rv != SECSuccess) { 2227 return (PR_FALSE); 2228 } 2229 2230 rv = CERT_GetCertTimes(certb, ¬BeforeB, ¬AfterB); 2231 if (rv != SECSuccess) { 2232 return (PR_TRUE); 2233 } 2234 2235 newerbefore = PR_FALSE; 2236 if (LL_CMP(notBeforeA, >, notBeforeB)) { 2237 newerbefore = PR_TRUE; 2238 } 2239 2240 newerafter = PR_FALSE; 2241 if (LL_CMP(notAfterA, >, notAfterB)) { 2242 newerafter = PR_TRUE; 2243 } 2244 2245 if (newerbefore && newerafter) { 2246 return (PR_TRUE); 2247 } 2248 2249 if ((!newerbefore) && (!newerafter)) { 2250 return (PR_FALSE); 2251 } 2252 2253 /* get current time */ 2254 now = PR_Now(); 2255 2256 if (newerbefore) { 2257 /* cert A was issued after cert B, but expires sooner */ 2258 /* if A is expired, then pick B */ 2259 if (LL_CMP(notAfterA, <, now)) { 2260 return (PR_FALSE); 2261 } 2262 return (PR_TRUE); 2263 } else { 2264 /* cert B was issued after cert A, but expires sooner */ 2265 /* if B is expired, then pick A */ 2266 if (LL_CMP(notAfterB, <, now)) { 2267 return (PR_TRUE); 2268 } 2269 return (PR_FALSE); 2270 } 2271 } 2272 2273 void 2274 CERT_DestroyCertArray(CERTCertificate **certs, unsigned int ncerts) 2275 { 2276 unsigned int i; 2277 2278 if (certs) { 2279 for (i = 0; i < ncerts; i++) { 2280 if (certs[i]) { 2281 CERT_DestroyCertificate(certs[i]); 2282 } 2283 } 2284 2285 PORT_Free(certs); 2286 } 2287 2288 return; 2289 } 2290 2291 char * 2292 CERT_FixupEmailAddr(const char *emailAddr) 2293 { 2294 char *retaddr; 2295 char *str; 2296 2297 if (emailAddr == NULL) { 2298 return (NULL); 2299 } 2300 2301 /* copy the string */ 2302 str = retaddr = PORT_Strdup(emailAddr); 2303 if (str == NULL) { 2304 return (NULL); 2305 } 2306 2307 /* make it lower case */ 2308 while (*str) { 2309 *str = tolower((unsigned char)*str); 2310 str++; 2311 } 2312 2313 return (retaddr); 2314 } 2315 2316 /* 2317 * NOTE - don't allow encode of govt-approved or invisible bits 2318 */ 2319 SECStatus 2320 CERT_DecodeTrustString(CERTCertTrust *trust, const char *trusts) 2321 { 2322 unsigned int i; 2323 unsigned int *pflags; 2324 2325 if (!trust) { 2326 PORT_SetError(SEC_ERROR_INVALID_ARGS); 2327 return SECFailure; 2328 } 2329 trust->sslFlags = 0; 2330 trust->emailFlags = 0; 2331 trust->objectSigningFlags = 0; 2332 if (!trusts) { 2333 PORT_SetError(SEC_ERROR_INVALID_ARGS); 2334 return SECFailure; 2335 } 2336 2337 pflags = &trust->sslFlags; 2338 2339 for (i = 0; i < PORT_Strlen(trusts); i++) { 2340 switch (trusts[i]) { 2341 case 'p': 2342 *pflags = *pflags | CERTDB_TERMINAL_RECORD; 2343 break; 2344 2345 case 'P': 2346 *pflags = *pflags | CERTDB_TRUSTED | CERTDB_TERMINAL_RECORD; 2347 break; 2348 2349 case 'w': 2350 *pflags = *pflags | CERTDB_SEND_WARN; 2351 break; 2352 2353 case 'c': 2354 *pflags = *pflags | CERTDB_VALID_CA; 2355 break; 2356 2357 case 'T': 2358 *pflags = *pflags | CERTDB_TRUSTED_CLIENT_CA | CERTDB_VALID_CA; 2359 break; 2360 2361 case 'C': 2362 *pflags = *pflags | CERTDB_TRUSTED_CA | CERTDB_VALID_CA; 2363 break; 2364 2365 case 'u': 2366 *pflags = *pflags | CERTDB_USER; 2367 break; 2368 2369 case 'i': 2370 *pflags = *pflags | CERTDB_INVISIBLE_CA; 2371 break; 2372 case 'g': 2373 *pflags = *pflags | CERTDB_GOVT_APPROVED_CA; 2374 break; 2375 2376 case ',': 2377 if (pflags == &trust->sslFlags) { 2378 pflags = &trust->emailFlags; 2379 } else { 2380 pflags = &trust->objectSigningFlags; 2381 } 2382 break; 2383 default: 2384 PORT_SetError(SEC_ERROR_INVALID_ARGS); 2385 return SECFailure; 2386 } 2387 } 2388 2389 return SECSuccess; 2390 } 2391 2392 static void 2393 EncodeFlags(char *trusts, unsigned int flags) 2394 { 2395 if (flags & CERTDB_VALID_CA) 2396 if (!(flags & CERTDB_TRUSTED_CA) && !(flags & CERTDB_TRUSTED_CLIENT_CA)) 2397 PORT_Strcat(trusts, "c"); 2398 if (flags & CERTDB_TERMINAL_RECORD) 2399 if (!(flags & CERTDB_TRUSTED)) 2400 PORT_Strcat(trusts, "p"); 2401 if (flags & CERTDB_TRUSTED_CA) 2402 PORT_Strcat(trusts, "C"); 2403 if (flags & CERTDB_TRUSTED_CLIENT_CA) 2404 PORT_Strcat(trusts, "T"); 2405 if (flags & CERTDB_TRUSTED) 2406 PORT_Strcat(trusts, "P"); 2407 if (flags & CERTDB_USER) 2408 PORT_Strcat(trusts, "u"); 2409 if (flags & CERTDB_SEND_WARN) 2410 PORT_Strcat(trusts, "w"); 2411 if (flags & CERTDB_INVISIBLE_CA) 2412 PORT_Strcat(trusts, "I"); 2413 if (flags & CERTDB_GOVT_APPROVED_CA) 2414 PORT_Strcat(trusts, "G"); 2415 return; 2416 } 2417 2418 char * 2419 CERT_EncodeTrustString(CERTCertTrust *trust) 2420 { 2421 char tmpTrustSSL[32]; 2422 char tmpTrustEmail[32]; 2423 char tmpTrustSigning[32]; 2424 char *retstr = NULL; 2425 2426 if (trust) { 2427 tmpTrustSSL[0] = '\0'; 2428 tmpTrustEmail[0] = '\0'; 2429 tmpTrustSigning[0] = '\0'; 2430 2431 EncodeFlags(tmpTrustSSL, trust->sslFlags); 2432 EncodeFlags(tmpTrustEmail, trust->emailFlags); 2433 EncodeFlags(tmpTrustSigning, trust->objectSigningFlags); 2434 2435 retstr = PR_smprintf("%s,%s,%s", tmpTrustSSL, tmpTrustEmail, 2436 tmpTrustSigning); 2437 } 2438 2439 return (retstr); 2440 } 2441 2442 SECStatus 2443 CERT_ImportCerts(CERTCertDBHandle *certdb, SECCertUsage usage, 2444 unsigned int ncerts, SECItem **derCerts, 2445 CERTCertificate ***retCerts, PRBool keepCerts, PRBool caOnly, 2446 char *nickname) 2447 { 2448 unsigned int i; 2449 CERTCertificate **certs = NULL; 2450 unsigned int fcerts = 0; 2451 2452 if (ncerts) { 2453 certs = PORT_ZNewArray(CERTCertificate *, ncerts); 2454 if (certs == NULL) { 2455 return (SECFailure); 2456 } 2457 2458 /* decode all of the certs into the temporary DB */ 2459 for (i = 0, fcerts = 0; i < ncerts; i++) { 2460 certs[fcerts] = CERT_NewTempCertificate(certdb, derCerts[i], NULL, 2461 PR_FALSE, PR_TRUE); 2462 if (certs[fcerts]) { 2463 SECItem subjKeyID = { siBuffer, NULL, 0 }; 2464 if (CERT_FindSubjectKeyIDExtension(certs[fcerts], &subjKeyID) == 2465 SECSuccess) { 2466 if (subjKeyID.data) { 2467 cert_AddSubjectKeyIDMapping(&subjKeyID, certs[fcerts]); 2468 } 2469 SECITEM_FreeItem(&subjKeyID, PR_FALSE); 2470 } 2471 fcerts++; 2472 } 2473 } 2474 2475 if (keepCerts) { 2476 for (i = 0; i < fcerts; i++) { 2477 char *canickname = NULL; 2478 PRBool isCA; 2479 2480 SECKEY_UpdateCertPQG(certs[i]); 2481 2482 isCA = CERT_IsCACert(certs[i], NULL); 2483 if (isCA) { 2484 canickname = CERT_MakeCANickname(certs[i]); 2485 } 2486 2487 if (isCA && (fcerts > 1)) { 2488 /* if we are importing only a single cert and specifying 2489 * a nickname, we want to use that nickname if it a CA, 2490 * otherwise if there are more than one cert, we don't 2491 * know which cert it belongs to. But we still may try 2492 * the individual canickname from the cert itself. 2493 */ 2494 /* Bug 1192442 - propagate errors from these calls. */ 2495 (void)CERT_AddTempCertToPerm(certs[i], canickname, NULL); 2496 } else { 2497 (void)CERT_AddTempCertToPerm( 2498 certs[i], nickname ? nickname : canickname, NULL); 2499 } 2500 2501 PORT_Free(canickname); 2502 /* don't care if it fails - keep going */ 2503 } 2504 } 2505 } 2506 2507 if (retCerts) { 2508 *retCerts = certs; 2509 } else { 2510 if (certs) { 2511 CERT_DestroyCertArray(certs, fcerts); 2512 } 2513 } 2514 2515 return (fcerts || !ncerts) ? SECSuccess : SECFailure; 2516 } 2517 2518 /* 2519 * a real list of certificates - need to convert CERTCertificateList 2520 * stuff and ASN 1 encoder/decoder over to using this... 2521 */ 2522 CERTCertList * 2523 CERT_NewCertList(void) 2524 { 2525 PLArenaPool *arena = NULL; 2526 CERTCertList *ret = NULL; 2527 2528 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 2529 if (arena == NULL) { 2530 goto loser; 2531 } 2532 2533 ret = (CERTCertList *)PORT_ArenaZAlloc(arena, sizeof(CERTCertList)); 2534 if (ret == NULL) { 2535 goto loser; 2536 } 2537 2538 ret->arena = arena; 2539 2540 PR_INIT_CLIST(&ret->list); 2541 2542 return (ret); 2543 2544 loser: 2545 if (arena != NULL) { 2546 PORT_FreeArena(arena, PR_FALSE); 2547 } 2548 2549 return (NULL); 2550 } 2551 2552 void 2553 CERT_DestroyCertList(CERTCertList *certs) 2554 { 2555 PRCList *node; 2556 2557 if (!certs) { 2558 return; 2559 } 2560 2561 while (!PR_CLIST_IS_EMPTY(&certs->list)) { 2562 node = PR_LIST_HEAD(&certs->list); 2563 CERT_DestroyCertificate(((CERTCertListNode *)node)->cert); 2564 PR_REMOVE_LINK(node); 2565 } 2566 2567 PORT_FreeArena(certs->arena, PR_FALSE); 2568 2569 return; 2570 } 2571 2572 void 2573 CERT_RemoveCertListNode(CERTCertListNode *node) 2574 { 2575 CERT_DestroyCertificate(node->cert); 2576 PR_REMOVE_LINK(&node->links); 2577 return; 2578 } 2579 2580 SECStatus 2581 CERT_AddCertToListTailWithData(CERTCertList *certs, CERTCertificate *cert, 2582 void *appData) 2583 { 2584 CERTCertListNode *node; 2585 2586 node = (CERTCertListNode *)PORT_ArenaZAlloc(certs->arena, 2587 sizeof(CERTCertListNode)); 2588 if (node == NULL) { 2589 goto loser; 2590 } 2591 2592 PR_INSERT_BEFORE(&node->links, &certs->list); 2593 /* certs->count++; */ 2594 node->cert = cert; 2595 node->appData = appData; 2596 return (SECSuccess); 2597 2598 loser: 2599 return (SECFailure); 2600 } 2601 2602 SECStatus 2603 CERT_AddCertToListTail(CERTCertList *certs, CERTCertificate *cert) 2604 { 2605 return CERT_AddCertToListTailWithData(certs, cert, NULL); 2606 } 2607 2608 SECStatus 2609 CERT_AddCertToListHeadWithData(CERTCertList *certs, CERTCertificate *cert, 2610 void *appData) 2611 { 2612 CERTCertListNode *node; 2613 CERTCertListNode *head; 2614 2615 head = CERT_LIST_HEAD(certs); 2616 if (head == NULL) { 2617 goto loser; 2618 } 2619 2620 node = (CERTCertListNode *)PORT_ArenaZAlloc(certs->arena, 2621 sizeof(CERTCertListNode)); 2622 if (node == NULL) { 2623 goto loser; 2624 } 2625 2626 PR_INSERT_BEFORE(&node->links, &head->links); 2627 /* certs->count++; */ 2628 node->cert = cert; 2629 node->appData = appData; 2630 return (SECSuccess); 2631 2632 loser: 2633 return (SECFailure); 2634 } 2635 2636 SECStatus 2637 CERT_AddCertToListHead(CERTCertList *certs, CERTCertificate *cert) 2638 { 2639 return CERT_AddCertToListHeadWithData(certs, cert, NULL); 2640 } 2641 2642 /* 2643 * Sort callback function to determine if cert a is newer than cert b. 2644 * Not valid certs are considered older than valid certs. 2645 */ 2646 PRBool 2647 CERT_SortCBValidity(CERTCertificate *certa, CERTCertificate *certb, void *arg) 2648 { 2649 PRTime sorttime; 2650 PRTime notBeforeA, notAfterA, notBeforeB, notAfterB; 2651 SECStatus rv; 2652 PRBool newerbefore, newerafter; 2653 PRBool aNotValid = PR_FALSE, bNotValid = PR_FALSE; 2654 2655 sorttime = *(PRTime *)arg; 2656 2657 rv = CERT_GetCertTimes(certa, ¬BeforeA, ¬AfterA); 2658 if (rv != SECSuccess) { 2659 return (PR_FALSE); 2660 } 2661 2662 rv = CERT_GetCertTimes(certb, ¬BeforeB, ¬AfterB); 2663 if (rv != SECSuccess) { 2664 return (PR_TRUE); 2665 } 2666 newerbefore = PR_FALSE; 2667 if (LL_CMP(notBeforeA, >, notBeforeB)) { 2668 newerbefore = PR_TRUE; 2669 } 2670 newerafter = PR_FALSE; 2671 if (LL_CMP(notAfterA, >, notAfterB)) { 2672 newerafter = PR_TRUE; 2673 } 2674 2675 /* check if A is valid at sorttime */ 2676 if (CERT_CheckCertValidTimes(certa, sorttime, PR_FALSE) != 2677 secCertTimeValid) { 2678 aNotValid = PR_TRUE; 2679 } 2680 2681 /* check if B is valid at sorttime */ 2682 if (CERT_CheckCertValidTimes(certb, sorttime, PR_FALSE) != 2683 secCertTimeValid) { 2684 bNotValid = PR_TRUE; 2685 } 2686 2687 /* a is valid, b is not */ 2688 if (bNotValid && (!aNotValid)) { 2689 return (PR_TRUE); 2690 } 2691 2692 /* b is valid, a is not */ 2693 if (aNotValid && (!bNotValid)) { 2694 return (PR_FALSE); 2695 } 2696 2697 /* a and b are either valid or not valid */ 2698 if (newerbefore && newerafter) { 2699 return (PR_TRUE); 2700 } 2701 2702 if ((!newerbefore) && (!newerafter)) { 2703 return (PR_FALSE); 2704 } 2705 2706 if (newerbefore) { 2707 /* cert A was issued after cert B, but expires sooner */ 2708 return (PR_TRUE); 2709 } else { 2710 /* cert B was issued after cert A, but expires sooner */ 2711 return (PR_FALSE); 2712 } 2713 } 2714 2715 SECStatus 2716 CERT_AddCertToListSorted(CERTCertList *certs, CERTCertificate *cert, 2717 CERTSortCallback f, void *arg) 2718 { 2719 CERTCertListNode *node; 2720 CERTCertListNode *head; 2721 PRBool ret; 2722 2723 node = (CERTCertListNode *)PORT_ArenaZAlloc(certs->arena, 2724 sizeof(CERTCertListNode)); 2725 if (node == NULL) { 2726 goto loser; 2727 } 2728 2729 head = CERT_LIST_HEAD(certs); 2730 2731 while (!CERT_LIST_END(head, certs)) { 2732 2733 /* if cert is already in the list, then don't add it again */ 2734 if (cert == head->cert) { 2735 /*XXX*/ 2736 /* don't keep a reference */ 2737 CERT_DestroyCertificate(cert); 2738 goto done; 2739 } 2740 2741 ret = (*f)(cert, head->cert, arg); 2742 /* if sort function succeeds, then insert before current node */ 2743 if (ret) { 2744 PR_INSERT_BEFORE(&node->links, &head->links); 2745 goto done; 2746 } 2747 2748 head = CERT_LIST_NEXT(head); 2749 } 2750 /* if we get to the end, then just insert it at the tail */ 2751 PR_INSERT_BEFORE(&node->links, &certs->list); 2752 2753 done: 2754 /* certs->count++; */ 2755 node->cert = cert; 2756 return (SECSuccess); 2757 2758 loser: 2759 return (SECFailure); 2760 } 2761 2762 /* This routine is here because pcertdb.c still has a call to it. 2763 * The SMIME profile code in pcertdb.c should be split into high (find 2764 * the email cert) and low (store the profile) code. At that point, we 2765 * can move this to certhigh.c where it belongs. 2766 * 2767 * remove certs from a list that don't have keyUsage and certType 2768 * that match the given usage. 2769 */ 2770 SECStatus 2771 CERT_FilterCertListByUsage(CERTCertList *certList, SECCertUsage usage, 2772 PRBool ca) 2773 { 2774 unsigned int requiredKeyUsage; 2775 unsigned int requiredCertType; 2776 CERTCertListNode *node, *savenode; 2777 SECStatus rv; 2778 2779 if (certList == NULL) 2780 goto loser; 2781 2782 rv = CERT_KeyUsageAndTypeForCertUsage(usage, ca, &requiredKeyUsage, 2783 &requiredCertType); 2784 if (rv != SECSuccess) { 2785 goto loser; 2786 } 2787 2788 node = CERT_LIST_HEAD(certList); 2789 2790 while (!CERT_LIST_END(node, certList)) { 2791 2792 PRBool bad = (PRBool)(!node->cert); 2793 2794 /* bad key usage ? */ 2795 if (!bad && 2796 CERT_CheckKeyUsage(node->cert, requiredKeyUsage) != SECSuccess) { 2797 bad = PR_TRUE; 2798 } 2799 /* bad cert type ? */ 2800 if (!bad) { 2801 unsigned int certType = 0; 2802 if (ca) { 2803 /* This function returns a more comprehensive cert type that 2804 * takes trust flags into consideration. Should probably 2805 * fix the cert decoding code to do this. 2806 */ 2807 (void)CERT_IsCACert(node->cert, &certType); 2808 } else { 2809 certType = node->cert->nsCertType; 2810 } 2811 if (!(certType & requiredCertType)) { 2812 bad = PR_TRUE; 2813 } 2814 } 2815 2816 if (bad) { 2817 /* remove the node if it is bad */ 2818 savenode = CERT_LIST_NEXT(node); 2819 CERT_RemoveCertListNode(node); 2820 node = savenode; 2821 } else { 2822 node = CERT_LIST_NEXT(node); 2823 } 2824 } 2825 return (SECSuccess); 2826 2827 loser: 2828 return (SECFailure); 2829 } 2830 2831 PRBool 2832 CERT_IsUserCert(CERTCertificate *cert) 2833 { 2834 CERTCertTrust trust; 2835 SECStatus rv = SECFailure; 2836 2837 rv = CERT_GetCertTrust(cert, &trust); 2838 if (rv == SECSuccess && 2839 ((trust.sslFlags & CERTDB_USER) || (trust.emailFlags & CERTDB_USER) || 2840 (trust.objectSigningFlags & CERTDB_USER))) { 2841 return PR_TRUE; 2842 } else { 2843 return PR_FALSE; 2844 } 2845 } 2846 2847 SECStatus 2848 CERT_FilterCertListForUserCerts(CERTCertList *certList) 2849 { 2850 CERTCertListNode *node, *freenode; 2851 CERTCertificate *cert; 2852 2853 if (!certList) { 2854 return SECFailure; 2855 } 2856 2857 node = CERT_LIST_HEAD(certList); 2858 2859 while (!CERT_LIST_END(node, certList)) { 2860 cert = node->cert; 2861 if (PR_TRUE != CERT_IsUserCert(cert)) { 2862 /* Not a User Cert, so remove this cert from the list */ 2863 freenode = node; 2864 node = CERT_LIST_NEXT(node); 2865 CERT_RemoveCertListNode(freenode); 2866 } else { 2867 /* Is a User cert, so leave it in the list */ 2868 node = CERT_LIST_NEXT(node); 2869 } 2870 } 2871 2872 return (SECSuccess); 2873 } 2874 2875 /* return true if cert is in the list */ 2876 PRBool 2877 CERT_IsInList(const CERTCertificate *cert, const CERTCertList *certList) 2878 { 2879 CERTCertListNode *node; 2880 for (node = CERT_LIST_HEAD(certList); !CERT_LIST_END(node, certList); 2881 node = CERT_LIST_NEXT(node)) { 2882 if (node->cert == cert) { 2883 return PR_TRUE; 2884 } 2885 } 2886 return PR_FALSE; 2887 } 2888 2889 /* returned certList is the intersection of the certs on certList and the 2890 * certs on filterList */ 2891 SECStatus 2892 CERT_FilterCertListByCertList(CERTCertList *certList, 2893 const CERTCertList *filterList) 2894 { 2895 CERTCertListNode *node, *freenode; 2896 CERTCertificate *cert; 2897 2898 if (!certList) { 2899 return SECFailure; 2900 } 2901 2902 if (!filterList || CERT_LIST_EMPTY(certList)) { 2903 /* if the filterList is empty, just clear out certList and return */ 2904 for (node = CERT_LIST_HEAD(certList); !CERT_LIST_END(node, certList);) { 2905 freenode = node; 2906 node = CERT_LIST_NEXT(node); 2907 CERT_RemoveCertListNode(freenode); 2908 } 2909 return SECSuccess; 2910 } 2911 2912 node = CERT_LIST_HEAD(certList); 2913 2914 while (!CERT_LIST_END(node, certList)) { 2915 cert = node->cert; 2916 if (!CERT_IsInList(cert, filterList)) { 2917 // no matching cert on filter list, remove it from certlist */ 2918 freenode = node; 2919 node = CERT_LIST_NEXT(node); 2920 CERT_RemoveCertListNode(freenode); 2921 } else { 2922 /* matching cert, keep it around */ 2923 node = CERT_LIST_NEXT(node); 2924 } 2925 } 2926 2927 return (SECSuccess); 2928 } 2929 2930 SECStatus 2931 CERT_FilterCertListByNickname(CERTCertList *certList, char *nickname, 2932 void *pwarg) 2933 { 2934 CERTCertList *nameList; 2935 SECStatus rv; 2936 2937 if (!certList) { 2938 return SECFailure; 2939 } 2940 2941 /* we could try to match the nickname to the individual cert, 2942 * but nickname parsing is quite complicated, so it's best just 2943 * to use the existing code and get a list of certs that match the 2944 * nickname. We can then compare that list with our input cert list 2945 * and return only those certs that are on both. */ 2946 nameList = PK11_FindCertsFromNickname(nickname, pwarg); 2947 2948 /* namelist could be NULL, this will force certList to become empty */ 2949 rv = CERT_FilterCertListByCertList(certList, nameList); 2950 /* CERT_DestroyCertList can now accept a NULL pointer */ 2951 CERT_DestroyCertList(nameList); 2952 return rv; 2953 } 2954 2955 static PZLock *certRefCountLock = NULL; 2956 2957 /* 2958 * Acquire the cert reference count lock 2959 * There is currently one global lock for all certs, but I'm putting a cert 2960 * arg here so that it will be easy to make it per-cert in the future if 2961 * that turns out to be necessary. 2962 */ 2963 void 2964 CERT_LockCertRefCount(CERTCertificate *cert) 2965 { 2966 PORT_Assert(certRefCountLock != NULL); 2967 PZ_Lock(certRefCountLock); 2968 return; 2969 } 2970 2971 /* 2972 * Free the cert reference count lock 2973 */ 2974 void 2975 CERT_UnlockCertRefCount(CERTCertificate *cert) 2976 { 2977 PORT_Assert(certRefCountLock != NULL); 2978 PRStatus prstat = PZ_Unlock(certRefCountLock); 2979 PORT_AssertArg(prstat == PR_SUCCESS); 2980 } 2981 2982 static PZLock *certTrustLock = NULL; 2983 2984 /* 2985 * Acquire the cert trust lock 2986 * There is currently one global lock for all certs, but I'm putting a cert 2987 * arg here so that it will be easy to make it per-cert in the future if 2988 * that turns out to be necessary. 2989 */ 2990 void 2991 CERT_LockCertTrust(const CERTCertificate *cert) 2992 { 2993 PORT_Assert(certTrustLock != NULL); 2994 PZ_Lock(certTrustLock); 2995 } 2996 2997 static PZLock *certTempPermCertLock = NULL; 2998 2999 /* 3000 * Acquire the cert temp/perm/nssCert lock 3001 */ 3002 void 3003 CERT_LockCertTempPerm(const CERTCertificate *cert) 3004 { 3005 PORT_Assert(certTempPermCertLock != NULL); 3006 PZ_Lock(certTempPermCertLock); 3007 } 3008 3009 /* Maybe[Lock, Unlock] variants are only to be used by 3010 * CERT_DestroyCertificate, since an application could 3011 * call this after NSS_Shutdown destroys cert locks. */ 3012 void 3013 CERT_MaybeLockCertTempPerm(const CERTCertificate *cert) 3014 { 3015 if (certTempPermCertLock) { 3016 PZ_Lock(certTempPermCertLock); 3017 } 3018 } 3019 3020 SECStatus 3021 cert_InitLocks(void) 3022 { 3023 if (certRefCountLock == NULL) { 3024 certRefCountLock = PZ_NewLock(nssILockRefLock); 3025 PORT_Assert(certRefCountLock != NULL); 3026 if (!certRefCountLock) { 3027 return SECFailure; 3028 } 3029 } 3030 3031 if (certTrustLock == NULL) { 3032 certTrustLock = PZ_NewLock(nssILockCertDB); 3033 PORT_Assert(certTrustLock != NULL); 3034 if (!certTrustLock) { 3035 PZ_DestroyLock(certRefCountLock); 3036 certRefCountLock = NULL; 3037 return SECFailure; 3038 } 3039 } 3040 3041 if (certTempPermCertLock == NULL) { 3042 certTempPermCertLock = PZ_NewLock(nssILockCertDB); 3043 PORT_Assert(certTempPermCertLock != NULL); 3044 if (!certTempPermCertLock) { 3045 PZ_DestroyLock(certTrustLock); 3046 PZ_DestroyLock(certRefCountLock); 3047 certRefCountLock = NULL; 3048 certTrustLock = NULL; 3049 return SECFailure; 3050 } 3051 } 3052 3053 return SECSuccess; 3054 } 3055 3056 SECStatus 3057 cert_DestroyLocks(void) 3058 { 3059 SECStatus rv = SECSuccess; 3060 3061 PORT_Assert(certRefCountLock != NULL); 3062 if (certRefCountLock) { 3063 PZ_DestroyLock(certRefCountLock); 3064 certRefCountLock = NULL; 3065 } else { 3066 rv = SECFailure; 3067 } 3068 3069 PORT_Assert(certTrustLock != NULL); 3070 if (certTrustLock) { 3071 PZ_DestroyLock(certTrustLock); 3072 certTrustLock = NULL; 3073 } else { 3074 rv = SECFailure; 3075 } 3076 3077 PORT_Assert(certTempPermCertLock != NULL); 3078 if (certTempPermCertLock) { 3079 PZ_DestroyLock(certTempPermCertLock); 3080 certTempPermCertLock = NULL; 3081 } else { 3082 rv = SECFailure; 3083 } 3084 return rv; 3085 } 3086 3087 /* 3088 * Free the cert trust lock 3089 */ 3090 void 3091 CERT_UnlockCertTrust(const CERTCertificate *cert) 3092 { 3093 PORT_Assert(certTrustLock != NULL); 3094 PRStatus prstat = PZ_Unlock(certTrustLock); 3095 PORT_AssertArg(prstat == PR_SUCCESS); 3096 } 3097 3098 /* 3099 * Free the temp/perm/nssCert lock 3100 */ 3101 void 3102 CERT_UnlockCertTempPerm(const CERTCertificate *cert) 3103 { 3104 PORT_Assert(certTempPermCertLock != NULL); 3105 PRStatus prstat = PZ_Unlock(certTempPermCertLock); 3106 PORT_AssertArg(prstat == PR_SUCCESS); 3107 } 3108 3109 void 3110 CERT_MaybeUnlockCertTempPerm(const CERTCertificate *cert) 3111 { 3112 if (certTempPermCertLock) { 3113 PZ_Unlock(certTempPermCertLock); 3114 } 3115 } 3116 3117 /* 3118 * Get the StatusConfig data for this handle 3119 */ 3120 CERTStatusConfig * 3121 CERT_GetStatusConfig(CERTCertDBHandle *handle) 3122 { 3123 return handle->statusConfig; 3124 } 3125 3126 /* 3127 * Set the StatusConfig data for this handle. There 3128 * should not be another configuration set. 3129 */ 3130 void 3131 CERT_SetStatusConfig(CERTCertDBHandle *handle, CERTStatusConfig *statusConfig) 3132 { 3133 PORT_Assert(handle->statusConfig == NULL); 3134 handle->statusConfig = statusConfig; 3135 } 3136 3137 /* 3138 * Code for dealing with subjKeyID to cert mappings. 3139 */ 3140 3141 static PLHashTable *gSubjKeyIDHash = NULL; 3142 static PRLock *gSubjKeyIDLock = NULL; 3143 static PLHashTable *gSubjKeyIDSlotCheckHash = NULL; 3144 static PRLock *gSubjKeyIDSlotCheckLock = NULL; 3145 3146 static void * 3147 cert_AllocTable(void *pool, PRSize size) 3148 { 3149 return PORT_Alloc(size); 3150 } 3151 3152 static void 3153 cert_FreeTable(void *pool, void *item) 3154 { 3155 PORT_Free(item); 3156 } 3157 3158 static PLHashEntry * 3159 cert_AllocEntry(void *pool, const void *key) 3160 { 3161 return PORT_New(PLHashEntry); 3162 } 3163 3164 static void 3165 cert_FreeEntry(void *pool, PLHashEntry *he, PRUintn flag) 3166 { 3167 SECITEM_FreeItem((SECItem *)(he->value), PR_TRUE); 3168 if (flag == HT_FREE_ENTRY) { 3169 SECITEM_FreeItem((SECItem *)(he->key), PR_TRUE); 3170 PORT_Free(he); 3171 } 3172 } 3173 3174 static PLHashAllocOps cert_AllocOps = { cert_AllocTable, cert_FreeTable, 3175 cert_AllocEntry, cert_FreeEntry }; 3176 3177 SECStatus 3178 cert_CreateSubjectKeyIDSlotCheckHash(void) 3179 { 3180 /* 3181 * This hash is used to remember the series of a slot 3182 * when we last checked for user certs 3183 */ 3184 gSubjKeyIDSlotCheckHash = 3185 PL_NewHashTable(0, SECITEM_Hash, SECITEM_HashCompare, 3186 SECITEM_HashCompare, &cert_AllocOps, NULL); 3187 if (!gSubjKeyIDSlotCheckHash) { 3188 PORT_SetError(SEC_ERROR_NO_MEMORY); 3189 return SECFailure; 3190 } 3191 gSubjKeyIDSlotCheckLock = PR_NewLock(); 3192 if (!gSubjKeyIDSlotCheckLock) { 3193 PL_HashTableDestroy(gSubjKeyIDSlotCheckHash); 3194 gSubjKeyIDSlotCheckHash = NULL; 3195 PORT_SetError(SEC_ERROR_NO_MEMORY); 3196 return SECFailure; 3197 } 3198 return SECSuccess; 3199 } 3200 3201 SECStatus 3202 cert_CreateSubjectKeyIDHashTable(void) 3203 { 3204 gSubjKeyIDHash = PL_NewHashTable(0, SECITEM_Hash, SECITEM_HashCompare, 3205 SECITEM_HashCompare, &cert_AllocOps, NULL); 3206 if (!gSubjKeyIDHash) { 3207 PORT_SetError(SEC_ERROR_NO_MEMORY); 3208 return SECFailure; 3209 } 3210 gSubjKeyIDLock = PR_NewLock(); 3211 if (!gSubjKeyIDLock) { 3212 PL_HashTableDestroy(gSubjKeyIDHash); 3213 gSubjKeyIDHash = NULL; 3214 PORT_SetError(SEC_ERROR_NO_MEMORY); 3215 return SECFailure; 3216 } 3217 /* initialize the companion hash (for remembering slot series) */ 3218 if (cert_CreateSubjectKeyIDSlotCheckHash() != SECSuccess) { 3219 cert_DestroySubjectKeyIDHashTable(); 3220 return SECFailure; 3221 } 3222 return SECSuccess; 3223 } 3224 3225 SECStatus 3226 cert_AddSubjectKeyIDMapping(SECItem *subjKeyID, CERTCertificate *cert) 3227 { 3228 SECItem *newKeyID, *oldVal, *newVal; 3229 SECStatus rv = SECFailure; 3230 3231 if (!gSubjKeyIDLock) { 3232 /* If one is created, then both are there. So only check for one. */ 3233 return SECFailure; 3234 } 3235 3236 newVal = SECITEM_DupItem(&cert->derCert); 3237 if (!newVal) { 3238 PORT_SetError(SEC_ERROR_NO_MEMORY); 3239 goto done; 3240 } 3241 newKeyID = SECITEM_DupItem(subjKeyID); 3242 if (!newKeyID) { 3243 SECITEM_FreeItem(newVal, PR_TRUE); 3244 PORT_SetError(SEC_ERROR_NO_MEMORY); 3245 goto done; 3246 } 3247 3248 PR_Lock(gSubjKeyIDLock); 3249 /* The hash table implementation does not free up the memory 3250 * associated with the key of an already existing entry if we add a 3251 * duplicate, so we would wind up leaking the previously allocated 3252 * key if we don't remove before adding. 3253 */ 3254 oldVal = (SECItem *)PL_HashTableLookup(gSubjKeyIDHash, subjKeyID); 3255 if (oldVal) { 3256 PL_HashTableRemove(gSubjKeyIDHash, subjKeyID); 3257 } 3258 3259 rv = (PL_HashTableAdd(gSubjKeyIDHash, newKeyID, newVal)) ? SECSuccess 3260 : SECFailure; 3261 PR_Unlock(gSubjKeyIDLock); 3262 done: 3263 return rv; 3264 } 3265 3266 SECStatus 3267 cert_RemoveSubjectKeyIDMapping(SECItem *subjKeyID) 3268 { 3269 SECStatus rv; 3270 if (!gSubjKeyIDLock) 3271 return SECFailure; 3272 3273 PR_Lock(gSubjKeyIDLock); 3274 rv = (PL_HashTableRemove(gSubjKeyIDHash, subjKeyID)) ? SECSuccess 3275 : SECFailure; 3276 PR_Unlock(gSubjKeyIDLock); 3277 return rv; 3278 } 3279 3280 SECStatus 3281 cert_UpdateSubjectKeyIDSlotCheck(SECItem *slotid, int series) 3282 { 3283 SECItem *oldSeries, *newSlotid, *newSeries; 3284 SECStatus rv = SECFailure; 3285 3286 if (!gSubjKeyIDSlotCheckLock) { 3287 return rv; 3288 } 3289 3290 newSlotid = SECITEM_DupItem(slotid); 3291 newSeries = SECITEM_AllocItem(NULL, NULL, sizeof(int)); 3292 if (!newSlotid || !newSeries) { 3293 PORT_SetError(SEC_ERROR_NO_MEMORY); 3294 goto loser; 3295 } 3296 PORT_Memcpy(newSeries->data, &series, sizeof(int)); 3297 3298 PR_Lock(gSubjKeyIDSlotCheckLock); 3299 oldSeries = (SECItem *)PL_HashTableLookup(gSubjKeyIDSlotCheckHash, slotid); 3300 if (oldSeries) { 3301 /* 3302 * make sure we don't leak the key of an existing entry 3303 * (similar to cert_AddSubjectKeyIDMapping, see comment there) 3304 */ 3305 PL_HashTableRemove(gSubjKeyIDSlotCheckHash, slotid); 3306 } 3307 rv = (PL_HashTableAdd(gSubjKeyIDSlotCheckHash, newSlotid, newSeries)) 3308 ? SECSuccess 3309 : SECFailure; 3310 PR_Unlock(gSubjKeyIDSlotCheckLock); 3311 if (rv == SECSuccess) { 3312 return rv; 3313 } 3314 3315 loser: 3316 if (newSlotid) { 3317 SECITEM_FreeItem(newSlotid, PR_TRUE); 3318 } 3319 if (newSeries) { 3320 SECITEM_FreeItem(newSeries, PR_TRUE); 3321 } 3322 return rv; 3323 } 3324 3325 int 3326 cert_SubjectKeyIDSlotCheckSeries(SECItem *slotid) 3327 { 3328 SECItem *seriesItem = NULL; 3329 int series; 3330 3331 if (!gSubjKeyIDSlotCheckLock) { 3332 PORT_SetError(SEC_ERROR_NOT_INITIALIZED); 3333 return -1; 3334 } 3335 3336 PR_Lock(gSubjKeyIDSlotCheckLock); 3337 seriesItem = (SECItem *)PL_HashTableLookup(gSubjKeyIDSlotCheckHash, slotid); 3338 PR_Unlock(gSubjKeyIDSlotCheckLock); 3339 /* getting a null series just means we haven't registered one yet, 3340 * just return 0 */ 3341 if (seriesItem == NULL) { 3342 return 0; 3343 } 3344 /* if we got a series back, assert if it's not the proper length. */ 3345 PORT_Assert(seriesItem->len == sizeof(int)); 3346 if (seriesItem->len != sizeof(int)) { 3347 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); 3348 return -1; 3349 } 3350 PORT_Memcpy(&series, seriesItem->data, sizeof(int)); 3351 return series; 3352 } 3353 3354 SECStatus 3355 cert_DestroySubjectKeyIDSlotCheckHash(void) 3356 { 3357 if (gSubjKeyIDSlotCheckHash) { 3358 PR_Lock(gSubjKeyIDSlotCheckLock); 3359 PL_HashTableDestroy(gSubjKeyIDSlotCheckHash); 3360 gSubjKeyIDSlotCheckHash = NULL; 3361 PR_Unlock(gSubjKeyIDSlotCheckLock); 3362 PR_DestroyLock(gSubjKeyIDSlotCheckLock); 3363 gSubjKeyIDSlotCheckLock = NULL; 3364 } 3365 return SECSuccess; 3366 } 3367 3368 SECStatus 3369 cert_DestroySubjectKeyIDHashTable(void) 3370 { 3371 if (gSubjKeyIDHash) { 3372 PR_Lock(gSubjKeyIDLock); 3373 PL_HashTableDestroy(gSubjKeyIDHash); 3374 gSubjKeyIDHash = NULL; 3375 PR_Unlock(gSubjKeyIDLock); 3376 PR_DestroyLock(gSubjKeyIDLock); 3377 gSubjKeyIDLock = NULL; 3378 } 3379 cert_DestroySubjectKeyIDSlotCheckHash(); 3380 return SECSuccess; 3381 } 3382 3383 SECItem * 3384 cert_FindDERCertBySubjectKeyID(SECItem *subjKeyID) 3385 { 3386 SECItem *val; 3387 3388 if (!gSubjKeyIDLock) 3389 return NULL; 3390 3391 PR_Lock(gSubjKeyIDLock); 3392 val = (SECItem *)PL_HashTableLookup(gSubjKeyIDHash, subjKeyID); 3393 if (val) { 3394 val = SECITEM_DupItem(val); 3395 } 3396 PR_Unlock(gSubjKeyIDLock); 3397 return val; 3398 } 3399 3400 CERTCertificate * 3401 CERT_FindCertBySubjectKeyID(CERTCertDBHandle *handle, SECItem *subjKeyID) 3402 { 3403 CERTCertificate *cert = NULL; 3404 SECItem *derCert; 3405 3406 derCert = cert_FindDERCertBySubjectKeyID(subjKeyID); 3407 if (derCert) { 3408 cert = CERT_FindCertByDERCert(handle, derCert); 3409 SECITEM_FreeItem(derCert, PR_TRUE); 3410 } 3411 return cert; 3412 }