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

Unified Diff: nss/lib/certdb/certdb.c

Issue 2078763002: Delete bundled copy of NSS and replace with README. (Closed) Base URL: https://chromium.googlesource.com/chromium/deps/nss@master
Patch Set: Delete bundled copy of NSS and replace with README. Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « nss/lib/certdb/certdb.h ('k') | nss/lib/certdb/certi.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: nss/lib/certdb/certdb.c
diff --git a/nss/lib/certdb/certdb.c b/nss/lib/certdb/certdb.c
deleted file mode 100644
index 80b83ed4357fb9cac50a6e046b60f94edb94fae9..0000000000000000000000000000000000000000
--- a/nss/lib/certdb/certdb.c
+++ /dev/null
@@ -1,3245 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-/*
- * Certificate handling code
- */
-
-#include "nssilock.h"
-#include "prmon.h"
-#include "prtime.h"
-#include "cert.h"
-#include "certi.h"
-#include "secder.h"
-#include "secoid.h"
-#include "secasn1.h"
-#include "genname.h"
-#include "keyhi.h"
-#include "secitem.h"
-#include "certdb.h"
-#include "prprf.h"
-#include "sechash.h"
-#include "prlong.h"
-#include "certxutl.h"
-#include "portreg.h"
-#include "secerr.h"
-#include "sslerr.h"
-#include "pk11func.h"
-#include "xconst.h" /* for CERT_DecodeAltNameExtension */
-
-#include "pki.h"
-#include "pki3hack.h"
-
-SEC_ASN1_MKSUB(CERT_TimeChoiceTemplate)
-SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate)
-SEC_ASN1_MKSUB(SEC_BitStringTemplate)
-SEC_ASN1_MKSUB(SEC_IntegerTemplate)
-SEC_ASN1_MKSUB(SEC_SkipTemplate)
-
-/*
- * Certificate database handling code
- */
-
-const SEC_ASN1Template CERT_CertExtensionTemplate[] = {
- { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CERTCertExtension) },
- { SEC_ASN1_OBJECT_ID, offsetof(CERTCertExtension, id) },
- { SEC_ASN1_OPTIONAL | SEC_ASN1_BOOLEAN, /* XXX DER_DEFAULT */
- offsetof(CERTCertExtension, critical) },
- { SEC_ASN1_OCTET_STRING, offsetof(CERTCertExtension, value) },
- { 0 }
-};
-
-const SEC_ASN1Template CERT_SequenceOfCertExtensionTemplate[] = {
- { SEC_ASN1_SEQUENCE_OF, 0, CERT_CertExtensionTemplate }
-};
-
-const SEC_ASN1Template CERT_TimeChoiceTemplate[] = {
- { SEC_ASN1_CHOICE, offsetof(SECItem, type), 0, sizeof(SECItem) },
- { SEC_ASN1_UTC_TIME, 0, 0, siUTCTime },
- { SEC_ASN1_GENERALIZED_TIME, 0, 0, siGeneralizedTime },
- { 0 }
-};
-
-const SEC_ASN1Template CERT_ValidityTemplate[] = {
- { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CERTValidity) },
- { SEC_ASN1_INLINE | SEC_ASN1_XTRN, offsetof(CERTValidity, notBefore),
- SEC_ASN1_SUB(CERT_TimeChoiceTemplate), 0 },
- { SEC_ASN1_INLINE | SEC_ASN1_XTRN, offsetof(CERTValidity, notAfter),
- SEC_ASN1_SUB(CERT_TimeChoiceTemplate), 0 },
- { 0 }
-};
-
-const SEC_ASN1Template CERT_CertificateTemplate[] = {
- { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CERTCertificate) },
- { SEC_ASN1_EXPLICIT | SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED |
- SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 0, /* XXX DER_DEFAULT */
- offsetof(CERTCertificate, version),
- SEC_ASN1_SUB(SEC_IntegerTemplate) },
- { SEC_ASN1_INTEGER, offsetof(CERTCertificate, serialNumber) },
- { SEC_ASN1_INLINE | SEC_ASN1_XTRN, offsetof(CERTCertificate, signature),
- SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
- { SEC_ASN1_SAVE, offsetof(CERTCertificate, derIssuer) },
- { SEC_ASN1_INLINE, offsetof(CERTCertificate, issuer), CERT_NameTemplate },
- { SEC_ASN1_INLINE, offsetof(CERTCertificate, validity),
- CERT_ValidityTemplate },
- { SEC_ASN1_SAVE, offsetof(CERTCertificate, derSubject) },
- { SEC_ASN1_INLINE, offsetof(CERTCertificate, subject), CERT_NameTemplate },
- { SEC_ASN1_SAVE, offsetof(CERTCertificate, derPublicKey) },
- { SEC_ASN1_INLINE, offsetof(CERTCertificate, subjectPublicKeyInfo),
- CERT_SubjectPublicKeyInfoTemplate },
- { SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 1,
- offsetof(CERTCertificate, issuerID),
- SEC_ASN1_SUB(SEC_BitStringTemplate) },
- { SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 2,
- offsetof(CERTCertificate, subjectID),
- SEC_ASN1_SUB(SEC_BitStringTemplate) },
- { SEC_ASN1_EXPLICIT | SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED |
- SEC_ASN1_CONTEXT_SPECIFIC | 3,
- offsetof(CERTCertificate, extensions),
- CERT_SequenceOfCertExtensionTemplate },
- { 0 }
-};
-
-const SEC_ASN1Template SEC_SignedCertificateTemplate[] = {
- { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CERTCertificate) },
- { SEC_ASN1_SAVE, offsetof(CERTCertificate, signatureWrap.data) },
- { SEC_ASN1_INLINE, 0, CERT_CertificateTemplate },
- { SEC_ASN1_INLINE | SEC_ASN1_XTRN,
- offsetof(CERTCertificate, signatureWrap.signatureAlgorithm),
- SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
- { SEC_ASN1_BIT_STRING, offsetof(CERTCertificate, signatureWrap.signature) },
- { 0 }
-};
-
-/*
- * Find the subjectName in a DER encoded certificate
- */
-const SEC_ASN1Template SEC_CertSubjectTemplate[] = {
- { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SECItem) },
- { SEC_ASN1_EXPLICIT | SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED |
- SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 0,
- 0, SEC_ASN1_SUB(SEC_SkipTemplate) }, /* version */
- { SEC_ASN1_SKIP }, /* serial number */
- { SEC_ASN1_SKIP }, /* signature algorithm */
- { SEC_ASN1_SKIP }, /* issuer */
- { SEC_ASN1_SKIP }, /* validity */
- { SEC_ASN1_ANY, 0, NULL }, /* subject */
- { SEC_ASN1_SKIP_REST },
- { 0 }
-};
-
-/*
- * Find the issuerName in a DER encoded certificate
- */
-const SEC_ASN1Template SEC_CertIssuerTemplate[] = {
- { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SECItem) },
- { SEC_ASN1_EXPLICIT | SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED |
- SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 0,
- 0, SEC_ASN1_SUB(SEC_SkipTemplate) }, /* version */
- { SEC_ASN1_SKIP }, /* serial number */
- { SEC_ASN1_SKIP }, /* signature algorithm */
- { SEC_ASN1_ANY, 0, NULL }, /* issuer */
- { SEC_ASN1_SKIP_REST },
- { 0 }
-};
-/*
- * Find the subjectName in a DER encoded certificate
- */
-const SEC_ASN1Template SEC_CertSerialNumberTemplate[] = {
- { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SECItem) },
- { SEC_ASN1_EXPLICIT | SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED |
- SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 0,
- 0, SEC_ASN1_SUB(SEC_SkipTemplate) }, /* version */
- { SEC_ASN1_ANY, 0, NULL }, /* serial number */
- { SEC_ASN1_SKIP_REST },
- { 0 }
-};
-
-/*
- * Find the issuer and serialNumber in a DER encoded certificate.
- * This data is used as the database lookup key since its the unique
- * identifier of a certificate.
- */
-const SEC_ASN1Template CERT_CertKeyTemplate[] = {
- { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CERTCertKey) },
- { SEC_ASN1_EXPLICIT | SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED |
- SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 0,
- 0, SEC_ASN1_SUB(SEC_SkipTemplate) }, /* version */
- { SEC_ASN1_INTEGER, offsetof(CERTCertKey, serialNumber) },
- { SEC_ASN1_SKIP }, /* signature algorithm */
- { SEC_ASN1_ANY, offsetof(CERTCertKey, derIssuer) },
- { SEC_ASN1_SKIP_REST },
- { 0 }
-};
-
-SEC_ASN1_CHOOSER_IMPLEMENT(CERT_TimeChoiceTemplate)
-SEC_ASN1_CHOOSER_IMPLEMENT(CERT_CertificateTemplate)
-SEC_ASN1_CHOOSER_IMPLEMENT(SEC_SignedCertificateTemplate)
-SEC_ASN1_CHOOSER_IMPLEMENT(CERT_SequenceOfCertExtensionTemplate)
-
-SECStatus
-CERT_KeyFromIssuerAndSN(PLArenaPool *arena, SECItem *issuer, SECItem *sn,
- SECItem *key)
-{
- key->len = sn->len + issuer->len;
-
- if ((sn->data == NULL) || (issuer->data == NULL)) {
- goto loser;
- }
-
- key->data = (unsigned char *)PORT_ArenaAlloc(arena, key->len);
- if (!key->data) {
- goto loser;
- }
-
- /* copy the serialNumber */
- PORT_Memcpy(key->data, sn->data, sn->len);
-
- /* copy the issuer */
- PORT_Memcpy(&key->data[sn->len], issuer->data, issuer->len);
-
- return (SECSuccess);
-
-loser:
- return (SECFailure);
-}
-
-/*
- * Extract the subject name from a DER certificate
- */
-SECStatus
-CERT_NameFromDERCert(SECItem *derCert, SECItem *derName)
-{
- int rv;
- PLArenaPool *arena;
- CERTSignedData sd;
- void *tmpptr;
-
- arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
-
- if (!arena) {
- return (SECFailure);
- }
-
- PORT_Memset(&sd, 0, sizeof(CERTSignedData));
- rv = SEC_QuickDERDecodeItem(arena, &sd, CERT_SignedDataTemplate, derCert);
-
- if (rv) {
- goto loser;
- }
-
- PORT_Memset(derName, 0, sizeof(SECItem));
- rv = SEC_QuickDERDecodeItem(arena, derName, SEC_CertSubjectTemplate,
- &sd.data);
-
- if (rv) {
- goto loser;
- }
-
- tmpptr = derName->data;
- derName->data = (unsigned char *)PORT_Alloc(derName->len);
- if (derName->data == NULL) {
- goto loser;
- }
-
- PORT_Memcpy(derName->data, tmpptr, derName->len);
-
- PORT_FreeArena(arena, PR_FALSE);
- return (SECSuccess);
-
-loser:
- PORT_FreeArena(arena, PR_FALSE);
- return (SECFailure);
-}
-
-SECStatus
-CERT_IssuerNameFromDERCert(SECItem *derCert, SECItem *derName)
-{
- int rv;
- PLArenaPool *arena;
- CERTSignedData sd;
- void *tmpptr;
-
- arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
-
- if (!arena) {
- return (SECFailure);
- }
-
- PORT_Memset(&sd, 0, sizeof(CERTSignedData));
- rv = SEC_QuickDERDecodeItem(arena, &sd, CERT_SignedDataTemplate, derCert);
-
- if (rv) {
- goto loser;
- }
-
- PORT_Memset(derName, 0, sizeof(SECItem));
- rv = SEC_QuickDERDecodeItem(arena, derName, SEC_CertIssuerTemplate,
- &sd.data);
-
- if (rv) {
- goto loser;
- }
-
- tmpptr = derName->data;
- derName->data = (unsigned char *)PORT_Alloc(derName->len);
- if (derName->data == NULL) {
- goto loser;
- }
-
- PORT_Memcpy(derName->data, tmpptr, derName->len);
-
- PORT_FreeArena(arena, PR_FALSE);
- return (SECSuccess);
-
-loser:
- PORT_FreeArena(arena, PR_FALSE);
- return (SECFailure);
-}
-
-SECStatus
-CERT_SerialNumberFromDERCert(SECItem *derCert, SECItem *derName)
-{
- int rv;
- PLArenaPool *arena;
- CERTSignedData sd;
- void *tmpptr;
-
- arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
-
- if (!arena) {
- return (SECFailure);
- }
-
- PORT_Memset(&sd, 0, sizeof(CERTSignedData));
- rv = SEC_QuickDERDecodeItem(arena, &sd, CERT_SignedDataTemplate, derCert);
-
- if (rv) {
- goto loser;
- }
-
- PORT_Memset(derName, 0, sizeof(SECItem));
- rv = SEC_QuickDERDecodeItem(arena, derName, SEC_CertSerialNumberTemplate,
- &sd.data);
-
- if (rv) {
- goto loser;
- }
-
- tmpptr = derName->data;
- derName->data = (unsigned char *)PORT_Alloc(derName->len);
- if (derName->data == NULL) {
- goto loser;
- }
-
- PORT_Memcpy(derName->data, tmpptr, derName->len);
-
- PORT_FreeArena(arena, PR_FALSE);
- return (SECSuccess);
-
-loser:
- PORT_FreeArena(arena, PR_FALSE);
- return (SECFailure);
-}
-
-/*
- * Generate a database key, based on serial number and issuer, from a
- * DER certificate.
- */
-SECStatus
-CERT_KeyFromDERCert(PLArenaPool *reqArena, SECItem *derCert, SECItem *key)
-{
- int rv;
- CERTSignedData sd;
- CERTCertKey certkey;
-
- if (!reqArena) {
- PORT_SetError(SEC_ERROR_INVALID_ARGS);
- return SECFailure;
- }
-
- PORT_Memset(&sd, 0, sizeof(CERTSignedData));
- rv =
- SEC_QuickDERDecodeItem(reqArena, &sd, CERT_SignedDataTemplate, derCert);
-
- if (rv) {
- goto loser;
- }
-
- PORT_Memset(&certkey, 0, sizeof(CERTCertKey));
- rv = SEC_QuickDERDecodeItem(reqArena, &certkey, CERT_CertKeyTemplate,
- &sd.data);
-
- if (rv) {
- goto loser;
- }
-
- return (CERT_KeyFromIssuerAndSN(reqArena, &certkey.derIssuer,
- &certkey.serialNumber, key));
-loser:
- return (SECFailure);
-}
-
-/*
- * fill in keyUsage field of the cert based on the cert extension
- * if the extension is not critical, then we allow all uses
- */
-static SECStatus
-GetKeyUsage(CERTCertificate *cert)
-{
- SECStatus rv;
- SECItem tmpitem;
-
- rv = CERT_FindKeyUsageExtension(cert, &tmpitem);
- if (rv == SECSuccess) {
- /* remember the actual value of the extension */
- cert->rawKeyUsage = tmpitem.data[0];
- cert->keyUsagePresent = PR_TRUE;
- cert->keyUsage = tmpitem.data[0];
-
- PORT_Free(tmpitem.data);
- tmpitem.data = NULL;
- } else {
- /* if the extension is not present, then we allow all uses */
- cert->keyUsage = KU_ALL;
- cert->rawKeyUsage = KU_ALL;
- cert->keyUsagePresent = PR_FALSE;
- }
-
- if (CERT_GovtApprovedBitSet(cert)) {
- cert->keyUsage |= KU_NS_GOVT_APPROVED;
- cert->rawKeyUsage |= KU_NS_GOVT_APPROVED;
- }
-
- return (SECSuccess);
-}
-
-static SECStatus
-findOIDinOIDSeqByTagNum(CERTOidSequence *seq, SECOidTag tagnum)
-{
- SECItem **oids;
- SECItem *oid;
- SECStatus rv = SECFailure;
-
- if (seq != NULL) {
- oids = seq->oids;
- while (oids != NULL && *oids != NULL) {
- oid = *oids;
- if (SECOID_FindOIDTag(oid) == tagnum) {
- rv = SECSuccess;
- break;
- }
- oids++;
- }
- }
- return rv;
-}
-
-/*
- * fill in nsCertType field of the cert based on the cert extension
- */
-SECStatus
-cert_GetCertType(CERTCertificate *cert)
-{
- PRUint32 nsCertType;
-
- if (cert->nsCertType) {
- /* once set, no need to recalculate */
- return SECSuccess;
- }
- nsCertType = cert_ComputeCertType(cert);
-
- /* Assert that it is safe to cast &cert->nsCertType to "PRInt32 *" */
- PORT_Assert(sizeof(cert->nsCertType) == sizeof(PRInt32));
- PR_ATOMIC_SET((PRInt32 *)&cert->nsCertType, nsCertType);
- return SECSuccess;
-}
-
-PRUint32
-cert_ComputeCertType(CERTCertificate *cert)
-{
- SECStatus rv;
- SECItem tmpitem;
- SECItem encodedExtKeyUsage;
- CERTOidSequence *extKeyUsage = NULL;
- PRBool basicConstraintPresent = PR_FALSE;
- CERTBasicConstraints basicConstraint;
- PRUint32 nsCertType = 0;
-
- tmpitem.data = NULL;
- CERT_FindNSCertTypeExtension(cert, &tmpitem);
- encodedExtKeyUsage.data = NULL;
- rv = CERT_FindCertExtension(cert, SEC_OID_X509_EXT_KEY_USAGE,
- &encodedExtKeyUsage);
- if (rv == SECSuccess) {
- extKeyUsage = CERT_DecodeOidSequence(&encodedExtKeyUsage);
- }
- rv = CERT_FindBasicConstraintExten(cert, &basicConstraint);
- if (rv == SECSuccess) {
- basicConstraintPresent = PR_TRUE;
- }
- if (tmpitem.data != NULL || extKeyUsage != NULL) {
- if (tmpitem.data == NULL) {
- nsCertType = 0;
- } else {
- nsCertType = tmpitem.data[0];
- }
-
- /* free tmpitem data pointer to avoid memory leak */
- PORT_Free(tmpitem.data);
- tmpitem.data = NULL;
-
- /*
- * for this release, we will allow SSL certs with an email address
- * to be used for email
- */
- if ((nsCertType & NS_CERT_TYPE_SSL_CLIENT) && cert->emailAddr &&
- cert->emailAddr[0]) {
- nsCertType |= NS_CERT_TYPE_EMAIL;
- }
- /*
- * for this release, we will allow SSL intermediate CAs to be
- * email intermediate CAs too.
- */
- if (nsCertType & NS_CERT_TYPE_SSL_CA) {
- nsCertType |= NS_CERT_TYPE_EMAIL_CA;
- }
- /*
- * allow a cert with the extended key usage of EMail Protect
- * to be used for email or as an email CA, if basic constraints
- * indicates that it is a CA.
- */
- if (findOIDinOIDSeqByTagNum(extKeyUsage,
- SEC_OID_EXT_KEY_USAGE_EMAIL_PROTECT) ==
- SECSuccess) {
- if (basicConstraintPresent == PR_TRUE && (basicConstraint.isCA)) {
- nsCertType |= NS_CERT_TYPE_EMAIL_CA;
- } else {
- nsCertType |= NS_CERT_TYPE_EMAIL;
- }
- }
- if (findOIDinOIDSeqByTagNum(
- extKeyUsage, SEC_OID_EXT_KEY_USAGE_SERVER_AUTH) == SECSuccess) {
- if (basicConstraintPresent == PR_TRUE && (basicConstraint.isCA)) {
- nsCertType |= NS_CERT_TYPE_SSL_CA;
- } else {
- nsCertType |= NS_CERT_TYPE_SSL_SERVER;
- }
- }
- /*
- * Treat certs with step-up OID as also having SSL server type.
- * COMODO needs this behaviour until June 2020. See Bug 737802.
- */
- if (findOIDinOIDSeqByTagNum(extKeyUsage,
- SEC_OID_NS_KEY_USAGE_GOVT_APPROVED) ==
- SECSuccess) {
- if (basicConstraintPresent == PR_TRUE && (basicConstraint.isCA)) {
- nsCertType |= NS_CERT_TYPE_SSL_CA;
- } else {
- nsCertType |= NS_CERT_TYPE_SSL_SERVER;
- }
- }
- if (findOIDinOIDSeqByTagNum(
- extKeyUsage, SEC_OID_EXT_KEY_USAGE_CLIENT_AUTH) == SECSuccess) {
- if (basicConstraintPresent == PR_TRUE && (basicConstraint.isCA)) {
- nsCertType |= NS_CERT_TYPE_SSL_CA;
- } else {
- nsCertType |= NS_CERT_TYPE_SSL_CLIENT;
- }
- }
- if (findOIDinOIDSeqByTagNum(
- extKeyUsage, SEC_OID_EXT_KEY_USAGE_CODE_SIGN) == SECSuccess) {
- if (basicConstraintPresent == PR_TRUE && (basicConstraint.isCA)) {
- nsCertType |= NS_CERT_TYPE_OBJECT_SIGNING_CA;
- } else {
- nsCertType |= NS_CERT_TYPE_OBJECT_SIGNING;
- }
- }
- if (findOIDinOIDSeqByTagNum(
- extKeyUsage, SEC_OID_EXT_KEY_USAGE_TIME_STAMP) == SECSuccess) {
- nsCertType |= EXT_KEY_USAGE_TIME_STAMP;
- }
- if (findOIDinOIDSeqByTagNum(extKeyUsage, SEC_OID_OCSP_RESPONDER) ==
- SECSuccess) {
- nsCertType |= EXT_KEY_USAGE_STATUS_RESPONDER;
- }
- } else {
- /* If no NS Cert Type extension and no EKU extension, then */
- nsCertType = 0;
- if (CERT_IsCACert(cert, &nsCertType))
- nsCertType |= EXT_KEY_USAGE_STATUS_RESPONDER;
- /* if the basic constraint extension says the cert is a CA, then
- allow SSL CA and EMAIL CA and Status Responder */
- if (basicConstraintPresent && basicConstraint.isCA) {
- nsCertType |= (NS_CERT_TYPE_SSL_CA | NS_CERT_TYPE_EMAIL_CA |
- EXT_KEY_USAGE_STATUS_RESPONDER);
- }
- /* allow any ssl or email (no ca or object signing. */
- nsCertType |= NS_CERT_TYPE_SSL_CLIENT | NS_CERT_TYPE_SSL_SERVER |
- NS_CERT_TYPE_EMAIL;
- }
-
- if (encodedExtKeyUsage.data != NULL) {
- PORT_Free(encodedExtKeyUsage.data);
- }
- if (extKeyUsage != NULL) {
- CERT_DestroyOidSequence(extKeyUsage);
- }
- return nsCertType;
-}
-
-/*
- * cert_GetKeyID() - extract or generate the subjectKeyID from a certificate
- */
-SECStatus
-cert_GetKeyID(CERTCertificate *cert)
-{
- SECItem tmpitem;
- SECStatus rv;
-
- cert->subjectKeyID.len = 0;
-
- /* see of the cert has a key identifier extension */
- rv = CERT_FindSubjectKeyIDExtension(cert, &tmpitem);
- if (rv == SECSuccess) {
- cert->subjectKeyID.data =
- (unsigned char *)PORT_ArenaAlloc(cert->arena, tmpitem.len);
- if (cert->subjectKeyID.data != NULL) {
- PORT_Memcpy(cert->subjectKeyID.data, tmpitem.data, tmpitem.len);
- cert->subjectKeyID.len = tmpitem.len;
- cert->keyIDGenerated = PR_FALSE;
- }
-
- PORT_Free(tmpitem.data);
- }
-
- /* if the cert doesn't have a key identifier extension, then generate one*/
- if (cert->subjectKeyID.len == 0) {
- /*
- * pkix says that if the subjectKeyID is not present, then we should
- * use the SHA-1 hash of the DER-encoded publicKeyInfo from the cert
- */
- cert->subjectKeyID.data =
- (unsigned char *)PORT_ArenaAlloc(cert->arena, SHA1_LENGTH);
- if (cert->subjectKeyID.data != NULL) {
- rv = PK11_HashBuf(SEC_OID_SHA1, cert->subjectKeyID.data,
- cert->derPublicKey.data, cert->derPublicKey.len);
- if (rv == SECSuccess) {
- cert->subjectKeyID.len = SHA1_LENGTH;
- }
- }
- }
-
- if (cert->subjectKeyID.len == 0) {
- return (SECFailure);
- }
- return (SECSuccess);
-}
-
-static PRBool
-cert_IsRootCert(CERTCertificate *cert)
-{
- SECStatus rv;
- SECItem tmpitem;
-
- /* cache the authKeyID extension, if present */
- cert->authKeyID = CERT_FindAuthKeyIDExten(cert->arena, cert);
-
- /* it MUST be self-issued to be a root */
- if (cert->derIssuer.len == 0 ||
- !SECITEM_ItemsAreEqual(&cert->derIssuer, &cert->derSubject)) {
- return PR_FALSE;
- }
-
- /* check the authKeyID extension */
- if (cert->authKeyID) {
- /* authority key identifier is present */
- if (cert->authKeyID->keyID.len > 0) {
- /* the keyIdentifier field is set, look for subjectKeyID */
- rv = CERT_FindSubjectKeyIDExtension(cert, &tmpitem);
- if (rv == SECSuccess) {
- PRBool match;
- /* also present, they MUST match for it to be a root */
- match =
- SECITEM_ItemsAreEqual(&cert->authKeyID->keyID, &tmpitem);
- PORT_Free(tmpitem.data);
- if (!match)
- return PR_FALSE; /* else fall through */
- } else {
- /* the subject key ID is required when AKI is present */
- return PR_FALSE;
- }
- }
- if (cert->authKeyID->authCertIssuer) {
- SECItem *caName;
- caName = (SECItem *)CERT_GetGeneralNameByType(
- cert->authKeyID->authCertIssuer, certDirectoryName, PR_TRUE);
- if (caName) {
- if (!SECITEM_ItemsAreEqual(&cert->derIssuer, caName)) {
- return PR_FALSE;
- } /* else fall through */
- } /* else ??? could not get general name as directory name? */
- }
- if (cert->authKeyID->authCertSerialNumber.len > 0) {
- if (!SECITEM_ItemsAreEqual(
- &cert->serialNumber,
- &cert->authKeyID->authCertSerialNumber)) {
- return PR_FALSE;
- } /* else fall through */
- }
- /* all of the AKI fields that were present passed the test */
- return PR_TRUE;
- }
- /* else the AKI was not present, so this is a root */
- return PR_TRUE;
-}
-
-/*
- * take a DER certificate and decode it into a certificate structure
- */
-CERTCertificate *
-CERT_DecodeDERCertificate(SECItem *derSignedCert, PRBool copyDER,
- char *nickname)
-{
- CERTCertificate *cert;
- PLArenaPool *arena;
- void *data;
- int rv;
- int len;
- char *tmpname;
-
- /* make a new arena */
- arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
-
- if (!arena) {
- return 0;
- }
-
- /* allocate the certificate structure */
- cert = (CERTCertificate *)PORT_ArenaZAlloc(arena, sizeof(CERTCertificate));
-
- if (!cert) {
- goto loser;
- }
-
- cert->arena = arena;
-
- if (copyDER) {
- /* copy the DER data for the cert into this arena */
- data = (void *)PORT_ArenaAlloc(arena, derSignedCert->len);
- if (!data) {
- goto loser;
- }
- cert->derCert.data = (unsigned char *)data;
- cert->derCert.len = derSignedCert->len;
- PORT_Memcpy(data, derSignedCert->data, derSignedCert->len);
- } else {
- /* point to passed in DER data */
- cert->derCert = *derSignedCert;
- }
-
- /* decode the certificate info */
- rv = SEC_QuickDERDecodeItem(arena, cert, SEC_SignedCertificateTemplate,
- &cert->derCert);
-
- if (rv) {
- goto loser;
- }
-
- if (cert_HasUnknownCriticalExten(cert->extensions) == PR_TRUE) {
- cert->options.bits.hasUnsupportedCriticalExt = PR_TRUE;
- }
-
- /* generate and save the database key for the cert */
- rv = CERT_KeyFromIssuerAndSN(arena, &cert->derIssuer, &cert->serialNumber,
- &cert->certKey);
- if (rv) {
- goto loser;
- }
-
- /* set the nickname */
- if (nickname == NULL) {
- cert->nickname = NULL;
- } else {
- /* copy and install the nickname */
- len = PORT_Strlen(nickname) + 1;
- cert->nickname = (char *)PORT_ArenaAlloc(arena, len);
- if (cert->nickname == NULL) {
- goto loser;
- }
-
- PORT_Memcpy(cert->nickname, nickname, len);
- }
-
- /* set the email address */
- cert->emailAddr = cert_GetCertificateEmailAddresses(cert);
-
- /* initialize the subjectKeyID */
- rv = cert_GetKeyID(cert);
- if (rv != SECSuccess) {
- goto loser;
- }
-
- /* initialize keyUsage */
- rv = GetKeyUsage(cert);
- if (rv != SECSuccess) {
- goto loser;
- }
-
- /* determine if this is a root cert */
- cert->isRoot = cert_IsRootCert(cert);
-
- /* initialize the certType */
- rv = cert_GetCertType(cert);
- if (rv != SECSuccess) {
- goto loser;
- }
-
- tmpname = CERT_NameToAscii(&cert->subject);
- if (tmpname != NULL) {
- cert->subjectName = PORT_ArenaStrdup(cert->arena, tmpname);
- PORT_Free(tmpname);
- }
-
- tmpname = CERT_NameToAscii(&cert->issuer);
- if (tmpname != NULL) {
- cert->issuerName = PORT_ArenaStrdup(cert->arena, tmpname);
- PORT_Free(tmpname);
- }
-
- cert->referenceCount = 1;
- cert->slot = NULL;
- cert->pkcs11ID = CK_INVALID_HANDLE;
- cert->dbnickname = NULL;
-
- return (cert);
-
-loser:
-
- if (arena) {
- PORT_FreeArena(arena, PR_FALSE);
- }
-
- return (0);
-}
-
-CERTCertificate *
-__CERT_DecodeDERCertificate(SECItem *derSignedCert, PRBool copyDER,
- char *nickname)
-{
- return CERT_DecodeDERCertificate(derSignedCert, copyDER, nickname);
-}
-
-CERTValidity *
-CERT_CreateValidity(PRTime notBefore, PRTime notAfter)
-{
- CERTValidity *v;
- int rv;
- PLArenaPool *arena;
-
- if (notBefore > notAfter) {
- PORT_SetError(SEC_ERROR_INVALID_ARGS);
- return NULL;
- }
- arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
-
- if (!arena) {
- return (0);
- }
-
- v = (CERTValidity *)PORT_ArenaZAlloc(arena, sizeof(CERTValidity));
- if (v) {
- v->arena = arena;
- rv = DER_EncodeTimeChoice(arena, &v->notBefore, notBefore);
- if (rv)
- goto loser;
- rv = DER_EncodeTimeChoice(arena, &v->notAfter, notAfter);
- if (rv)
- goto loser;
- }
- return v;
-
-loser:
- CERT_DestroyValidity(v);
- return 0;
-}
-
-SECStatus
-CERT_CopyValidity(PLArenaPool *arena, CERTValidity *to, CERTValidity *from)
-{
- SECStatus rv;
-
- CERT_DestroyValidity(to);
- to->arena = arena;
-
- rv = SECITEM_CopyItem(arena, &to->notBefore, &from->notBefore);
- if (rv)
- return rv;
- rv = SECITEM_CopyItem(arena, &to->notAfter, &from->notAfter);
- return rv;
-}
-
-void
-CERT_DestroyValidity(CERTValidity *v)
-{
- if (v && v->arena) {
- PORT_FreeArena(v->arena, PR_FALSE);
- }
- return;
-}
-
-/*
-** Amount of time that a certifiate is allowed good before it is actually
-** good. This is used for pending certificates, ones that are about to be
-** valid. The slop is designed to allow for some variance in the clocks
-** of the machine checking the certificate.
-*/
-#define PENDING_SLOP (24L * 60L * 60L) /* seconds per day */
-static PRInt32 pendingSlop = PENDING_SLOP; /* seconds */
-
-PRInt32
-CERT_GetSlopTime(void)
-{
- return pendingSlop; /* seconds */
-}
-
-SECStatus CERT_SetSlopTime(PRInt32 slop) /* seconds */
-{
- if (slop < 0)
- return SECFailure;
- pendingSlop = slop;
- return SECSuccess;
-}
-
-SECStatus
-CERT_GetCertTimes(const CERTCertificate *c, PRTime *notBefore, PRTime *notAfter)
-{
- SECStatus rv;
-
- if (!c || !notBefore || !notAfter) {
- PORT_SetError(SEC_ERROR_INVALID_ARGS);
- return SECFailure;
- }
-
- /* convert DER not-before time */
- rv = DER_DecodeTimeChoice(notBefore, &c->validity.notBefore);
- if (rv) {
- return (SECFailure);
- }
-
- /* convert DER not-after time */
- rv = DER_DecodeTimeChoice(notAfter, &c->validity.notAfter);
- if (rv) {
- return (SECFailure);
- }
-
- return (SECSuccess);
-}
-
-/*
- * Check the validity times of a certificate
- */
-SECCertTimeValidity
-CERT_CheckCertValidTimes(const CERTCertificate *c, PRTime t,
- PRBool allowOverride)
-{
- PRTime notBefore, notAfter, llPendingSlop, tmp1;
- SECStatus rv;
-
- if (!c) {
- PORT_SetError(SEC_ERROR_INVALID_ARGS);
- return (secCertTimeUndetermined);
- }
- /* if cert is already marked OK, then don't bother to check */
- if (allowOverride && c->timeOK) {
- return (secCertTimeValid);
- }
-
- rv = CERT_GetCertTimes(c, &notBefore, &notAfter);
-
- if (rv) {
- return (secCertTimeExpired); /*XXX is this the right thing to do here?*/
- }
-
- LL_I2L(llPendingSlop, pendingSlop);
- /* convert to micro seconds */
- LL_UI2L(tmp1, PR_USEC_PER_SEC);
- LL_MUL(llPendingSlop, llPendingSlop, tmp1);
- LL_SUB(notBefore, notBefore, llPendingSlop);
- if (LL_CMP(t, <, notBefore)) {
- PORT_SetError(SEC_ERROR_EXPIRED_CERTIFICATE);
- return (secCertTimeNotValidYet);
- }
- if (LL_CMP(t, >, notAfter)) {
- PORT_SetError(SEC_ERROR_EXPIRED_CERTIFICATE);
- return (secCertTimeExpired);
- }
-
- return (secCertTimeValid);
-}
-
-SECStatus
-SEC_GetCrlTimes(CERTCrl *date, PRTime *notBefore, PRTime *notAfter)
-{
- int rv;
-
- /* convert DER not-before time */
- rv = DER_DecodeTimeChoice(notBefore, &date->lastUpdate);
- if (rv) {
- return (SECFailure);
- }
-
- /* convert DER not-after time */
- if (date->nextUpdate.data) {
- rv = DER_DecodeTimeChoice(notAfter, &date->nextUpdate);
- if (rv) {
- return (SECFailure);
- }
- } else {
- LL_I2L(*notAfter, 0L);
- }
- return (SECSuccess);
-}
-
-/* These routines should probably be combined with the cert
- * routines using an common extraction routine.
- */
-SECCertTimeValidity
-SEC_CheckCrlTimes(CERTCrl *crl, PRTime t)
-{
- PRTime notBefore, notAfter, llPendingSlop, tmp1;
- SECStatus rv;
-
- if (!crl) {
- PORT_SetError(SEC_ERROR_INVALID_ARGS);
- return (secCertTimeUndetermined);
- }
-
- rv = SEC_GetCrlTimes(crl, &notBefore, &notAfter);
-
- if (rv) {
- return (secCertTimeExpired);
- }
-
- LL_I2L(llPendingSlop, pendingSlop);
- /* convert to micro seconds */
- LL_I2L(tmp1, PR_USEC_PER_SEC);
- LL_MUL(llPendingSlop, llPendingSlop, tmp1);
- LL_SUB(notBefore, notBefore, llPendingSlop);
- if (LL_CMP(t, <, notBefore)) {
- PORT_SetError(SEC_ERROR_CRL_EXPIRED);
- return (secCertTimeNotValidYet);
- }
-
- /* If next update is omitted and the test for notBefore passes, then
- we assume that the crl is up to date.
- */
- if (LL_IS_ZERO(notAfter)) {
- return (secCertTimeValid);
- }
-
- if (LL_CMP(t, >, notAfter)) {
- PORT_SetError(SEC_ERROR_CRL_EXPIRED);
- return (secCertTimeExpired);
- }
-
- return (secCertTimeValid);
-}
-
-PRBool
-SEC_CrlIsNewer(CERTCrl *inNew, CERTCrl *old)
-{
- PRTime newNotBefore, newNotAfter;
- PRTime oldNotBefore, oldNotAfter;
- SECStatus rv;
-
- /* problems with the new CRL? reject it */
- rv = SEC_GetCrlTimes(inNew, &newNotBefore, &newNotAfter);
- if (rv)
- return PR_FALSE;
-
- /* problems with the old CRL? replace it */
- rv = SEC_GetCrlTimes(old, &oldNotBefore, &oldNotAfter);
- if (rv)
- return PR_TRUE;
-
- /* Question: what about the notAfter's? */
- return ((PRBool)LL_CMP(oldNotBefore, <, newNotBefore));
-}
-
-/*
- * return required key usage and cert type based on cert usage
- */
-SECStatus
-CERT_KeyUsageAndTypeForCertUsage(SECCertUsage usage, PRBool ca,
- unsigned int *retKeyUsage,
- unsigned int *retCertType)
-{
- unsigned int requiredKeyUsage = 0;
- unsigned int requiredCertType = 0;
-
- if (ca) {
- switch (usage) {
- case certUsageSSLServerWithStepUp:
- requiredKeyUsage = KU_NS_GOVT_APPROVED | KU_KEY_CERT_SIGN;
- requiredCertType = NS_CERT_TYPE_SSL_CA;
- break;
- case certUsageSSLClient:
- requiredKeyUsage = KU_KEY_CERT_SIGN;
- requiredCertType = NS_CERT_TYPE_SSL_CA;
- break;
- case certUsageSSLServer:
- requiredKeyUsage = KU_KEY_CERT_SIGN;
- requiredCertType = NS_CERT_TYPE_SSL_CA;
- break;
- case certUsageSSLCA:
- requiredKeyUsage = KU_KEY_CERT_SIGN;
- requiredCertType = NS_CERT_TYPE_SSL_CA;
- break;
- case certUsageEmailSigner:
- requiredKeyUsage = KU_KEY_CERT_SIGN;
- requiredCertType = NS_CERT_TYPE_EMAIL_CA;
- break;
- case certUsageEmailRecipient:
- requiredKeyUsage = KU_KEY_CERT_SIGN;
- requiredCertType = NS_CERT_TYPE_EMAIL_CA;
- break;
- case certUsageObjectSigner:
- requiredKeyUsage = KU_KEY_CERT_SIGN;
- requiredCertType = NS_CERT_TYPE_OBJECT_SIGNING_CA;
- break;
- case certUsageAnyCA:
- case certUsageVerifyCA:
- case certUsageStatusResponder:
- requiredKeyUsage = KU_KEY_CERT_SIGN;
- requiredCertType = NS_CERT_TYPE_OBJECT_SIGNING_CA |
- NS_CERT_TYPE_EMAIL_CA | NS_CERT_TYPE_SSL_CA;
- break;
- default:
- PORT_Assert(0);
- goto loser;
- }
- } else {
- switch (usage) {
- case certUsageSSLClient:
- /*
- * RFC 5280 lists digitalSignature and keyAgreement for
- * id-kp-clientAuth. NSS does not support the *_fixed_dh and
- * *_fixed_ecdh client certificate types.
- */
- requiredKeyUsage = KU_DIGITAL_SIGNATURE;
- requiredCertType = NS_CERT_TYPE_SSL_CLIENT;
- break;
- case certUsageSSLServer:
- requiredKeyUsage = KU_KEY_AGREEMENT_OR_ENCIPHERMENT;
- requiredCertType = NS_CERT_TYPE_SSL_SERVER;
- break;
- case certUsageSSLServerWithStepUp:
- requiredKeyUsage =
- KU_KEY_AGREEMENT_OR_ENCIPHERMENT | KU_NS_GOVT_APPROVED;
- requiredCertType = NS_CERT_TYPE_SSL_SERVER;
- break;
- case certUsageSSLCA:
- requiredKeyUsage = KU_KEY_CERT_SIGN;
- requiredCertType = NS_CERT_TYPE_SSL_CA;
- break;
- case certUsageEmailSigner:
- requiredKeyUsage = KU_DIGITAL_SIGNATURE_OR_NON_REPUDIATION;
- requiredCertType = NS_CERT_TYPE_EMAIL;
- break;
- case certUsageEmailRecipient:
- requiredKeyUsage = KU_KEY_AGREEMENT_OR_ENCIPHERMENT;
- requiredCertType = NS_CERT_TYPE_EMAIL;
- break;
- case certUsageObjectSigner:
- /* RFC 5280 lists only digitalSignature for id-kp-codeSigning.
- */
- requiredKeyUsage = KU_DIGITAL_SIGNATURE;
- requiredCertType = NS_CERT_TYPE_OBJECT_SIGNING;
- break;
- case certUsageStatusResponder:
- requiredKeyUsage = KU_DIGITAL_SIGNATURE_OR_NON_REPUDIATION;
- requiredCertType = EXT_KEY_USAGE_STATUS_RESPONDER;
- break;
- default:
- PORT_Assert(0);
- goto loser;
- }
- }
-
- if (retKeyUsage != NULL) {
- *retKeyUsage = requiredKeyUsage;
- }
- if (retCertType != NULL) {
- *retCertType = requiredCertType;
- }
-
- return (SECSuccess);
-loser:
- return (SECFailure);
-}
-
-/*
- * check the key usage of a cert against a set of required values
- */
-SECStatus
-CERT_CheckKeyUsage(CERTCertificate *cert, unsigned int requiredUsage)
-{
- if (!cert) {
- PORT_SetError(SEC_ERROR_INVALID_ARGS);
- return SECFailure;
- }
- /* choose between key agreement or key encipherment based on key
- * type in cert
- */
- if (requiredUsage & KU_KEY_AGREEMENT_OR_ENCIPHERMENT) {
- KeyType keyType = CERT_GetCertKeyType(&cert->subjectPublicKeyInfo);
- /* turn off the special bit */
- requiredUsage &= (~KU_KEY_AGREEMENT_OR_ENCIPHERMENT);
-
- switch (keyType) {
- case rsaKey:
- requiredUsage |= KU_KEY_ENCIPHERMENT;
- break;
- case dsaKey:
- requiredUsage |= KU_DIGITAL_SIGNATURE;
- break;
- case dhKey:
- requiredUsage |= KU_KEY_AGREEMENT;
- break;
- case ecKey:
- /* Accept either signature or agreement. */
- if (!(cert->keyUsage &
- (KU_DIGITAL_SIGNATURE | KU_KEY_AGREEMENT)))
- goto loser;
- break;
- default:
- goto loser;
- }
- }
-
- /* Allow either digital signature or non-repudiation */
- if (requiredUsage & KU_DIGITAL_SIGNATURE_OR_NON_REPUDIATION) {
- /* turn off the special bit */
- requiredUsage &= (~KU_DIGITAL_SIGNATURE_OR_NON_REPUDIATION);
-
- if (!(cert->keyUsage & (KU_DIGITAL_SIGNATURE | KU_NON_REPUDIATION)))
- goto loser;
- }
-
- if ((cert->keyUsage & requiredUsage) == requiredUsage)
- return SECSuccess;
-
-loser:
- PORT_SetError(SEC_ERROR_INADEQUATE_KEY_USAGE);
- return SECFailure;
-}
-
-CERTCertificate *
-CERT_DupCertificate(CERTCertificate *c)
-{
- if (c) {
- NSSCertificate *tmp = STAN_GetNSSCertificate(c);
- nssCertificate_AddRef(tmp);
- }
- return c;
-}
-
-/*
- * Allow use of default cert database, so that apps(such as mozilla) don't
- * have to pass the handle all over the place.
- */
-static CERTCertDBHandle *default_cert_db_handle = 0;
-
-void
-CERT_SetDefaultCertDB(CERTCertDBHandle *handle)
-{
- default_cert_db_handle = handle;
-
- return;
-}
-
-CERTCertDBHandle *
-CERT_GetDefaultCertDB(void)
-{
- return (default_cert_db_handle);
-}
-
-/* XXX this would probably be okay/better as an xp routine? */
-static void
-sec_lower_string(char *s)
-{
- if (s == NULL) {
- return;
- }
-
- while (*s) {
- *s = PORT_Tolower(*s);
- s++;
- }
-
- return;
-}
-
-static PRBool
-cert_IsIPAddr(const char *hn)
-{
- PRBool isIPaddr = PR_FALSE;
- PRNetAddr netAddr;
- isIPaddr = (PR_SUCCESS == PR_StringToNetAddr(hn, &netAddr));
- return isIPaddr;
-}
-
-/*
-** Add a domain name to the list of names that the user has explicitly
-** allowed (despite cert name mismatches) for use with a server cert.
-*/
-SECStatus
-CERT_AddOKDomainName(CERTCertificate *cert, const char *hn)
-{
- CERTOKDomainName *domainOK;
- int newNameLen;
-
- if (!hn || !(newNameLen = strlen(hn))) {
- PORT_SetError(SEC_ERROR_INVALID_ARGS);
- return SECFailure;
- }
- domainOK = (CERTOKDomainName *)PORT_ArenaZAlloc(
- cert->arena, (sizeof *domainOK) + newNameLen);
- if (!domainOK)
- return SECFailure; /* error code is already set. */
-
- PORT_Strcpy(domainOK->name, hn);
- sec_lower_string(domainOK->name);
-
- /* put at head of list. */
- domainOK->next = cert->domainOK;
- cert->domainOK = domainOK;
- return SECSuccess;
-}
-
-/* returns SECSuccess if hn matches pattern cn,
-** returns SECFailure with SSL_ERROR_BAD_CERT_DOMAIN if no match,
-** returns SECFailure with some other error code if another error occurs.
-**
-** This function may modify string cn, so caller must pass a modifiable copy.
-*/
-static SECStatus
-cert_TestHostName(char *cn, const char *hn)
-{
- static int useShellExp = -1;
-
- if (useShellExp < 0) {
- useShellExp = (NULL != PR_GetEnvSecure("NSS_USE_SHEXP_IN_CERT_NAME"));
- }
- if (useShellExp) {
- /* Backward compatible code, uses Shell Expressions (SHEXP). */
- int regvalid = PORT_RegExpValid(cn);
- if (regvalid != NON_SXP) {
- SECStatus rv;
- /* cn is a regular expression, try to match the shexp */
- int match = PORT_RegExpCaseSearch(hn, cn);
-
- if (match == 0) {
- rv = SECSuccess;
- } else {
- PORT_SetError(SSL_ERROR_BAD_CERT_DOMAIN);
- rv = SECFailure;
- }
- return rv;
- }
- } else {
- /* New approach conforms to RFC 6125. */
- char *wildcard = PORT_Strchr(cn, '*');
- char *firstcndot = PORT_Strchr(cn, '.');
- char *secondcndot =
- firstcndot ? PORT_Strchr(firstcndot + 1, '.') : NULL;
- char *firsthndot = PORT_Strchr(hn, '.');
-
- /* For a cn pattern to be considered valid, the wildcard character...
- * - may occur only in a DNS name with at least 3 components, and
- * - may occur only as last character in the first component, and
- * - may be preceded by additional characters, and
- * - must not be preceded by an IDNA ACE prefix (xn--)
- */
- if (wildcard && secondcndot && secondcndot[1] && firsthndot &&
- firstcndot - wildcard == 1 /* wildcard is last char in first component */
- && secondcndot - firstcndot > 1 /* second component is non-empty */
- && PORT_Strrchr(cn, '*') == wildcard /* only one wildcard in cn */
- && !PORT_Strncasecmp(cn, hn, wildcard - cn) &&
- !PORT_Strcasecmp(firstcndot, firsthndot)
- /* If hn starts with xn--, then cn must start with wildcard */
- && (PORT_Strncasecmp(hn, "xn--", 4) || wildcard == cn)) {
- /* valid wildcard pattern match */
- return SECSuccess;
- }
- }
- /* String cn has no wildcard or shell expression.
- * Compare entire string hn with cert name.
- */
- if (PORT_Strcasecmp(hn, cn) == 0) {
- return SECSuccess;
- }
-
- PORT_SetError(SSL_ERROR_BAD_CERT_DOMAIN);
- return SECFailure;
-}
-
-SECStatus
-cert_VerifySubjectAltName(const CERTCertificate *cert, const char *hn)
-{
- PLArenaPool *arena = NULL;
- CERTGeneralName *nameList = NULL;
- CERTGeneralName *current;
- char *cn;
- int cnBufLen;
- int DNSextCount = 0;
- int IPextCount = 0;
- PRBool isIPaddr = PR_FALSE;
- SECStatus rv = SECFailure;
- SECItem subAltName;
- PRNetAddr netAddr;
- char cnbuf[128];
-
- subAltName.data = NULL;
- cn = cnbuf;
- cnBufLen = sizeof cnbuf;
-
- rv = CERT_FindCertExtension(cert, SEC_OID_X509_SUBJECT_ALT_NAME,
- &subAltName);
- if (rv != SECSuccess) {
- goto fail;
- }
- isIPaddr = (PR_SUCCESS == PR_StringToNetAddr(hn, &netAddr));
- rv = SECFailure;
- arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
- if (!arena)
- goto fail;
-
- nameList = current = CERT_DecodeAltNameExtension(arena, &subAltName);
- if (!current)
- goto fail;
-
- do {
- switch (current->type) {
- case certDNSName:
- if (!isIPaddr) {
- /* DNS name current->name.other.data is not null terminated.
- ** so must copy it.
- */
- int cnLen = current->name.other.len;
- rv = CERT_RFC1485_EscapeAndQuote(
- cn, cnBufLen, (char *)current->name.other.data, cnLen);
- if (rv != SECSuccess &&
- PORT_GetError() == SEC_ERROR_OUTPUT_LEN) {
- cnBufLen =
- cnLen * 3 + 3; /* big enough for worst case */
- cn = (char *)PORT_ArenaAlloc(arena, cnBufLen);
- if (!cn)
- goto fail;
- rv = CERT_RFC1485_EscapeAndQuote(
- cn, cnBufLen, (char *)current->name.other.data,
- cnLen);
- }
- if (rv == SECSuccess)
- rv = cert_TestHostName(cn, hn);
- if (rv == SECSuccess)
- goto finish;
- }
- DNSextCount++;
- break;
- case certIPAddress:
- if (isIPaddr) {
- int match = 0;
- PRIPv6Addr v6Addr;
- if (current->name.other.len == 4 && /* IP v4 address */
- netAddr.inet.family == PR_AF_INET) {
- match = !memcmp(&netAddr.inet.ip,
- current->name.other.data, 4);
- } else if (current->name.other.len ==
- 16 && /* IP v6 address */
- netAddr.ipv6.family == PR_AF_INET6) {
- match = !memcmp(&netAddr.ipv6.ip,
- current->name.other.data, 16);
- } else if (current->name.other.len ==
- 16 && /* IP v6 address */
- netAddr.inet.family == PR_AF_INET) {
- /* convert netAddr to ipv6, then compare. */
- /* ipv4 must be in Network Byte Order on input. */
- PR_ConvertIPv4AddrToIPv6(netAddr.inet.ip, &v6Addr);
- match = !memcmp(&v6Addr, current->name.other.data, 16);
- } else if (current->name.other.len == 4 && /* IP v4 address */
- netAddr.inet.family == PR_AF_INET6) {
- /* convert netAddr to ipv6, then compare. */
- PRUint32 ipv4 = (current->name.other.data[0] << 24) |
- (current->name.other.data[1] << 16) |
- (current->name.other.data[2] << 8) |
- current->name.other.data[3];
- /* ipv4 must be in Network Byte Order on input. */
- PR_ConvertIPv4AddrToIPv6(PR_htonl(ipv4), &v6Addr);
- match = !memcmp(&netAddr.ipv6.ip, &v6Addr, 16);
- }
- if (match) {
- rv = SECSuccess;
- goto finish;
- }
- }
- IPextCount++;
- break;
- default:
- break;
- }
- current = CERT_GetNextGeneralName(current);
- } while (current != nameList);
-
-fail:
-
- if (!(isIPaddr ? IPextCount : DNSextCount)) {
- /* no relevant value in the extension was found. */
- PORT_SetError(SEC_ERROR_EXTENSION_NOT_FOUND);
- } else {
- PORT_SetError(SSL_ERROR_BAD_CERT_DOMAIN);
- }
- rv = SECFailure;
-
-finish:
-
- /* Don't free nameList, it's part of the arena. */
- if (arena) {
- PORT_FreeArena(arena, PR_FALSE);
- }
-
- if (subAltName.data) {
- SECITEM_FreeItem(&subAltName, PR_FALSE);
- }
-
- return rv;
-}
-
-/*
- * If found:
- * - subAltName contains the extension (caller must free)
- * - return value is the decoded namelist (allocated off arena)
- * if not found, or if failure to decode:
- * - return value is NULL
- */
-CERTGeneralName *
-cert_GetSubjectAltNameList(const CERTCertificate *cert, PLArenaPool *arena)
-{
- CERTGeneralName *nameList = NULL;
- SECStatus rv = SECFailure;
- SECItem subAltName;
-
- if (!cert || !arena)
- return NULL;
-
- subAltName.data = NULL;
-
- rv = CERT_FindCertExtension(cert, SEC_OID_X509_SUBJECT_ALT_NAME,
- &subAltName);
- if (rv != SECSuccess)
- return NULL;
-
- nameList = CERT_DecodeAltNameExtension(arena, &subAltName);
- SECITEM_FreeItem(&subAltName, PR_FALSE);
- return nameList;
-}
-
-PRUint32
-cert_CountDNSPatterns(CERTGeneralName *firstName)
-{
- CERTGeneralName *current;
- PRUint32 count = 0;
-
- if (!firstName)
- return 0;
-
- current = firstName;
- do {
- switch (current->type) {
- case certDNSName:
- case certIPAddress:
- ++count;
- break;
- default:
- break;
- }
- current = CERT_GetNextGeneralName(current);
- } while (current != firstName);
-
- return count;
-}
-
-#ifndef INET6_ADDRSTRLEN
-#define INET6_ADDRSTRLEN 46
-#endif
-
-/* will fill nickNames,
- * will allocate all data from nickNames->arena,
- * numberOfGeneralNames should have been obtained from cert_CountDNSPatterns,
- * will ensure the numberOfGeneralNames matches the number of output entries.
- */
-SECStatus
-cert_GetDNSPatternsFromGeneralNames(CERTGeneralName *firstName,
- PRUint32 numberOfGeneralNames,
- CERTCertNicknames *nickNames)
-{
- CERTGeneralName *currentInput;
- char **currentOutput;
-
- if (!firstName || !nickNames || !numberOfGeneralNames)
- return SECFailure;
-
- nickNames->numnicknames = numberOfGeneralNames;
- nickNames->nicknames = PORT_ArenaAlloc(
- nickNames->arena, sizeof(char *) * numberOfGeneralNames);
- if (!nickNames->nicknames)
- return SECFailure;
-
- currentInput = firstName;
- currentOutput = nickNames->nicknames;
- do {
- char *cn = NULL;
- char ipbuf[INET6_ADDRSTRLEN];
- PRNetAddr addr;
-
- if (numberOfGeneralNames < 1) {
- /* internal consistency error */
- return SECFailure;
- }
-
- switch (currentInput->type) {
- case certDNSName:
- /* DNS name currentInput->name.other.data is not null
- *terminated.
- ** so must copy it.
- */
- cn = (char *)PORT_ArenaAlloc(nickNames->arena,
- currentInput->name.other.len + 1);
- if (!cn)
- return SECFailure;
- PORT_Memcpy(cn, currentInput->name.other.data,
- currentInput->name.other.len);
- cn[currentInput->name.other.len] = 0;
- break;
- case certIPAddress:
- if (currentInput->name.other.len == 4) {
- addr.inet.family = PR_AF_INET;
- memcpy(&addr.inet.ip, currentInput->name.other.data,
- currentInput->name.other.len);
- } else if (currentInput->name.other.len == 16) {
- addr.ipv6.family = PR_AF_INET6;
- memcpy(&addr.ipv6.ip, currentInput->name.other.data,
- currentInput->name.other.len);
- }
- if (PR_NetAddrToString(&addr, ipbuf, sizeof(ipbuf)) ==
- PR_FAILURE)
- return SECFailure;
- cn = PORT_ArenaStrdup(nickNames->arena, ipbuf);
- if (!cn)
- return SECFailure;
- break;
- default:
- break;
- }
- if (cn) {
- *currentOutput = cn;
- nickNames->totallen += PORT_Strlen(cn);
- ++currentOutput;
- --numberOfGeneralNames;
- }
- currentInput = CERT_GetNextGeneralName(currentInput);
- } while (currentInput != firstName);
-
- return (numberOfGeneralNames == 0) ? SECSuccess : SECFailure;
-}
-
-/*
- * Collect all valid DNS names from the given cert.
- * The output arena will reference some temporaray data,
- * but this saves us from dealing with two arenas.
- * The caller may free all data by freeing CERTCertNicknames->arena.
- */
-CERTCertNicknames *
-CERT_GetValidDNSPatternsFromCert(CERTCertificate *cert)
-{
- CERTGeneralName *generalNames;
- CERTCertNicknames *nickNames;
- PLArenaPool *arena;
- char *singleName;
-
- arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
- if (!arena) {
- return NULL;
- }
-
- nickNames = PORT_ArenaAlloc(arena, sizeof(CERTCertNicknames));
- if (!nickNames) {
- PORT_FreeArena(arena, PR_FALSE);
- return NULL;
- }
-
- /* init the structure */
- nickNames->arena = arena;
- nickNames->head = NULL;
- nickNames->numnicknames = 0;
- nickNames->nicknames = NULL;
- nickNames->totallen = 0;
-
- generalNames = cert_GetSubjectAltNameList(cert, arena);
- if (generalNames) {
- SECStatus rv_getnames = SECFailure;
- PRUint32 numNames = cert_CountDNSPatterns(generalNames);
-
- if (numNames) {
- rv_getnames = cert_GetDNSPatternsFromGeneralNames(
- generalNames, numNames, nickNames);
- }
-
- /* if there were names, we'll exit now, either with success or failure
- */
- if (numNames) {
- if (rv_getnames == SECSuccess) {
- return nickNames;
- }
-
- /* failure to produce output */
- PORT_FreeArena(arena, PR_FALSE);
- return NULL;
- }
- }
-
- /* no SAN extension or no names found in extension */
- singleName = CERT_GetCommonName(&cert->subject);
- if (singleName) {
- nickNames->numnicknames = 1;
- nickNames->nicknames = PORT_ArenaAlloc(arena, sizeof(char *));
- if (nickNames->nicknames) {
- *nickNames->nicknames = PORT_ArenaStrdup(arena, singleName);
- }
- PORT_Free(singleName);
-
- /* Did we allocate both the buffer of pointers and the string? */
- if (nickNames->nicknames && *nickNames->nicknames) {
- return nickNames;
- }
- }
-
- PORT_FreeArena(arena, PR_FALSE);
- return NULL;
-}
-
-/* Make sure that the name of the host we are connecting to matches the
- * name that is incoded in the common-name component of the certificate
- * that they are using.
- */
-SECStatus
-CERT_VerifyCertName(const CERTCertificate *cert, const char *hn)
-{
- char *cn;
- SECStatus rv;
- CERTOKDomainName *domainOK;
-
- if (!hn || !strlen(hn)) {
- PORT_SetError(SEC_ERROR_INVALID_ARGS);
- return SECFailure;
- }
-
- /* if the name is one that the user has already approved, it's OK. */
- for (domainOK = cert->domainOK; domainOK; domainOK = domainOK->next) {
- if (0 == PORT_Strcasecmp(hn, domainOK->name)) {
- return SECSuccess;
- }
- }
-
- /* Per RFC 2818, if the SubjectAltName extension is present, it must
- ** be used as the cert's identity.
- */
- rv = cert_VerifySubjectAltName(cert, hn);
- if (rv == SECSuccess || PORT_GetError() != SEC_ERROR_EXTENSION_NOT_FOUND)
- return rv;
-
- cn = CERT_GetCommonName(&cert->subject);
- if (cn) {
- PRBool isIPaddr = cert_IsIPAddr(hn);
- if (isIPaddr) {
- if (PORT_Strcasecmp(hn, cn) == 0) {
- rv = SECSuccess;
- } else {
- PORT_SetError(SSL_ERROR_BAD_CERT_DOMAIN);
- rv = SECFailure;
- }
- } else {
- rv = cert_TestHostName(cn, hn);
- }
- PORT_Free(cn);
- } else
- PORT_SetError(SSL_ERROR_BAD_CERT_DOMAIN);
- return rv;
-}
-
-PRBool
-CERT_CompareCerts(const CERTCertificate *c1, const CERTCertificate *c2)
-{
- SECComparison comp;
-
- comp = SECITEM_CompareItem(&c1->derCert, &c2->derCert);
- if (comp == SECEqual) { /* certs are the same */
- return (PR_TRUE);
- } else {
- return (PR_FALSE);
- }
-}
-
-static SECStatus
-StringsEqual(char *s1, char *s2)
-{
- if ((s1 == NULL) || (s2 == NULL)) {
- if (s1 != s2) { /* only one is null */
- return (SECFailure);
- }
- return (SECSuccess); /* both are null */
- }
-
- if (PORT_Strcmp(s1, s2) != 0) {
- return (SECFailure); /* not equal */
- }
-
- return (SECSuccess); /* strings are equal */
-}
-
-PRBool
-CERT_CompareCertsForRedirection(CERTCertificate *c1, CERTCertificate *c2)
-{
- SECComparison comp;
- char *c1str, *c2str;
- SECStatus eq;
-
- comp = SECITEM_CompareItem(&c1->derCert, &c2->derCert);
- if (comp == SECEqual) { /* certs are the same */
- return (PR_TRUE);
- }
-
- /* check if they are issued by the same CA */
- comp = SECITEM_CompareItem(&c1->derIssuer, &c2->derIssuer);
- if (comp != SECEqual) { /* different issuer */
- return (PR_FALSE);
- }
-
- /* check country name */
- c1str = CERT_GetCountryName(&c1->subject);
- c2str = CERT_GetCountryName(&c2->subject);
- eq = StringsEqual(c1str, c2str);
- PORT_Free(c1str);
- PORT_Free(c2str);
- if (eq != SECSuccess) {
- return (PR_FALSE);
- }
-
- /* check locality name */
- c1str = CERT_GetLocalityName(&c1->subject);
- c2str = CERT_GetLocalityName(&c2->subject);
- eq = StringsEqual(c1str, c2str);
- PORT_Free(c1str);
- PORT_Free(c2str);
- if (eq != SECSuccess) {
- return (PR_FALSE);
- }
-
- /* check state name */
- c1str = CERT_GetStateName(&c1->subject);
- c2str = CERT_GetStateName(&c2->subject);
- eq = StringsEqual(c1str, c2str);
- PORT_Free(c1str);
- PORT_Free(c2str);
- if (eq != SECSuccess) {
- return (PR_FALSE);
- }
-
- /* check org name */
- c1str = CERT_GetOrgName(&c1->subject);
- c2str = CERT_GetOrgName(&c2->subject);
- eq = StringsEqual(c1str, c2str);
- PORT_Free(c1str);
- PORT_Free(c2str);
- if (eq != SECSuccess) {
- return (PR_FALSE);
- }
-
-#ifdef NOTDEF
- /* check orgUnit name */
- /*
- * We need to revisit this and decide which fields should be allowed to be
- * different
- */
- c1str = CERT_GetOrgUnitName(&c1->subject);
- c2str = CERT_GetOrgUnitName(&c2->subject);
- eq = StringsEqual(c1str, c2str);
- PORT_Free(c1str);
- PORT_Free(c2str);
- if (eq != SECSuccess) {
- return (PR_FALSE);
- }
-#endif
-
- return (PR_TRUE); /* all fields but common name are the same */
-}
-
-/* CERT_CertChainFromCert and CERT_DestroyCertificateList moved
- to certhigh.c */
-
-CERTIssuerAndSN *
-CERT_GetCertIssuerAndSN(PLArenaPool *arena, CERTCertificate *cert)
-{
- CERTIssuerAndSN *result;
- SECStatus rv;
-
- if (arena == NULL) {
- arena = cert->arena;
- }
-
- result = (CERTIssuerAndSN *)PORT_ArenaZAlloc(arena, sizeof(*result));
- if (result == NULL) {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- return NULL;
- }
-
- rv = SECITEM_CopyItem(arena, &result->derIssuer, &cert->derIssuer);
- if (rv != SECSuccess)
- return NULL;
-
- rv = CERT_CopyName(arena, &result->issuer, &cert->issuer);
- if (rv != SECSuccess)
- return NULL;
-
- rv = SECITEM_CopyItem(arena, &result->serialNumber, &cert->serialNumber);
- if (rv != SECSuccess)
- return NULL;
-
- return result;
-}
-
-char *
-CERT_MakeCANickname(CERTCertificate *cert)
-{
- char *firstname = NULL;
- char *org = NULL;
- char *nickname = NULL;
- int count;
- CERTCertificate *dummycert;
-
- firstname = CERT_GetCommonName(&cert->subject);
- if (firstname == NULL) {
- firstname = CERT_GetOrgUnitName(&cert->subject);
- }
-
- org = CERT_GetOrgName(&cert->issuer);
- if (org == NULL) {
- org = CERT_GetDomainComponentName(&cert->issuer);
- if (org == NULL) {
- if (firstname) {
- org = firstname;
- firstname = NULL;
- } else {
- org = PORT_Strdup("Unknown CA");
- }
- }
- }
-
- /* can only fail if PORT_Strdup fails, in which case
- * we're having memory problems. */
- if (org == NULL) {
- goto done;
- }
-
- count = 1;
- while (1) {
-
- if (firstname) {
- if (count == 1) {
- nickname = PR_smprintf("%s - %s", firstname, org);
- } else {
- nickname = PR_smprintf("%s - %s #%d", firstname, org, count);
- }
- } else {
- if (count == 1) {
- nickname = PR_smprintf("%s", org);
- } else {
- nickname = PR_smprintf("%s #%d", org, count);
- }
- }
- if (nickname == NULL) {
- goto done;
- }
-
- /* look up the nickname to make sure it isn't in use already */
- dummycert = CERT_FindCertByNickname(cert->dbhandle, nickname);
-
- if (dummycert == NULL) {
- goto done;
- }
-
- /* found a cert, destroy it and loop */
- CERT_DestroyCertificate(dummycert);
-
- /* free the nickname */
- PORT_Free(nickname);
-
- count++;
- }
-
-done:
- if (firstname) {
- PORT_Free(firstname);
- }
- if (org) {
- PORT_Free(org);
- }
-
- return (nickname);
-}
-
-/* CERT_Import_CAChain moved to certhigh.c */
-
-void
-CERT_DestroyCrl(CERTSignedCrl *crl)
-{
- SEC_DestroyCrl(crl);
-}
-
-static int
-cert_Version(CERTCertificate *cert)
-{
- int version = 0;
- if (cert && cert->version.data && cert->version.len) {
- version = DER_GetInteger(&cert->version);
- if (version < 0)
- version = 0;
- }
- return version;
-}
-
-static unsigned int
-cert_ComputeTrustOverrides(CERTCertificate *cert, unsigned int cType)
-{
- CERTCertTrust trust;
- SECStatus rv = SECFailure;
-
- rv = CERT_GetCertTrust(cert, &trust);
-
- if (rv == SECSuccess &&
- (trust.sslFlags | trust.emailFlags | trust.objectSigningFlags)) {
-
- if (trust.sslFlags & (CERTDB_TERMINAL_RECORD | CERTDB_TRUSTED))
- cType |= NS_CERT_TYPE_SSL_SERVER | NS_CERT_TYPE_SSL_CLIENT;
- if (trust.sslFlags & (CERTDB_VALID_CA | CERTDB_TRUSTED_CA))
- cType |= NS_CERT_TYPE_SSL_CA;
-#if defined(CERTDB_NOT_TRUSTED)
- if (trust.sslFlags & CERTDB_NOT_TRUSTED)
- cType &= ~(NS_CERT_TYPE_SSL_SERVER | NS_CERT_TYPE_SSL_CLIENT |
- NS_CERT_TYPE_SSL_CA);
-#endif
- if (trust.emailFlags & (CERTDB_TERMINAL_RECORD | CERTDB_TRUSTED))
- cType |= NS_CERT_TYPE_EMAIL;
- if (trust.emailFlags & (CERTDB_VALID_CA | CERTDB_TRUSTED_CA))
- cType |= NS_CERT_TYPE_EMAIL_CA;
-#if defined(CERTDB_NOT_TRUSTED)
- if (trust.emailFlags & CERTDB_NOT_TRUSTED)
- cType &= ~(NS_CERT_TYPE_EMAIL | NS_CERT_TYPE_EMAIL_CA);
-#endif
- if (trust.objectSigningFlags &
- (CERTDB_TERMINAL_RECORD | CERTDB_TRUSTED))
- cType |= NS_CERT_TYPE_OBJECT_SIGNING;
- if (trust.objectSigningFlags & (CERTDB_VALID_CA | CERTDB_TRUSTED_CA))
- cType |= NS_CERT_TYPE_OBJECT_SIGNING_CA;
-#if defined(CERTDB_NOT_TRUSTED)
- if (trust.objectSigningFlags & CERTDB_NOT_TRUSTED)
- cType &=
- ~(NS_CERT_TYPE_OBJECT_SIGNING | NS_CERT_TYPE_OBJECT_SIGNING_CA);
-#endif
- }
- return cType;
-}
-
-/*
- * Does a cert belong to a CA? We decide based on perm database trust
- * flags, Netscape Cert Type Extension, and KeyUsage Extension.
- */
-PRBool
-CERT_IsCACert(CERTCertificate *cert, unsigned int *rettype)
-{
- unsigned int cType = cert->nsCertType;
- PRBool ret = PR_FALSE;
-
- if (cType & (NS_CERT_TYPE_SSL_CA | NS_CERT_TYPE_EMAIL_CA |
- NS_CERT_TYPE_OBJECT_SIGNING_CA)) {
- ret = PR_TRUE;
- } else {
- SECStatus rv;
- CERTBasicConstraints constraints;
-
- rv = CERT_FindBasicConstraintExten(cert, &constraints);
- if (rv == SECSuccess && constraints.isCA) {
- ret = PR_TRUE;
- cType |= (NS_CERT_TYPE_SSL_CA | NS_CERT_TYPE_EMAIL_CA);
- }
- }
-
- /* finally check if it's an X.509 v1 root CA */
- if (!ret &&
- (cert->isRoot && cert_Version(cert) < SEC_CERTIFICATE_VERSION_3)) {
- ret = PR_TRUE;
- cType |= (NS_CERT_TYPE_SSL_CA | NS_CERT_TYPE_EMAIL_CA);
- }
- /* Now apply trust overrides, if any */
- cType = cert_ComputeTrustOverrides(cert, cType);
- ret = (cType & (NS_CERT_TYPE_SSL_CA | NS_CERT_TYPE_EMAIL_CA |
- NS_CERT_TYPE_OBJECT_SIGNING_CA))
- ? PR_TRUE
- : PR_FALSE;
-
- if (rettype != NULL) {
- *rettype = cType;
- }
- return ret;
-}
-
-PRBool
-CERT_IsCADERCert(SECItem *derCert, unsigned int *type)
-{
- CERTCertificate *cert;
- PRBool isCA;
-
- /* This is okay -- only looks at extensions */
- cert = CERT_DecodeDERCertificate(derCert, PR_FALSE, NULL);
- if (cert == NULL)
- return PR_FALSE;
-
- isCA = CERT_IsCACert(cert, type);
- CERT_DestroyCertificate(cert);
- return isCA;
-}
-
-PRBool
-CERT_IsRootDERCert(SECItem *derCert)
-{
- CERTCertificate *cert;
- PRBool isRoot;
-
- /* This is okay -- only looks at extensions */
- cert = CERT_DecodeDERCertificate(derCert, PR_FALSE, NULL);
- if (cert == NULL)
- return PR_FALSE;
-
- isRoot = cert->isRoot;
- CERT_DestroyCertificate(cert);
- return isRoot;
-}
-
-CERTCompareValidityStatus
-CERT_CompareValidityTimes(CERTValidity *val_a, CERTValidity *val_b)
-{
- PRTime notBeforeA, notBeforeB, notAfterA, notAfterB;
-
- if (!val_a || !val_b) {
- PORT_SetError(SEC_ERROR_INVALID_ARGS);
- return certValidityUndetermined;
- }
-
- if (SECSuccess != DER_DecodeTimeChoice(&notBeforeA, &val_a->notBefore) ||
- SECSuccess != DER_DecodeTimeChoice(&notBeforeB, &val_b->notBefore) ||
- SECSuccess != DER_DecodeTimeChoice(&notAfterA, &val_a->notAfter) ||
- SECSuccess != DER_DecodeTimeChoice(&notAfterB, &val_b->notAfter)) {
- return certValidityUndetermined;
- }
-
- /* sanity check */
- if (LL_CMP(notBeforeA, >, notAfterA) || LL_CMP(notBeforeB, >, notAfterB)) {
- PORT_SetError(SEC_ERROR_INVALID_TIME);
- return certValidityUndetermined;
- }
-
- if (LL_CMP(notAfterA, !=, notAfterB)) {
- /* one cert validity goes farther into the future, select it */
- return LL_CMP(notAfterA, <, notAfterB) ? certValidityChooseB
- : certValidityChooseA;
- }
- /* the two certs have the same expiration date */
- PORT_Assert(LL_CMP(notAfterA, ==, notAfterB));
- /* do they also have the same start date ? */
- if (LL_CMP(notBeforeA, ==, notBeforeB)) {
- return certValidityEqual;
- }
- /* choose cert with the later start date */
- return LL_CMP(notBeforeA, <, notBeforeB) ? certValidityChooseB
- : certValidityChooseA;
-}
-
-/*
- * is certa newer than certb? If one is expired, pick the other one.
- */
-PRBool
-CERT_IsNewer(CERTCertificate *certa, CERTCertificate *certb)
-{
- PRTime notBeforeA, notAfterA, notBeforeB, notAfterB, now;
- SECStatus rv;
- PRBool newerbefore, newerafter;
-
- rv = CERT_GetCertTimes(certa, &notBeforeA, &notAfterA);
- if (rv != SECSuccess) {
- return (PR_FALSE);
- }
-
- rv = CERT_GetCertTimes(certb, &notBeforeB, &notAfterB);
- if (rv != SECSuccess) {
- return (PR_TRUE);
- }
-
- newerbefore = PR_FALSE;
- if (LL_CMP(notBeforeA, >, notBeforeB)) {
- newerbefore = PR_TRUE;
- }
-
- newerafter = PR_FALSE;
- if (LL_CMP(notAfterA, >, notAfterB)) {
- newerafter = PR_TRUE;
- }
-
- if (newerbefore && newerafter) {
- return (PR_TRUE);
- }
-
- if ((!newerbefore) && (!newerafter)) {
- return (PR_FALSE);
- }
-
- /* get current time */
- now = PR_Now();
-
- if (newerbefore) {
- /* cert A was issued after cert B, but expires sooner */
- /* if A is expired, then pick B */
- if (LL_CMP(notAfterA, <, now)) {
- return (PR_FALSE);
- }
- return (PR_TRUE);
- } else {
- /* cert B was issued after cert A, but expires sooner */
- /* if B is expired, then pick A */
- if (LL_CMP(notAfterB, <, now)) {
- return (PR_TRUE);
- }
- return (PR_FALSE);
- }
-}
-
-void
-CERT_DestroyCertArray(CERTCertificate **certs, unsigned int ncerts)
-{
- unsigned int i;
-
- if (certs) {
- for (i = 0; i < ncerts; i++) {
- if (certs[i]) {
- CERT_DestroyCertificate(certs[i]);
- }
- }
-
- PORT_Free(certs);
- }
-
- return;
-}
-
-char *
-CERT_FixupEmailAddr(const char *emailAddr)
-{
- char *retaddr;
- char *str;
-
- if (emailAddr == NULL) {
- return (NULL);
- }
-
- /* copy the string */
- str = retaddr = PORT_Strdup(emailAddr);
- if (str == NULL) {
- return (NULL);
- }
-
- /* make it lower case */
- while (*str) {
- *str = tolower(*str);
- str++;
- }
-
- return (retaddr);
-}
-
-/*
- * NOTE - don't allow encode of govt-approved or invisible bits
- */
-SECStatus
-CERT_DecodeTrustString(CERTCertTrust *trust, const char *trusts)
-{
- unsigned int i;
- unsigned int *pflags;
-
- if (!trust) {
- PORT_SetError(SEC_ERROR_INVALID_ARGS);
- return SECFailure;
- }
- trust->sslFlags = 0;
- trust->emailFlags = 0;
- trust->objectSigningFlags = 0;
- if (!trusts) {
- PORT_SetError(SEC_ERROR_INVALID_ARGS);
- return SECFailure;
- }
-
- pflags = &trust->sslFlags;
-
- for (i = 0; i < PORT_Strlen(trusts); i++) {
- switch (trusts[i]) {
- case 'p':
- *pflags = *pflags | CERTDB_TERMINAL_RECORD;
- break;
-
- case 'P':
- *pflags = *pflags | CERTDB_TRUSTED | CERTDB_TERMINAL_RECORD;
- break;
-
- case 'w':
- *pflags = *pflags | CERTDB_SEND_WARN;
- break;
-
- case 'c':
- *pflags = *pflags | CERTDB_VALID_CA;
- break;
-
- case 'T':
- *pflags = *pflags | CERTDB_TRUSTED_CLIENT_CA | CERTDB_VALID_CA;
- break;
-
- case 'C':
- *pflags = *pflags | CERTDB_TRUSTED_CA | CERTDB_VALID_CA;
- break;
-
- case 'u':
- *pflags = *pflags | CERTDB_USER;
- break;
-
- case 'i':
- *pflags = *pflags | CERTDB_INVISIBLE_CA;
- break;
- case 'g':
- *pflags = *pflags | CERTDB_GOVT_APPROVED_CA;
- break;
-
- case ',':
- if (pflags == &trust->sslFlags) {
- pflags = &trust->emailFlags;
- } else {
- pflags = &trust->objectSigningFlags;
- }
- break;
- default:
- PORT_SetError(SEC_ERROR_INVALID_ARGS);
- return SECFailure;
- }
- }
-
- return SECSuccess;
-}
-
-static void
-EncodeFlags(char *trusts, unsigned int flags)
-{
- if (flags & CERTDB_VALID_CA)
- if (!(flags & CERTDB_TRUSTED_CA) && !(flags & CERTDB_TRUSTED_CLIENT_CA))
- PORT_Strcat(trusts, "c");
- if (flags & CERTDB_TERMINAL_RECORD)
- if (!(flags & CERTDB_TRUSTED))
- PORT_Strcat(trusts, "p");
- if (flags & CERTDB_TRUSTED_CA)
- PORT_Strcat(trusts, "C");
- if (flags & CERTDB_TRUSTED_CLIENT_CA)
- PORT_Strcat(trusts, "T");
- if (flags & CERTDB_TRUSTED)
- PORT_Strcat(trusts, "P");
- if (flags & CERTDB_USER)
- PORT_Strcat(trusts, "u");
- if (flags & CERTDB_SEND_WARN)
- PORT_Strcat(trusts, "w");
- if (flags & CERTDB_INVISIBLE_CA)
- PORT_Strcat(trusts, "I");
- if (flags & CERTDB_GOVT_APPROVED_CA)
- PORT_Strcat(trusts, "G");
- return;
-}
-
-char *
-CERT_EncodeTrustString(CERTCertTrust *trust)
-{
- char tmpTrustSSL[32];
- char tmpTrustEmail[32];
- char tmpTrustSigning[32];
- char *retstr = NULL;
-
- if (trust) {
- tmpTrustSSL[0] = '\0';
- tmpTrustEmail[0] = '\0';
- tmpTrustSigning[0] = '\0';
-
- EncodeFlags(tmpTrustSSL, trust->sslFlags);
- EncodeFlags(tmpTrustEmail, trust->emailFlags);
- EncodeFlags(tmpTrustSigning, trust->objectSigningFlags);
-
- retstr = PR_smprintf("%s,%s,%s", tmpTrustSSL, tmpTrustEmail,
- tmpTrustSigning);
- }
-
- return (retstr);
-}
-
-SECStatus
-CERT_ImportCerts(CERTCertDBHandle *certdb, SECCertUsage usage,
- unsigned int ncerts, SECItem **derCerts,
- CERTCertificate ***retCerts, PRBool keepCerts, PRBool caOnly,
- char *nickname)
-{
- unsigned int i;
- CERTCertificate **certs = NULL;
- unsigned int fcerts = 0;
-
- if (ncerts) {
- certs = PORT_ZNewArray(CERTCertificate *, ncerts);
- if (certs == NULL) {
- return (SECFailure);
- }
-
- /* decode all of the certs into the temporary DB */
- for (i = 0, fcerts = 0; i < ncerts; i++) {
- certs[fcerts] = CERT_NewTempCertificate(certdb, derCerts[i], NULL,
- PR_FALSE, PR_TRUE);
- if (certs[fcerts]) {
- SECItem subjKeyID = { siBuffer, NULL, 0 };
- if (CERT_FindSubjectKeyIDExtension(certs[fcerts], &subjKeyID) ==
- SECSuccess) {
- if (subjKeyID.data) {
- cert_AddSubjectKeyIDMapping(&subjKeyID, certs[fcerts]);
- }
- SECITEM_FreeItem(&subjKeyID, PR_FALSE);
- }
- fcerts++;
- }
- }
-
- if (keepCerts) {
- for (i = 0; i < fcerts; i++) {
- char *canickname = NULL;
- PRBool isCA;
-
- SECKEY_UpdateCertPQG(certs[i]);
-
- isCA = CERT_IsCACert(certs[i], NULL);
- if (isCA) {
- canickname = CERT_MakeCANickname(certs[i]);
- }
-
- if (isCA && (fcerts > 1)) {
- /* if we are importing only a single cert and specifying
- * a nickname, we want to use that nickname if it a CA,
- * otherwise if there are more than one cert, we don't
- * know which cert it belongs to. But we still may try
- * the individual canickname from the cert itself.
- */
- /* Bug 1192442 - propagate errors from these calls. */
- (void)CERT_AddTempCertToPerm(certs[i], canickname, NULL);
- } else {
- (void)CERT_AddTempCertToPerm(
- certs[i], nickname ? nickname : canickname, NULL);
- }
-
- PORT_Free(canickname);
- /* don't care if it fails - keep going */
- }
- }
- }
-
- if (retCerts) {
- *retCerts = certs;
- } else {
- if (certs) {
- CERT_DestroyCertArray(certs, fcerts);
- }
- }
-
- return (fcerts || !ncerts) ? SECSuccess : SECFailure;
-}
-
-/*
- * a real list of certificates - need to convert CERTCertificateList
- * stuff and ASN 1 encoder/decoder over to using this...
- */
-CERTCertList *
-CERT_NewCertList(void)
-{
- PLArenaPool *arena = NULL;
- CERTCertList *ret = NULL;
-
- arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
- if (arena == NULL) {
- goto loser;
- }
-
- ret = (CERTCertList *)PORT_ArenaZAlloc(arena, sizeof(CERTCertList));
- if (ret == NULL) {
- goto loser;
- }
-
- ret->arena = arena;
-
- PR_INIT_CLIST(&ret->list);
-
- return (ret);
-
-loser:
- if (arena != NULL) {
- PORT_FreeArena(arena, PR_FALSE);
- }
-
- return (NULL);
-}
-
-void
-CERT_DestroyCertList(CERTCertList *certs)
-{
- PRCList *node;
-
- while (!PR_CLIST_IS_EMPTY(&certs->list)) {
- node = PR_LIST_HEAD(&certs->list);
- CERT_DestroyCertificate(((CERTCertListNode *)node)->cert);
- PR_REMOVE_LINK(node);
- }
-
- PORT_FreeArena(certs->arena, PR_FALSE);
-
- return;
-}
-
-void
-CERT_RemoveCertListNode(CERTCertListNode *node)
-{
- CERT_DestroyCertificate(node->cert);
- PR_REMOVE_LINK(&node->links);
- return;
-}
-
-SECStatus
-CERT_AddCertToListTailWithData(CERTCertList *certs, CERTCertificate *cert,
- void *appData)
-{
- CERTCertListNode *node;
-
- node = (CERTCertListNode *)PORT_ArenaZAlloc(certs->arena,
- sizeof(CERTCertListNode));
- if (node == NULL) {
- goto loser;
- }
-
- PR_INSERT_BEFORE(&node->links, &certs->list);
- /* certs->count++; */
- node->cert = cert;
- node->appData = appData;
- return (SECSuccess);
-
-loser:
- return (SECFailure);
-}
-
-SECStatus
-CERT_AddCertToListTail(CERTCertList *certs, CERTCertificate *cert)
-{
- return CERT_AddCertToListTailWithData(certs, cert, NULL);
-}
-
-SECStatus
-CERT_AddCertToListHeadWithData(CERTCertList *certs, CERTCertificate *cert,
- void *appData)
-{
- CERTCertListNode *node;
- CERTCertListNode *head;
-
- head = CERT_LIST_HEAD(certs);
-
- if (head == NULL)
- return CERT_AddCertToListTail(certs, cert);
-
- node = (CERTCertListNode *)PORT_ArenaZAlloc(certs->arena,
- sizeof(CERTCertListNode));
- if (node == NULL) {
- goto loser;
- }
-
- PR_INSERT_BEFORE(&node->links, &head->links);
- /* certs->count++; */
- node->cert = cert;
- node->appData = appData;
- return (SECSuccess);
-
-loser:
- return (SECFailure);
-}
-
-SECStatus
-CERT_AddCertToListHead(CERTCertList *certs, CERTCertificate *cert)
-{
- return CERT_AddCertToListHeadWithData(certs, cert, NULL);
-}
-
-/*
- * Sort callback function to determine if cert a is newer than cert b.
- * Not valid certs are considered older than valid certs.
- */
-PRBool
-CERT_SortCBValidity(CERTCertificate *certa, CERTCertificate *certb, void *arg)
-{
- PRTime sorttime;
- PRTime notBeforeA, notAfterA, notBeforeB, notAfterB;
- SECStatus rv;
- PRBool newerbefore, newerafter;
- PRBool aNotValid = PR_FALSE, bNotValid = PR_FALSE;
-
- sorttime = *(PRTime *)arg;
-
- rv = CERT_GetCertTimes(certa, &notBeforeA, &notAfterA);
- if (rv != SECSuccess) {
- return (PR_FALSE);
- }
-
- rv = CERT_GetCertTimes(certb, &notBeforeB, &notAfterB);
- if (rv != SECSuccess) {
- return (PR_TRUE);
- }
- newerbefore = PR_FALSE;
- if (LL_CMP(notBeforeA, >, notBeforeB)) {
- newerbefore = PR_TRUE;
- }
- newerafter = PR_FALSE;
- if (LL_CMP(notAfterA, >, notAfterB)) {
- newerafter = PR_TRUE;
- }
-
- /* check if A is valid at sorttime */
- if (CERT_CheckCertValidTimes(certa, sorttime, PR_FALSE) !=
- secCertTimeValid) {
- aNotValid = PR_TRUE;
- }
-
- /* check if B is valid at sorttime */
- if (CERT_CheckCertValidTimes(certb, sorttime, PR_FALSE) !=
- secCertTimeValid) {
- bNotValid = PR_TRUE;
- }
-
- /* a is valid, b is not */
- if (bNotValid && (!aNotValid)) {
- return (PR_TRUE);
- }
-
- /* b is valid, a is not */
- if (aNotValid && (!bNotValid)) {
- return (PR_FALSE);
- }
-
- /* a and b are either valid or not valid */
- if (newerbefore && newerafter) {
- return (PR_TRUE);
- }
-
- if ((!newerbefore) && (!newerafter)) {
- return (PR_FALSE);
- }
-
- if (newerbefore) {
- /* cert A was issued after cert B, but expires sooner */
- return (PR_TRUE);
- } else {
- /* cert B was issued after cert A, but expires sooner */
- return (PR_FALSE);
- }
-}
-
-SECStatus
-CERT_AddCertToListSorted(CERTCertList *certs, CERTCertificate *cert,
- CERTSortCallback f, void *arg)
-{
- CERTCertListNode *node;
- CERTCertListNode *head;
- PRBool ret;
-
- node = (CERTCertListNode *)PORT_ArenaZAlloc(certs->arena,
- sizeof(CERTCertListNode));
- if (node == NULL) {
- goto loser;
- }
-
- head = CERT_LIST_HEAD(certs);
-
- while (!CERT_LIST_END(head, certs)) {
-
- /* if cert is already in the list, then don't add it again */
- if (cert == head->cert) {
- /*XXX*/
- /* don't keep a reference */
- CERT_DestroyCertificate(cert);
- goto done;
- }
-
- ret = (*f)(cert, head->cert, arg);
- /* if sort function succeeds, then insert before current node */
- if (ret) {
- PR_INSERT_BEFORE(&node->links, &head->links);
- goto done;
- }
-
- head = CERT_LIST_NEXT(head);
- }
- /* if we get to the end, then just insert it at the tail */
- PR_INSERT_BEFORE(&node->links, &certs->list);
-
-done:
- /* certs->count++; */
- node->cert = cert;
- return (SECSuccess);
-
-loser:
- return (SECFailure);
-}
-
-/* This routine is here because pcertdb.c still has a call to it.
- * The SMIME profile code in pcertdb.c should be split into high (find
- * the email cert) and low (store the profile) code. At that point, we
- * can move this to certhigh.c where it belongs.
- *
- * remove certs from a list that don't have keyUsage and certType
- * that match the given usage.
- */
-SECStatus
-CERT_FilterCertListByUsage(CERTCertList *certList, SECCertUsage usage,
- PRBool ca)
-{
- unsigned int requiredKeyUsage;
- unsigned int requiredCertType;
- CERTCertListNode *node, *savenode;
- SECStatus rv;
-
- if (certList == NULL)
- goto loser;
-
- rv = CERT_KeyUsageAndTypeForCertUsage(usage, ca, &requiredKeyUsage,
- &requiredCertType);
- if (rv != SECSuccess) {
- goto loser;
- }
-
- node = CERT_LIST_HEAD(certList);
-
- while (!CERT_LIST_END(node, certList)) {
-
- PRBool bad = (PRBool)(!node->cert);
-
- /* bad key usage ? */
- if (!bad &&
- CERT_CheckKeyUsage(node->cert, requiredKeyUsage) != SECSuccess) {
- bad = PR_TRUE;
- }
- /* bad cert type ? */
- if (!bad) {
- unsigned int certType = 0;
- if (ca) {
- /* This function returns a more comprehensive cert type that
- * takes trust flags into consideration. Should probably
- * fix the cert decoding code to do this.
- */
- (void)CERT_IsCACert(node->cert, &certType);
- } else {
- certType = node->cert->nsCertType;
- }
- if (!(certType & requiredCertType)) {
- bad = PR_TRUE;
- }
- }
-
- if (bad) {
- /* remove the node if it is bad */
- savenode = CERT_LIST_NEXT(node);
- CERT_RemoveCertListNode(node);
- node = savenode;
- } else {
- node = CERT_LIST_NEXT(node);
- }
- }
- return (SECSuccess);
-
-loser:
- return (SECFailure);
-}
-
-PRBool
-CERT_IsUserCert(CERTCertificate *cert)
-{
- CERTCertTrust trust;
- SECStatus rv = SECFailure;
-
- rv = CERT_GetCertTrust(cert, &trust);
- if (rv == SECSuccess &&
- ((trust.sslFlags & CERTDB_USER) || (trust.emailFlags & CERTDB_USER) ||
- (trust.objectSigningFlags & CERTDB_USER))) {
- return PR_TRUE;
- } else {
- return PR_FALSE;
- }
-}
-
-SECStatus
-CERT_FilterCertListForUserCerts(CERTCertList *certList)
-{
- CERTCertListNode *node, *freenode;
- CERTCertificate *cert;
-
- if (!certList) {
- return SECFailure;
- }
-
- node = CERT_LIST_HEAD(certList);
-
- while (!CERT_LIST_END(node, certList)) {
- cert = node->cert;
- if (PR_TRUE != CERT_IsUserCert(cert)) {
- /* Not a User Cert, so remove this cert from the list */
- freenode = node;
- node = CERT_LIST_NEXT(node);
- CERT_RemoveCertListNode(freenode);
- } else {
- /* Is a User cert, so leave it in the list */
- node = CERT_LIST_NEXT(node);
- }
- }
-
- return (SECSuccess);
-}
-
-static PZLock *certRefCountLock = NULL;
-
-/*
- * Acquire the cert reference count lock
- * There is currently one global lock for all certs, but I'm putting a cert
- * arg here so that it will be easy to make it per-cert in the future if
- * that turns out to be necessary.
- */
-void
-CERT_LockCertRefCount(CERTCertificate *cert)
-{
- PORT_Assert(certRefCountLock != NULL);
- PZ_Lock(certRefCountLock);
- return;
-}
-
-/*
- * Free the cert reference count lock
- */
-void
-CERT_UnlockCertRefCount(CERTCertificate *cert)
-{
- PORT_Assert(certRefCountLock != NULL);
-
-#ifdef DEBUG
- {
- PRStatus prstat = PZ_Unlock(certRefCountLock);
- PORT_Assert(prstat == PR_SUCCESS);
- }
-#else
- PZ_Unlock(certRefCountLock);
-#endif
-}
-
-static PZLock *certTrustLock = NULL;
-
-/*
- * Acquire the cert trust lock
- * There is currently one global lock for all certs, but I'm putting a cert
- * arg here so that it will be easy to make it per-cert in the future if
- * that turns out to be necessary.
- */
-void
-CERT_LockCertTrust(const CERTCertificate *cert)
-{
- PORT_Assert(certTrustLock != NULL);
- PZ_Lock(certTrustLock);
- return;
-}
-
-SECStatus
-cert_InitLocks(void)
-{
- if (certRefCountLock == NULL) {
- certRefCountLock = PZ_NewLock(nssILockRefLock);
- PORT_Assert(certRefCountLock != NULL);
- if (!certRefCountLock) {
- return SECFailure;
- }
- }
-
- if (certTrustLock == NULL) {
- certTrustLock = PZ_NewLock(nssILockCertDB);
- PORT_Assert(certTrustLock != NULL);
- if (!certTrustLock) {
- PZ_DestroyLock(certRefCountLock);
- certRefCountLock = NULL;
- return SECFailure;
- }
- }
-
- return SECSuccess;
-}
-
-SECStatus
-cert_DestroyLocks(void)
-{
- SECStatus rv = SECSuccess;
-
- PORT_Assert(certRefCountLock != NULL);
- if (certRefCountLock) {
- PZ_DestroyLock(certRefCountLock);
- certRefCountLock = NULL;
- } else {
- rv = SECFailure;
- }
-
- PORT_Assert(certTrustLock != NULL);
- if (certTrustLock) {
- PZ_DestroyLock(certTrustLock);
- certTrustLock = NULL;
- } else {
- rv = SECFailure;
- }
- return rv;
-}
-
-/*
- * Free the cert trust lock
- */
-void
-CERT_UnlockCertTrust(const CERTCertificate *cert)
-{
- PORT_Assert(certTrustLock != NULL);
-
-#ifdef DEBUG
- {
- PRStatus prstat = PZ_Unlock(certTrustLock);
- PORT_Assert(prstat == PR_SUCCESS);
- }
-#else
- PZ_Unlock(certTrustLock);
-#endif
-}
-
-/*
- * Get the StatusConfig data for this handle
- */
-CERTStatusConfig *
-CERT_GetStatusConfig(CERTCertDBHandle *handle)
-{
- return handle->statusConfig;
-}
-
-/*
- * Set the StatusConfig data for this handle. There
- * should not be another configuration set.
- */
-void
-CERT_SetStatusConfig(CERTCertDBHandle *handle, CERTStatusConfig *statusConfig)
-{
- PORT_Assert(handle->statusConfig == NULL);
- handle->statusConfig = statusConfig;
-}
-
-/*
- * Code for dealing with subjKeyID to cert mappings.
- */
-
-static PLHashTable *gSubjKeyIDHash = NULL;
-static PRLock *gSubjKeyIDLock = NULL;
-static PLHashTable *gSubjKeyIDSlotCheckHash = NULL;
-static PRLock *gSubjKeyIDSlotCheckLock = NULL;
-
-static void *
-cert_AllocTable(void *pool, PRSize size)
-{
- return PORT_Alloc(size);
-}
-
-static void
-cert_FreeTable(void *pool, void *item)
-{
- PORT_Free(item);
-}
-
-static PLHashEntry *
-cert_AllocEntry(void *pool, const void *key)
-{
- return PORT_New(PLHashEntry);
-}
-
-static void
-cert_FreeEntry(void *pool, PLHashEntry *he, PRUintn flag)
-{
- SECITEM_FreeItem((SECItem *)(he->value), PR_TRUE);
- if (flag == HT_FREE_ENTRY) {
- SECITEM_FreeItem((SECItem *)(he->key), PR_TRUE);
- PORT_Free(he);
- }
-}
-
-static PLHashAllocOps cert_AllocOps = { cert_AllocTable, cert_FreeTable,
- cert_AllocEntry, cert_FreeEntry };
-
-SECStatus
-cert_CreateSubjectKeyIDSlotCheckHash(void)
-{
- /*
- * This hash is used to remember the series of a slot
- * when we last checked for user certs
- */
- gSubjKeyIDSlotCheckHash =
- PL_NewHashTable(0, SECITEM_Hash, SECITEM_HashCompare,
- SECITEM_HashCompare, &cert_AllocOps, NULL);
- if (!gSubjKeyIDSlotCheckHash) {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- return SECFailure;
- }
- gSubjKeyIDSlotCheckLock = PR_NewLock();
- if (!gSubjKeyIDSlotCheckLock) {
- PL_HashTableDestroy(gSubjKeyIDSlotCheckHash);
- gSubjKeyIDSlotCheckHash = NULL;
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- return SECFailure;
- }
- return SECSuccess;
-}
-
-SECStatus
-cert_CreateSubjectKeyIDHashTable(void)
-{
- gSubjKeyIDHash = PL_NewHashTable(0, SECITEM_Hash, SECITEM_HashCompare,
- SECITEM_HashCompare, &cert_AllocOps, NULL);
- if (!gSubjKeyIDHash) {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- return SECFailure;
- }
- gSubjKeyIDLock = PR_NewLock();
- if (!gSubjKeyIDLock) {
- PL_HashTableDestroy(gSubjKeyIDHash);
- gSubjKeyIDHash = NULL;
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- return SECFailure;
- }
- /* initialize the companion hash (for remembering slot series) */
- if (cert_CreateSubjectKeyIDSlotCheckHash() != SECSuccess) {
- cert_DestroySubjectKeyIDHashTable();
- return SECFailure;
- }
- return SECSuccess;
-}
-
-SECStatus
-cert_AddSubjectKeyIDMapping(SECItem *subjKeyID, CERTCertificate *cert)
-{
- SECItem *newKeyID, *oldVal, *newVal;
- SECStatus rv = SECFailure;
-
- if (!gSubjKeyIDLock) {
- /* If one is created, then both are there. So only check for one. */
- return SECFailure;
- }
-
- newVal = SECITEM_DupItem(&cert->derCert);
- if (!newVal) {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- goto done;
- }
- newKeyID = SECITEM_DupItem(subjKeyID);
- if (!newKeyID) {
- SECITEM_FreeItem(newVal, PR_TRUE);
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- goto done;
- }
-
- PR_Lock(gSubjKeyIDLock);
- /* The hash table implementation does not free up the memory
- * associated with the key of an already existing entry if we add a
- * duplicate, so we would wind up leaking the previously allocated
- * key if we don't remove before adding.
- */
- oldVal = (SECItem *)PL_HashTableLookup(gSubjKeyIDHash, subjKeyID);
- if (oldVal) {
- PL_HashTableRemove(gSubjKeyIDHash, subjKeyID);
- }
-
- rv = (PL_HashTableAdd(gSubjKeyIDHash, newKeyID, newVal)) ? SECSuccess
- : SECFailure;
- PR_Unlock(gSubjKeyIDLock);
-done:
- return rv;
-}
-
-SECStatus
-cert_RemoveSubjectKeyIDMapping(SECItem *subjKeyID)
-{
- SECStatus rv;
- if (!gSubjKeyIDLock)
- return SECFailure;
-
- PR_Lock(gSubjKeyIDLock);
- rv = (PL_HashTableRemove(gSubjKeyIDHash, subjKeyID)) ? SECSuccess
- : SECFailure;
- PR_Unlock(gSubjKeyIDLock);
- return rv;
-}
-
-SECStatus
-cert_UpdateSubjectKeyIDSlotCheck(SECItem *slotid, int series)
-{
- SECItem *oldSeries, *newSlotid, *newSeries;
- SECStatus rv = SECFailure;
-
- if (!gSubjKeyIDSlotCheckLock) {
- return rv;
- }
-
- newSlotid = SECITEM_DupItem(slotid);
- newSeries = SECITEM_AllocItem(NULL, NULL, sizeof(int));
- if (!newSlotid || !newSeries) {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- goto loser;
- }
- PORT_Memcpy(newSeries->data, &series, sizeof(int));
-
- PR_Lock(gSubjKeyIDSlotCheckLock);
- oldSeries = (SECItem *)PL_HashTableLookup(gSubjKeyIDSlotCheckHash, slotid);
- if (oldSeries) {
- /*
- * make sure we don't leak the key of an existing entry
- * (similar to cert_AddSubjectKeyIDMapping, see comment there)
- */
- PL_HashTableRemove(gSubjKeyIDSlotCheckHash, slotid);
- }
- rv = (PL_HashTableAdd(gSubjKeyIDSlotCheckHash, newSlotid, newSeries))
- ? SECSuccess
- : SECFailure;
- PR_Unlock(gSubjKeyIDSlotCheckLock);
- if (rv == SECSuccess) {
- return rv;
- }
-
-loser:
- if (newSlotid) {
- SECITEM_FreeItem(newSlotid, PR_TRUE);
- }
- if (newSeries) {
- SECITEM_FreeItem(newSeries, PR_TRUE);
- }
- return rv;
-}
-
-int
-cert_SubjectKeyIDSlotCheckSeries(SECItem *slotid)
-{
- SECItem *seriesItem = NULL;
- int series;
-
- if (!gSubjKeyIDSlotCheckLock) {
- PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
- return -1;
- }
-
- PR_Lock(gSubjKeyIDSlotCheckLock);
- seriesItem = (SECItem *)PL_HashTableLookup(gSubjKeyIDSlotCheckHash, slotid);
- PR_Unlock(gSubjKeyIDSlotCheckLock);
- /* getting a null series just means we haven't registered one yet,
- * just return 0 */
- if (seriesItem == NULL) {
- return 0;
- }
- /* if we got a series back, assert if it's not the proper length. */
- PORT_Assert(seriesItem->len == sizeof(int));
- if (seriesItem->len != sizeof(int)) {
- PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
- return -1;
- }
- PORT_Memcpy(&series, seriesItem->data, sizeof(int));
- return series;
-}
-
-SECStatus
-cert_DestroySubjectKeyIDSlotCheckHash(void)
-{
- if (gSubjKeyIDSlotCheckHash) {
- PR_Lock(gSubjKeyIDSlotCheckLock);
- PL_HashTableDestroy(gSubjKeyIDSlotCheckHash);
- gSubjKeyIDSlotCheckHash = NULL;
- PR_Unlock(gSubjKeyIDSlotCheckLock);
- PR_DestroyLock(gSubjKeyIDSlotCheckLock);
- gSubjKeyIDSlotCheckLock = NULL;
- }
- return SECSuccess;
-}
-
-SECStatus
-cert_DestroySubjectKeyIDHashTable(void)
-{
- if (gSubjKeyIDHash) {
- PR_Lock(gSubjKeyIDLock);
- PL_HashTableDestroy(gSubjKeyIDHash);
- gSubjKeyIDHash = NULL;
- PR_Unlock(gSubjKeyIDLock);
- PR_DestroyLock(gSubjKeyIDLock);
- gSubjKeyIDLock = NULL;
- }
- cert_DestroySubjectKeyIDSlotCheckHash();
- return SECSuccess;
-}
-
-SECItem *
-cert_FindDERCertBySubjectKeyID(SECItem *subjKeyID)
-{
- SECItem *val;
-
- if (!gSubjKeyIDLock)
- return NULL;
-
- PR_Lock(gSubjKeyIDLock);
- val = (SECItem *)PL_HashTableLookup(gSubjKeyIDHash, subjKeyID);
- if (val) {
- val = SECITEM_DupItem(val);
- }
- PR_Unlock(gSubjKeyIDLock);
- return val;
-}
-
-CERTCertificate *
-CERT_FindCertBySubjectKeyID(CERTCertDBHandle *handle, SECItem *subjKeyID)
-{
- CERTCertificate *cert = NULL;
- SECItem *derCert;
-
- derCert = cert_FindDERCertBySubjectKeyID(subjKeyID);
- if (derCert) {
- cert = CERT_FindCertByDERCert(handle, derCert);
- SECITEM_FreeItem(derCert, PR_TRUE);
- }
- return cert;
-}
« no previous file with comments | « nss/lib/certdb/certdb.h ('k') | nss/lib/certdb/certi.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698