summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjpierre%netscape.com <devnull@localhost>2002-07-04 03:09:49 +0000
committerjpierre%netscape.com <devnull@localhost>2002-07-04 03:09:49 +0000
commitbfabf37a89bb233b307e473fba61a5fbc3f97fa9 (patch)
treed8ed5b2e0cdadc97e209d780af034c3637f5830b
parent8af685ac1b9aba1b6c72a09afd331581d5856ec8 (diff)
downloadnss-hg-bfabf37a89bb233b307e473fba61a5fbc3f97fa9.tar.gz
Add new CERT_VerifyCertificate function - fix for 149832
-rw-r--r--security/nss/lib/certdb/cert.h21
-rw-r--r--security/nss/lib/certdb/certt.h17
-rw-r--r--security/nss/lib/certhigh/certvfy.c349
-rw-r--r--security/nss/lib/nss/nss.def2
4 files changed, 370 insertions, 19 deletions
diff --git a/security/nss/lib/certdb/cert.h b/security/nss/lib/certdb/cert.h
index b130959a7..56269f5f2 100644
--- a/security/nss/lib/certdb/cert.h
+++ b/security/nss/lib/certdb/cert.h
@@ -532,6 +532,27 @@ extern SECStatus CERT_VerifySignedData(CERTSignedData *sd,
void *wincx);
/*
+** NEW FUNCTIONS with new bit-field-FIELD SECCertificateUsage - please use
+** verify a certificate by checking validity times against a certain time,
+** that we trust the issuer, and that the signature on the certificate is
+** valid.
+** "cert" the certificate to verify
+** "checkSig" only check signatures if true
+*/
+extern SECStatus
+CERT_VerifyCertificate(CERTCertDBHandle *handle, CERTCertificate *cert,
+ PRBool checkSig, SECCertificateUsage requiredUsages,
+ int64 t, void *wincx, CERTVerifyLog *log,
+ SECCertificateUsage* returnedUsages);
+
+/* same as above, but uses current time */
+extern SECStatus
+CERT_VerifyCertificateNow(CERTCertDBHandle *handle, CERTCertificate *cert,
+ PRBool checkSig, SECCertificateUsage requiredUsages,
+ void *wincx, SECCertificateUsage* returnedUsages);
+
+/*
+** OLD OBSOLETE FUNCTIONS with enum SECCertUsage - DO NOT USE FOR NEW CODE
** verify a certificate by checking validity times against a certain time,
** that we trust the issuer, and that the signature on the certificate is
** valid.
diff --git a/security/nss/lib/certdb/certt.h b/security/nss/lib/certdb/certt.h
index 911f5f158..4b87c1dfb 100644
--- a/security/nss/lib/certdb/certt.h
+++ b/security/nss/lib/certdb/certt.h
@@ -473,6 +473,23 @@ typedef enum SECCertUsageEnum {
certUsageAnyCA = 11
} SECCertUsage;
+typedef PRInt64 SECCertificateUsage;
+
+#define certificateUsageSSLClient (0x0001)
+#define certificateUsageSSLServer (0x0002)
+#define certificateUsageSSLServerWithStepUp (0x0004)
+#define certificateUsageSSLCA (0x0008)
+#define certificateUsageEmailSigner (0x0010)
+#define certificateUsageEmailRecipient (0x0020)
+#define certificateUsageObjectSigner (0x0040)
+#define certificateUsageUserCertImport (0x0080)
+#define certificateUsageVerifyCA (0x0100)
+#define certificateUsageProtectedObjectSigner (0x0200)
+#define certificateUsageStatusResponder (0x0400)
+#define certificateUsageAnyCA (0x0800)
+
+#define highestUsage certificateUsageAnyCA
+
/*
* Does the cert belong to the user, a peer, or a CA.
*/
diff --git a/security/nss/lib/certhigh/certvfy.c b/security/nss/lib/certhigh/certvfy.c
index 1ae7237de..ff4538d17 100644
--- a/security/nss/lib/certhigh/certvfy.c
+++ b/security/nss/lib/certhigh/certvfy.c
@@ -556,13 +556,10 @@ AddToVerifyLog(CERTVerifyLog *log, CERTCertificate *cert, unsigned long error,
AddToVerifyLog(log, cert, PORT_GetError(), depth, (void *)arg); \
}
-
-
-
SECStatus
-CERT_VerifyCertChain(CERTCertDBHandle *handle, CERTCertificate *cert,
+__CERT_VerifyCertChain(CERTCertDBHandle *handle, CERTCertificate *cert,
PRBool checkSig, SECCertUsage certUsage, int64 t,
- void *wincx, CERTVerifyLog *log)
+ void *wincx, CERTVerifyLog *log, PRBool doCRL, PRBool* revoked)
{
SECTrustType trustType;
CERTBasicConstraints basicConstraint;
@@ -590,6 +587,10 @@ CERT_VerifyCertChain(CERTCertDBHandle *handle, CERTCertificate *cert,
enum { cbd_None, cbd_User, cbd_CA } last_type = cbd_None;
SECKEYPublicKey *key;
+ if (revoked) {
+ *revoked = PR_FALSE;
+ }
+
if (CERT_KeyUsageAndTypeForCertUsage(certUsage, PR_TRUE,
&requiredCAKeyUsage,
&caCertType)
@@ -855,17 +856,25 @@ fortezzaDone:
* point
*/
/* check revoked list (issuer) */
- rv = SEC_CheckCRL(handle, subjectCert, issuerCert, t, wincx);
- if (rv == SECFailure) {
- LOG_ERROR_OR_EXIT(log,subjectCert,count,0);
- } else if (rv == SECWouldBlock) {
- /* We found something fishy, so we intend to issue an
- * error to the user, but the user may wish to continue
- * processing, in which case we better make sure nothing
- * worse has happened... so keep cranking the loop */
- rvFinal = SECFailure;
- LOG_ERROR(log,subjectCert,count,0);
- }
+ if (PR_TRUE == doCRL) {
+ rv = SEC_CheckCRL(handle, subjectCert, issuerCert, t, wincx);
+ if (rv == SECFailure) {
+ if (revoked) {
+ *revoked = PR_TRUE;
+ }
+ LOG_ERROR_OR_EXIT(log,subjectCert,count,0);
+ } else if (rv == SECWouldBlock) {
+ /* We found something fishy, so we intend to issue an
+ * error to the user, but the user may wish to continue
+ * processing, in which case we better make sure nothing
+ * worse has happened... so keep cranking the loop */
+ rvFinal = SECFailure;
+ if (revoked) {
+ *revoked = PR_TRUE;
+ }
+ LOG_ERROR(log,subjectCert,count,0);
+ }
+ }
if ( issuerCert->trust ) {
@@ -977,13 +986,304 @@ done:
}
return rv;
}
-
+
+#define NEXT_ITERATION() { \
+ i*=2; \
+ certUsage++; \
+ continue; \
+}
+
+#define VALID_USAGE() { \
+ NEXT_ITERATION(); \
+}
+
+#define INVALID_USAGE() { \
+ if (returnedUsages) { \
+ *returnedUsages &= !i; \
+ } \
+ if (PR_TRUE == requiredUsage) { \
+ valid = SECFailure; \
+ } \
+ NEXT_ITERATION(); \
+}
+
+SECStatus
+CERT_VerifyCertChain(CERTCertDBHandle *handle, CERTCertificate *cert,
+ PRBool checkSig, SECCertUsage certUsage, int64 t,
+ void *wincx, CERTVerifyLog *log)
+{
+ return __CERT_VerifyCertChain(handle, cert, checkSig, certUsage, t, wincx, log,
+ PR_TRUE, NULL);
+}
+
/*
- * verify a certificate by checking if its valid and that we
+ * verify a certificate by checking if it's valid and that we
* trust the issuer.
- * Note that this routine does not verify the signature of the certificate.
+ *
+ * certificateUsage contains a bitfield of all cert usages that are
+ * required for verification to succeed
+ *
+ * a bitfield of cert usages is returned in *returnedUsages
+ * if requiredUsages is non-zero, the returned bitmap is only
+ * for those required usages, otherwise it is for all usages
+ *
*/
SECStatus
+CERT_VerifyCertificate(CERTCertDBHandle *handle, CERTCertificate *cert,
+ PRBool checkSig, SECCertificateUsage requiredUsages, int64 t,
+ void *wincx, CERTVerifyLog *log, SECCertificateUsage* returnedUsages)
+{
+ SECStatus rv;
+ SECStatus valid;
+ unsigned int requiredKeyUsage;
+ unsigned int requiredCertType;
+ unsigned int flags;
+ unsigned int certType;
+ PRBool allowOverride;
+ SECCertTimeValidity validity;
+ CERTStatusConfig *statusConfig;
+ PRBool checkedChain = PR_FALSE;
+ PRInt32 i;
+ SECCertUsage certUsage = 0;
+ PRBool doOCSP = PR_FALSE;
+ PRBool checkedCRL = PR_FALSE;
+ PRBool checkedOCSP = PR_FALSE;
+ PRBool checkAllUsages = PR_FALSE;
+ PRBool revoked = PR_FALSE;
+
+ if (!requiredUsages) {
+ /* there are no required usages, so the user probably wants to
+ get status for all usages */
+ checkAllUsages = PR_TRUE;
+ }
+
+ if (returnedUsages) {
+ *returnedUsages = 0;
+ } else {
+ /* we don't have a place to return status for all usages,
+ so we can skip checks for usages that aren't required */
+ checkAllUsages = PR_FALSE;
+ }
+ valid = SECSuccess ; /* start off assuming cert is valid */
+
+#ifdef notdef
+ /* check if this cert is in the Evil list */
+ rv = CERT_CheckForEvilCert(cert);
+ if ( rv != SECSuccess ) {
+ PORT_SetError(SEC_ERROR_REVOKED_CERTIFICATE);
+ LOG_ERROR(log,cert,0,0);
+ return SECFailure;
+ }
+#endif
+
+ /* make sure that the cert is valid at time t */
+ allowOverride = (PRBool)((requiredUsages & certUsageSSLServer) ||
+ (requiredUsages & certificateUsageSSLServerWithStepUp));
+ validity = CERT_CheckCertValidTimes(cert, t, allowOverride);
+ if ( validity != secCertTimeValid ) {
+ LOG_ERROR(log,cert,0,validity);
+ return SECFailure;
+ }
+
+ /* check key usage and netscape cert type */
+ CERT_GetCertType(cert);
+ certType = cert->nsCertType;
+
+ for (i=1;i<=highestUsage && !(SECFailure == valid && !returnedUsages) ;) {
+ PRBool requiredUsage = (i & requiredUsages) ? PR_TRUE : PR_FALSE;
+ if (PR_FALSE == requiredUsage && PR_FALSE == checkAllUsages) {
+ NEXT_ITERATION();
+ }
+ if (returnedUsages) {
+ *returnedUsages |= i; /* start off assuming this usage is valid */
+ }
+ switch ( certUsage ) {
+ case certUsageSSLClient:
+ case certUsageSSLServer:
+ case certUsageSSLServerWithStepUp:
+ case certUsageSSLCA:
+ case certUsageEmailSigner:
+ case certUsageEmailRecipient:
+ case certUsageObjectSigner:
+ case certUsageStatusResponder:
+ rv = CERT_KeyUsageAndTypeForCertUsage(certUsage, PR_FALSE,
+ &requiredKeyUsage,
+ &requiredCertType);
+ if ( rv != SECSuccess ) {
+ PORT_Assert(0);
+ /* EXIT_IF_NOT_LOGGING(log); XXX ??? */
+ requiredKeyUsage = 0;
+ requiredCertType = 0;
+ INVALID_USAGE();
+ }
+ break;
+ case certUsageVerifyCA:
+ requiredKeyUsage = KU_KEY_CERT_SIGN;
+ requiredCertType = NS_CERT_TYPE_CA;
+ if ( ! ( certType & NS_CERT_TYPE_CA ) ) {
+ certType |= NS_CERT_TYPE_CA;
+ }
+ break;
+
+ case certUsageAnyCA:
+ case certUsageProtectedObjectSigner:
+ case certUsageUserCertImport:
+ /* these usages cannot be verified */
+ NEXT_ITERATION();
+
+ default:
+ PORT_Assert(0);
+ requiredKeyUsage = 0;
+ requiredCertType = 0;
+ INVALID_USAGE();
+ }
+ if ( CERT_CheckKeyUsage(cert, requiredKeyUsage) != SECSuccess ) {
+ if (PR_TRUE == requiredUsage) {
+ PORT_SetError(SEC_ERROR_INADEQUATE_KEY_USAGE);
+ }
+ LOG_ERROR(log,cert,0,requiredKeyUsage);
+ INVALID_USAGE();
+ }
+ if ( !( certType & requiredCertType ) ) {
+ if (PR_TRUE == requiredUsage) {
+ PORT_SetError(SEC_ERROR_INADEQUATE_CERT_TYPE);
+ }
+ LOG_ERROR(log,cert,0,requiredCertType);
+ INVALID_USAGE();
+ }
+
+ /* check trust flags to see if this cert is directly trusted */
+ if ( cert->trust ) { /* the cert is in the DB */
+ switch ( certUsage ) {
+ case certUsageSSLClient:
+ case certUsageSSLServer:
+ flags = cert->trust->sslFlags;
+
+ /* is the cert directly trusted or not trusted ? */
+ if ( flags & CERTDB_VALID_PEER ) {/*the trust record is valid*/
+ if ( flags & CERTDB_TRUSTED ) { /* trust this cert */
+ VALID_USAGE();
+ } else { /* don't trust this cert */
+ if (PR_TRUE == requiredUsage) {
+ PORT_SetError(SEC_ERROR_UNTRUSTED_CERT);
+ }
+ LOG_ERROR(log,cert,0,flags);
+ INVALID_USAGE();
+ }
+ }
+ break;
+ case certUsageSSLServerWithStepUp:
+ /* XXX - step up certs can't be directly trusted */
+ break;
+ case certUsageSSLCA:
+ break;
+ case certUsageEmailSigner:
+ case certUsageEmailRecipient:
+ flags = cert->trust->emailFlags;
+
+ /* is the cert directly trusted or not trusted ? */
+ if ( ( flags & ( CERTDB_VALID_PEER | CERTDB_TRUSTED ) ) ==
+ ( CERTDB_VALID_PEER | CERTDB_TRUSTED ) ) {
+ VALID_USAGE();
+ }
+ break;
+ case certUsageObjectSigner:
+ flags = cert->trust->objectSigningFlags;
+
+ /* is the cert directly trusted or not trusted ? */
+ if ( flags & CERTDB_VALID_PEER ) {/*the trust record is valid*/
+ if ( flags & CERTDB_TRUSTED ) { /* trust this cert */
+ VALID_USAGE();
+ } else { /* don't trust this cert */
+ if (PR_TRUE == requiredUsage) {
+ PORT_SetError(SEC_ERROR_UNTRUSTED_CERT);
+ }
+ LOG_ERROR(log,cert,0,flags);
+ INVALID_USAGE();
+ }
+ }
+ break;
+ case certUsageVerifyCA:
+ case certUsageStatusResponder:
+ flags = cert->trust->sslFlags;
+ /* is the cert directly trusted or not trusted ? */
+ if ( ( flags & ( CERTDB_VALID_CA | CERTDB_TRUSTED_CA ) ) ==
+ ( CERTDB_VALID_CA | CERTDB_TRUSTED_CA ) ) {
+ VALID_USAGE();
+ }
+ flags = cert->trust->emailFlags;
+ /* is the cert directly trusted or not trusted ? */
+ if ( ( flags & ( CERTDB_VALID_CA | CERTDB_TRUSTED_CA ) ) ==
+ ( CERTDB_VALID_CA | CERTDB_TRUSTED_CA ) ) {
+ VALID_USAGE();
+ }
+ flags = cert->trust->objectSigningFlags;
+ /* is the cert directly trusted or not trusted ? */
+ if ( ( flags & ( CERTDB_VALID_CA | CERTDB_TRUSTED_CA ) ) ==
+ ( CERTDB_VALID_CA | CERTDB_TRUSTED_CA ) ) {
+ VALID_USAGE();
+ }
+ break;
+ case certUsageAnyCA:
+ case certUsageProtectedObjectSigner:
+ case certUsageUserCertImport:
+ /* XXX to make the compiler happy. Should these be
+ * explicitly handled?
+ */
+ break;
+ }
+ }
+
+ if (PR_TRUE == revoked) {
+ INVALID_USAGE();
+ }
+
+ /* only optionally check signature the first time */
+ /* don't check CRL as part of cert chain, we are doing that separately */
+ /* rv = __CERT_VerifyCertChain(handle, cert, (PR_TRUE == checkedChain) ? PR_FALSE : checkSig,
+ certUsage, t, wincx, log, issuerCert, PR_TRUE); */
+ rv = __CERT_VerifyCertChain(handle, cert, (PR_TRUE == checkedChain) ? PR_FALSE : checkSig,
+ certUsage, t, wincx, log, checkedChain?PR_FALSE:PR_TRUE, &revoked);
+ checkedChain = PR_TRUE;
+
+ if (rv != SECSuccess) {
+ /* EXIT_IF_NOT_LOGGING(log); XXX ???? */
+ INVALID_USAGE();
+ }
+
+ /*
+ * Check OCSP revocation status, but only if the cert we are checking
+ * is not a status reponder itself. We only do this in the case
+ * where we checked the cert chain (above); explicit trust "wins"
+ * (avoids status checking, just as it avoids CRL checking) by
+ * bypassing this code.
+ */
+
+ if (PR_FALSE == checkedOCSP) {
+ checkedOCSP = PR_TRUE; /* only check OCSP once */
+ statusConfig = CERT_GetStatusConfig(handle);
+ if ( (! (requiredUsages & certificateUsageStatusResponder)) &&
+ statusConfig != NULL) {
+ if (statusConfig->statusChecker != NULL) {
+ rv = (* statusConfig->statusChecker)(handle, cert,
+ t, wincx);
+ if (rv != SECSuccess) {
+ LOG_ERROR(log,cert,0,0);
+ revoked = PR_TRUE;
+ INVALID_USAGE();
+ }
+ }
+ }
+ }
+
+ NEXT_ITERATION();
+ }
+
+ return(valid);
+}
+
+/* obsolete, do not use for new code */
+SECStatus
CERT_VerifyCert(CERTCertDBHandle *handle, CERTCertificate *cert,
PRBool checkSig, SECCertUsage certUsage, int64 t,
void *wincx, CERTVerifyLog *log)
@@ -1172,6 +1472,16 @@ loser:
* trust the issuer. Verify time against now.
*/
SECStatus
+CERT_VerifyCertificateNow(CERTCertDBHandle *handle, CERTCertificate *cert,
+ PRBool checkSig, SECCertificateUsage requiredUsages,
+ void *wincx, SECCertificateUsage* returnedUsages)
+{
+ return(CERT_VerifyCertificate(handle, cert, checkSig,
+ requiredUsages, PR_Now(), wincx, NULL, returnedUsages));
+}
+
+/* obsolete, do not use for new code */
+SECStatus
CERT_VerifyCertNow(CERTCertDBHandle *handle, CERTCertificate *cert,
PRBool checkSig, SECCertUsage certUsage, void *wincx)
{
@@ -1179,6 +1489,7 @@ CERT_VerifyCertNow(CERTCertDBHandle *handle, CERTCertificate *cert,
certUsage, PR_Now(), wincx, NULL));
}
+
/* [ FROM pcertdb.c ] */
/*
* Supported usage values and types:
diff --git a/security/nss/lib/nss/nss.def b/security/nss/lib/nss/nss.def
index e83d7dfeb..2d6268f05 100644
--- a/security/nss/lib/nss/nss.def
+++ b/security/nss/lib/nss/nss.def
@@ -695,6 +695,8 @@ CERT_VerifyOCSPResponseSignature;
CERT_GetOCSPResponseStatus;
CERT_DestroyOCSPCertID;
CERT_CreateOCSPCertID;
+CERT_VerifyCertificate;
+CERT_VerifyCertificateNow;
;+ local:
;+ *;
;+};