diff options
author | jpierre%netscape.com <devnull@localhost> | 2002-07-04 03:09:49 +0000 |
---|---|---|
committer | jpierre%netscape.com <devnull@localhost> | 2002-07-04 03:09:49 +0000 |
commit | bfabf37a89bb233b307e473fba61a5fbc3f97fa9 (patch) | |
tree | d8ed5b2e0cdadc97e209d780af034c3637f5830b /security/nss | |
parent | 8af685ac1b9aba1b6c72a09afd331581d5856ec8 (diff) | |
download | nss-hg-bfabf37a89bb233b307e473fba61a5fbc3f97fa9.tar.gz |
Add new CERT_VerifyCertificate function - fix for 149832
Diffstat (limited to 'security/nss')
-rw-r--r-- | security/nss/lib/certdb/cert.h | 21 | ||||
-rw-r--r-- | security/nss/lib/certdb/certt.h | 17 | ||||
-rw-r--r-- | security/nss/lib/certhigh/certvfy.c | 349 | ||||
-rw-r--r-- | security/nss/lib/nss/nss.def | 2 |
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: ;+ *; ;+}; |