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