📄 certchk.c
字号:
constrainedAttributeListPtr = findAttributeField( subjectAttributes,
CRYPT_CERTINFO_SUBJECTALTNAME, CRYPT_CERTINFO_RFC822NAME );
if( attributeListPtr != NULL && constrainedAttributeListPtr != NULL && \
wildcardMatch( constrainedAttributeListPtr, attributeListPtr,
FALSE ) == matchValue )
status = CRYPT_ERROR_INVALID;
attributeListPtr = findAttributeField( issuerAttributes,
constraintType, CRYPT_CERTINFO_DNSNAME );
constrainedAttributeListPtr = findAttributeField( subjectAttributes,
CRYPT_CERTINFO_SUBJECTALTNAME, CRYPT_CERTINFO_DNSNAME );
if( attributeListPtr != NULL && constrainedAttributeListPtr != NULL && \
wildcardMatch( constrainedAttributeListPtr, attributeListPtr,
FALSE ) == matchValue )
status = CRYPT_ERROR_INVALID;
attributeListPtr = findAttributeField( issuerAttributes,
constraintType, CRYPT_CERTINFO_UNIFORMRESOURCEIDENTIFIER );
constrainedAttributeListPtr = findAttributeField( subjectAttributes,
CRYPT_CERTINFO_SUBJECTALTNAME, CRYPT_CERTINFO_UNIFORMRESOURCEIDENTIFIER );
if( attributeListPtr != NULL && constrainedAttributeListPtr != NULL && \
wildcardMatch( constrainedAttributeListPtr, attributeListPtr,
FALSE ) == matchValue )
status = CRYPT_ERROR_INVALID;
if( cryptStatusError( status ) )
{
setErrorValues( CRYPT_CERTINFO_SUBJECTALTNAME,
CRYPT_ERRTYPE_CONSTRAINT );
return( status );
}
return( CRYPT_OK );
}
/* Check policy constraints placed by an issuer, checked if complianceLevel
>= CRYPT_COMPLIANCELEVEL_PKIX_FULL */
int checkPolicyConstraints( const CERT_INFO *subjectCertInfoPtr,
const ATTRIBUTE_LIST *issuerAttributes,
CRYPT_ATTRIBUTE_TYPE *errorLocus,
CRYPT_ERRTYPE_TYPE *errorType )
{
ATTRIBUTE_LIST *attributeListPtr, *constrainedAttributeListPtr;
assert( isReadPtr( subjectCertInfoPtr, CERT_INFO ) );
assert( isReadPtr( issuerAttributes, ATTRIBUTE_LIST ) );
/* Compare the issuer and subject policies if constraints exist */
attributeListPtr = findAttributeField( issuerAttributes,
CRYPT_CERTINFO_CERTPOLICYID,
CRYPT_ATTRIBUTE_NONE );
if( attributeListPtr == NULL )
return( CRYPT_OK );
constrainedAttributeListPtr = \
findAttributeField( subjectCertInfoPtr->attributes,
CRYPT_CERTINFO_CERTPOLICYID,
CRYPT_ATTRIBUTE_NONE );
if( constrainedAttributeListPtr == NULL )
{
setErrorValues( CRYPT_CERTINFO_CERTPOLICYID, CRYPT_ERRTYPE_CONSTRAINT );
return( CRYPT_ERROR_INVALID );
}
if( attributeListPtr->valueLength != \
constrainedAttributeListPtr->valueLength || \
memcmp( attributeListPtr->value, constrainedAttributeListPtr->value,
attributeListPtr->valueLength ) )
{
setErrorValues( CRYPT_CERTINFO_CERTPOLICYID, CRYPT_ERRTYPE_CONSTRAINT );
return( CRYPT_ERROR_INVALID );
}
return( CRYPT_OK );
}
/****************************************************************************
* *
* Check for Constraint Violations *
* *
****************************************************************************/
/* Check the validity of a CRL based on an issuer cert */
static int checkCRL( const CERT_INFO *crlInfoPtr,
const CERT_INFO *issuerCertInfoPtr,
const int complianceLevel,
CRYPT_ATTRIBUTE_TYPE *errorLocus,
CRYPT_ERRTYPE_TYPE *errorType )
{
ATTRIBUTE_LIST *attributeListPtr;
/* If it's a delta CRL, make sure that the CRL numbers make sense (that
is, that the delta CRL was issued after the full CRL) */
attributeListPtr = findAttributeField( crlInfoPtr->attributes,
CRYPT_CERTINFO_DELTACRLINDICATOR,
CRYPT_ATTRIBUTE_NONE );
if( attributeListPtr != NULL )
{
const int deltaCRLindicator = ( int ) attributeListPtr->intValue;
attributeListPtr = findAttributeField( crlInfoPtr->attributes,
CRYPT_CERTINFO_CRLNUMBER,
CRYPT_ATTRIBUTE_NONE );
if( attributeListPtr != NULL && \
attributeListPtr->intValue >= deltaCRLindicator )
{
setErrorValues( CRYPT_CERTINFO_DELTACRLINDICATOR,
CRYPT_ERRTYPE_CONSTRAINT );
return( CRYPT_ERROR_INVALID );
}
}
/* If it's a standalone CRL entry used purely as a container for
revocation data, don't try and perform any issuer-based checking */
if( issuerCertInfoPtr == NULL )
return( CRYPT_OK );
/* There is one universal case in which a cert is regarded as an invalid
issuer cert regardless of any special-case considerations for self-
signed/v1 certs, and that's when the cert is explicitly not trusted
for this purpose */
if( issuerCertInfoPtr->trustedUsage != CRYPT_ERROR && \
!( issuerCertInfoPtr->trustedUsage & CRYPT_KEYUSAGE_CRLSIGN ) )
{
setErrorValues( CRYPT_CERTINFO_TRUSTED_USAGE,
CRYPT_ERRTYPE_ISSUERCONSTRAINT );
return( CRYPT_ERROR_INVALID );
}
/* If the issuer is a v1 cert, we can't do any checking of issuer
attributes/capabilities */
if( issuerCertInfoPtr->version <= 2 )
return( CRYPT_OK );
/* If it's an oblivious check, we're done */
if( complianceLevel <= CRYPT_COMPLIANCELEVEL_OBLIVIOUS )
return( CRYPT_OK );
/* Make sure that the issuer has a key usage attribute present and can
sign certs (PKIX section 4.2.1.3) */
attributeListPtr = findAttributeField( issuerCertInfoPtr->attributes,
CRYPT_CERTINFO_KEYUSAGE,
CRYPT_ATTRIBUTE_NONE );
if( attributeListPtr == NULL || \
!( attributeListPtr->intValue & CRYPT_KEYUSAGE_CRLSIGN ) )
{
/* The issuer can't sign CRLs */
setErrorValues( CRYPT_CERTINFO_KEYUSAGE,
CRYPT_ERRTYPE_ISSUERCONSTRAINT );
return( CRYPT_ERROR_INVALID );
}
/* Make sure that there's a basicConstraints attribute present and that
the issuer is a CA (PKIX section 4.2.1.10) */
attributeListPtr = findAttributeField( issuerCertInfoPtr->attributes,
CRYPT_CERTINFO_CA,
CRYPT_ATTRIBUTE_NONE );
if( attributeListPtr == NULL || !attributeListPtr->intValue )
{
setErrorValues( CRYPT_CERTINFO_CA, CRYPT_ERRTYPE_ISSUERCONSTRAINT );
return( CRYPT_ERROR_INVALID );
}
return( CRYPT_OK );
}
/* Check the validity of a subject cert based on an issuer cert, with the
level of checking performed depending on the complianceLevel setting */
int checkCert( CERT_INFO *subjectCertInfoPtr,
const CERT_INFO *issuerCertInfoPtr,
const BOOLEAN shortCircuitCheck,
CRYPT_ATTRIBUTE_TYPE *errorLocus,
CRYPT_ERRTYPE_TYPE *errorType )
{
const ATTRIBUTE_LIST *subjectAttributes = subjectCertInfoPtr->attributes;
const ATTRIBUTE_LIST *issuerAttributes = \
( issuerCertInfoPtr != NULL ) ? issuerCertInfoPtr->attributes : NULL;
ATTRIBUTE_LIST *attributeListPtr;
const BOOLEAN selfSigned = ( subjectCertInfoPtr->flags & CERT_FLAG_SELFSIGNED );
BOOLEAN subjectIsCA = FALSE, issuerIsCA = FALSE;
const time_t currentTime = getTime();
int complianceLevel, status;
assert( isReadPtr( subjectCertInfoPtr, CERT_INFO ) );
assert( isWritePtr( errorLocus, sizeof( CRYPT_ATTRIBUTE_TYPE ) ) );
assert( isWritePtr( errorType, sizeof( CRYPT_ERRTYPE_TYPE ) ) );
/* If it's some form of certificate request or an OCSP object (which means
it isn't signed by an issuer in the normal sense), there's nothing to
check (yet) */
if( subjectCertInfoPtr->type == CRYPT_CERTTYPE_CERTREQUEST || \
subjectCertInfoPtr->type == CRYPT_CERTTYPE_REQUEST_CERT || \
subjectCertInfoPtr->type == CRYPT_CERTTYPE_REQUEST_REVOCATION || \
subjectCertInfoPtr->type == CRYPT_CERTTYPE_RTCS_REQUEST || \
subjectCertInfoPtr->type == CRYPT_CERTTYPE_RTCS_RESPONSE || \
subjectCertInfoPtr->type == CRYPT_CERTTYPE_OCSP_REQUEST || \
subjectCertInfoPtr->type == CRYPT_CERTTYPE_OCSP_RESPONSE )
return( CRYPT_OK );
/* It's an issuer-signed object, there must be an issuer cert present
unless its a standalone single CRL entry that acts purely as a
container for revocation data */
assert( subjectCertInfoPtr->type == CRYPT_CERTTYPE_CRL || \
isReadPtr( issuerCertInfoPtr, CERT_INFO ) );
/* Determine how much checking we need to perform */
status = krnlSendMessage( subjectCertInfoPtr->ownerHandle,
IMESSAGE_GETATTRIBUTE, &complianceLevel,
CRYPT_OPTION_CERT_COMPLIANCELEVEL );
if( cryptStatusError( status ) )
return( status );
/* If we're checking a CRL, call the special-case routine for this */
if( subjectCertInfoPtr->type == CRYPT_CERTTYPE_CRL )
return( checkCRL( subjectCertInfoPtr, issuerCertInfoPtr,
complianceLevel, errorLocus, errorType ) );
/* There is one universal case in which a cert is regarded as an invalid
issuer cert regardless of any special-case considerations for self-
signed/v1 certs, and that's when the cert is explicitly not trusted
for this purpose */
if( issuerCertInfoPtr->trustedUsage != CRYPT_ERROR && \
!( issuerCertInfoPtr->trustedUsage & CRYPT_KEYUSAGE_KEYCERTSIGN ) )
{
/* The issuer can sign certs but is explicitly not trusted to do
so */
setErrorValues( CRYPT_CERTINFO_TRUSTED_USAGE,
CRYPT_ERRTYPE_ISSUERCONSTRAINT );
return( CRYPT_ERROR_INVALID );
}
if( selfSigned )
{
/* Check whether the issuer (== subject) is explicitly not trusted
to sign itself */
if( subjectCertInfoPtr->trustedUsage != CRYPT_ERROR && \
!( subjectCertInfoPtr->trustedUsage & CRYPT_KEYUSAGE_KEYCERTSIGN ) )
{
setErrorValues( CRYPT_CERTINFO_TRUSTED_USAGE,
CRYPT_ERRTYPE_CONSTRAINT );
return( CRYPT_ERROR_INVALID );
}
}
/* If we're not running in oblivious mode, we're done */
if( complianceLevel < CRYPT_COMPLIANCELEVEL_REDUCED )
return( CRYPT_OK );
/* Check that the validity period is in order. If we're checking an
existing cert then the start time has to be valid, if we're creating
a new cert then it doesn't have to be valid since the cert could be
created for use in the future */
if( currentTime < MIN_TIME_VALUE )
{
/* Time is broken, we can't reliably check for expiry times */
setErrorValues( CRYPT_CERTINFO_VALIDFROM, CRYPT_ERRTYPE_CONSTRAINT );
return( CRYPT_ERROR_INVALID );
}
if( subjectCertInfoPtr->startTime >= subjectCertInfoPtr->endTime || \
( subjectCertInfoPtr->certificate != NULL && \
currentTime < subjectCertInfoPtr->startTime ) )
{
setErrorValues( CRYPT_CERTINFO_VALIDFROM, CRYPT_ERRTYPE_CONSTRAINT );
return( CRYPT_ERROR_INVALID );
}
if( currentTime > subjectCertInfoPtr->endTime )
{
setErrorValues( CRYPT_CERTINFO_VALIDTO, CRYPT_ERRTYPE_CONSTRAINT );
return( CRYPT_ERROR_INVALID );
}
/* If it's a self-signed cert or we're doing a short-circuit check of a
cert in a chain that has already been checked, and we've already
checked it at the appropriate level, there's no need to perform any
further checks */
if( ( selfSigned || shortCircuitCheck ) && \
( subjectCertInfoPtr->maxCheckLevel >= complianceLevel ) )
return( CRYPT_OK );
/* If the cert isn't self-signed, check name chaining */
if( !selfSigned )
{
/* Check that the subject issuer and issuer subject names chain
properly. If the DNs are present in pre-encoded form, we do
a binary comparison, which is faster than calling compareDN() */
if( subjectCertInfoPtr->certificate != NULL )
{
if( subjectCertInfoPtr->issuerDNsize != \
issuerCertInfoPtr->subjectDNsize || \
memcmp( subjectCertInfoPtr->issuerDNptr,
issuerCertInfoPtr->subjectDNptr,
subjectCertInfoPtr->issuerDNsize ) )
{
setErrorValues( CRYPT_CERTINFO_ISSUERNAME,
CRYPT_ERRTYPE_CONSTRAINT );
return( CRYPT_ERROR_INVALID );
}
}
else
if( !compareDN( subjectCertInfoPtr->issuerName,
issuerCertInfoPtr->subjectName, FALSE ) )
{
setErrorValues( CRYPT_CERTINFO_ISSUERNAME,
CRYPT_ERRTYPE_CONSTRAINT );
return( CRYPT_ERROR_INVALID );
}
}
/* Determine whether the subject or issuer are CA certs */
attributeListPtr = findAttributeField( subjectAttributes,
CRYPT_CERTINFO_CA,
CRYPT_ATTRIBUTE_NONE );
if( attributeListPtr != NULL )
subjectIsCA = attributeListPtr->intValue;
attributeListPtr = findAttributeField( issuerAttributes,
CRYPT_CERTINFO_CA,
CRYPT_ATTRIBUTE_NONE );
if( attributeListPtr != NULL )
issuerIsCA = attributeListPtr->intValue;
/* If the issuer is a non self-signed v3 cert, check the issuer
attributes/capabilities. Note that this means that a self-signed
cert has an implicitly permitted usage of keyCertSign for itself even
if it's a non-CA cert (a Smith and Wesson beats four aces) */
if( !selfSigned && issuerCertInfoPtr->version > 2 )
{
/* Make sure that the issuer has a key usage attribute present and
can sign certs (PKIX section 4.2.1.3) */
attributeListPtr = findAttributeField( issuerAttributes,
CRYPT_CERTINFO_KEYUSAGE,
CRYPT_ATTRIBUTE_NONE );
if( attributeListPtr == NULL || \
!( attributeListPtr->intValue & CRYPT_KEYUSAGE_KEYCERTSIGN ) )
{
/* The issuer can't sign certs */
setErrorValues( CRYPT_CERTINFO_KEYUSAGE,
CRYPT_ERRTYPE_ISSUERCONSTRAINT );
return( CRYPT_ERROR_INVALID );
}
/* Make sure that there's a basicConstraints attribute present/the
issuer is a CA (PKIX section 4.2.1.10) */
if( !issuerIsCA )
{
setErrorValues( CRYPT_CERTINFO_CA, CRYPT_ERRTYPE_ISSUERCONSTRAINT );
return( CRYPT_ERROR_INVALID );
}
}
/* If we're doing a reduced level of checking, we're done */
if( complianceLevel < CRYPT_COMPLIANCELEVEL_STANDARD )
{
if( subjectCertInfoPtr->maxCheckLevel < complianceLevel )
subjectCertInfoPtr->maxCheckLevel = complianceLevel;
return( CRYPT_OK );
}
/* Check that the cert usage flags are present and consistent. The key
usage checking level ranges from CRYPT_COMPLIANCELEVEL_STANDARD to
CRYPT_COMPLIANCELEVEL_PKIX_PARTIAL so we re-do the check even if it's
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -