mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-11 20:35:50 +00:00
Add new CERT_VerifyCertificate function - fix for 149832
This commit is contained in:
parent
1267864ca1
commit
967d483ebe
@ -34,7 +34,7 @@
|
||||
/*
|
||||
* cert.h - public data structures and prototypes for the certificate library
|
||||
*
|
||||
* $Id: cert.h,v 1.16 2002/06/19 15:58:22 rangansen%netscape.com Exp $
|
||||
* $Id: cert.h,v 1.17 2002/07/04 03:09:29 jpierre%netscape.com Exp $
|
||||
*/
|
||||
|
||||
#ifndef _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.
|
||||
|
@ -33,7 +33,7 @@
|
||||
/*
|
||||
* certt.h - public data structures for the certificate library
|
||||
*
|
||||
* $Id: certt.h,v 1.18 2002/06/13 21:42:41 relyea%netscape.com Exp $
|
||||
* $Id: certt.h,v 1.19 2002/07/04 03:09:29 jpierre%netscape.com Exp $
|
||||
*/
|
||||
#ifndef _CERTT_H_
|
||||
#define _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.
|
||||
*/
|
||||
|
@ -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:
|
||||
|
@ -695,6 +695,8 @@ CERT_VerifyOCSPResponseSignature;
|
||||
CERT_GetOCSPResponseStatus;
|
||||
CERT_DestroyOCSPCertID;
|
||||
CERT_CreateOCSPCertID;
|
||||
CERT_VerifyCertificate;
|
||||
CERT_VerifyCertificateNow;
|
||||
;+ local:
|
||||
;+ *;
|
||||
;+};
|
||||
|
Loading…
Reference in New Issue
Block a user