📄 certchk.c
字号:
/* Enforce validity period nesting if necessary */
krnlSendMessage( subjectCertInfoPtr->ownerHandle,
RESOURCE_IMESSAGE_GETATTRIBUTE, &validityNesting,
CRYPT_OPTION_CERT_DECODE_VALIDITYNESTING );
if( validityNesting )
{
if( subjectCertInfoPtr->startTime < issuerCertInfoPtr->startTime )
{
setErrorInfo( subjectCertInfoPtr, CRYPT_CERTINFO_VALIDFROM,
CRYPT_ERRTYPE_CONSTRAINT );
return( CRYPT_ERROR_INVALID );
}
if( subjectCertInfoPtr->endTime > issuerCertInfoPtr->endTime )
{
setErrorInfo( subjectCertInfoPtr, CRYPT_CERTINFO_VALIDTO,
CRYPT_ERRTYPE_CONSTRAINT );
return( CRYPT_ERROR_INVALID );
}
}
/* Check that the cert usage flags are consistent */
if( !( subjectCertInfoPtr->flags & CERT_FLAG_CERTCHECKED ) && \
subjectCertInfoPtr->type != CRYPT_CERTTYPE_ATTRIBUTE_CERT )
{
status = checkKeyUsageFlags( subjectCertInfoPtr );
if( cryptStatusError( status ) )
return( status );
}
/* If the cert isn't self-signed, check name and altName chaining */
if( !( subjectCertInfoPtr->flags & CERT_FLAG_SELFSIGNED ) )
{
/* Check that the subject issuer and issuer subject names chain
properly */
if( !compareDN( subjectCertInfoPtr->issuerName,
issuerCertInfoPtr->subjectName, FALSE ) )
{
setErrorInfo( subjectCertInfoPtr, CRYPT_CERTINFO_ISSUERNAME,
CRYPT_ERRTYPE_CONSTRAINT );
return( CRYPT_ERROR_INVALID );
}
/* If an issuer altname is present, check that it chains correctly */
if( subjectCertInfoPtr->type != CRYPT_CERTTYPE_ATTRIBUTE_CERT )
{
boolean1 = ( findAttribute( issuerAttributes,
CRYPT_CERTINFO_SUBJECTALTNAME ) != NULL ) ? TRUE : FALSE;
boolean2 = ( findAttribute( subjectAttributes,
CRYPT_CERTINFO_ISSUERALTNAME ) != NULL ) ? TRUE : FALSE;
if( boolean1 ^ boolean2 )
{
/* The altName must be present in both certs */
if( boolean1 )
{
setErrorInfo( subjectCertInfoPtr,
CRYPT_CERTINFO_ISSUERALTNAME,
CRYPT_ERRTYPE_CONSTRAINT );
}
else
setErrorInfo( subjectCertInfoPtr,
CRYPT_CERTINFO_SUBJECTALTNAME,
CRYPT_ERRTYPE_ISSUERCONSTRAINT );
return( CRYPT_ERROR_INVALID );
}
if( boolean1 && boolean2 )
{
subjectCertInfoPtr->errorLocus = compareAltNames( subjectAttributes,
issuerAttributes );
if( subjectCertInfoPtr->errorLocus != CRYPT_ATTRIBUTE_NONE )
return( CRYPT_ERROR_INVALID );
}
}
}
/* If there's a path length constraint present, make sure the cert is a
CA cert. If the issuer path length is set to zero, make sure the
subject is a non-CA cert */
attributeListPtr = findAttributeField( issuerAttributes,
CRYPT_CERTINFO_PATHLENCONSTRAINT, CRYPT_ATTRIBUTE_NONE );
if( attributeListPtr != NULL )
{
if( !issuerIsCA )
{
setErrorInfo( subjectCertInfoPtr, CRYPT_CERTINFO_CA,
CRYPT_ERRTYPE_ISSUERCONSTRAINT );
return( CRYPT_ERROR_INVALID );
}
if( !( subjectCertInfoPtr->flags & CERT_FLAG_SELFSIGNED ) && \
!attributeListPtr->value && subjectIsCA )
{
setErrorInfo( subjectCertInfoPtr, CRYPT_CERTINFO_PATHLENCONSTRAINT,
CRYPT_ERRTYPE_ISSUERCONSTRAINT );
return( CRYPT_ERROR_INVALID );
}
}
if( !( subjectCertInfoPtr->flags & CERT_FLAG_CERTCHECKED ) && \
findAttributeField( subjectAttributes,
CRYPT_CERTINFO_PATHLENCONSTRAINT, CRYPT_ATTRIBUTE_NONE ) && \
!subjectIsCA )
{
setErrorInfo( subjectCertInfoPtr, CRYPT_CERTINFO_CA,
CRYPT_ERRTYPE_CONSTRAINT );
return( CRYPT_ERROR_INVALID );
}
/* If there's a name constraint present, make sure the cert is a CA
cert */
if( !( subjectCertInfoPtr->flags & CERT_FLAG_CERTCHECKED ) && \
findAttribute( subjectAttributes, CRYPT_CERTINFO_NAMECONSTRAINTS ) && \
!subjectIsCA )
{
setErrorInfo( subjectCertInfoPtr, CRYPT_CERTINFO_CA,
CRYPT_ERRTYPE_CONSTRAINT );
return( CRYPT_ERROR_INVALID );
}
if( findAttribute( issuerAttributes, CRYPT_CERTINFO_NAMECONSTRAINTS ) && \
!issuerIsCA )
{
setErrorInfo( subjectCertInfoPtr, CRYPT_CERTINFO_CA,
CRYPT_ERRTYPE_ISSUERCONSTRAINT );
return( CRYPT_ERROR_INVALID );
}
/* If the issuing cert has name constraints and isn't self-signed, make
sure the subject name and altName falls within the constrained
subtrees. Since excluded subtrees override permitted subtrees, we
check these first */
if( !( subjectCertInfoPtr->flags & CERT_FLAG_SELFSIGNED ) )
{
if( findAttribute( issuerAttributes, \
CRYPT_CERTINFO_EXCLUDEDSUBTREES ) != NULL && \
cryptStatusError( checkNameConstraints( subjectCertInfoPtr,
issuerAttributes, TRUE ) ) )
return( CRYPT_ERROR_INVALID );
if( findAttribute( issuerAttributes,
CRYPT_CERTINFO_PERMITTEDSUBTREES ) != NULL && \
cryptStatusError( checkNameConstraints( subjectCertInfoPtr,
issuerAttributes, FALSE ) ) )
return( CRYPT_ERROR_INVALID );
}
/* If there's a policy constraint present, make sure the cert is a CA
cert. If the skip count is set to zero (ie the constraint applies to
the current cert), check the issuer constraints against the subject */
if( !( subjectCertInfoPtr->flags & CERT_FLAG_CERTCHECKED ) && \
findAttribute( subjectAttributes, CRYPT_CERTINFO_POLICYCONSTRAINTS ) && \
!subjectIsCA )
{
setErrorInfo( subjectCertInfoPtr, CRYPT_CERTINFO_CA,
CRYPT_ERRTYPE_CONSTRAINT );
return( CRYPT_ERROR_INVALID );
}
if( findAttribute( issuerAttributes, CRYPT_CERTINFO_POLICYCONSTRAINTS ) )
{
if( !issuerIsCA )
{
setErrorInfo( subjectCertInfoPtr, CRYPT_CERTINFO_CA,
CRYPT_ERRTYPE_ISSUERCONSTRAINT );
return( CRYPT_ERROR_INVALID );
}
/* Make sure the skip count is set to zero, which means the constraint
applies to the subject */
attributeListPtr = findAttribute( issuerAttributes,
CRYPT_CERTINFO_REQUIREEXPLICITPOLICY );
if( attributeListPtr != NULL && attributeListPtr->value == 0 )
{
status = checkPolicyConstraints( subjectCertInfoPtr,
issuerAttributes );
if( cryptStatusError( status ) )
return( status );
}
}
/* If it's not a self-signed cert, make sure that the issuer cert is of
the appropriate type */
if( !( subjectCertInfoPtr->flags & CERT_FLAG_SELFSIGNED ) )
{
/* If there's a key usage attribute present, make sure the issuer can
sign certs */
attributeListPtr = findAttribute( issuerAttributes,
CRYPT_CERTINFO_KEYUSAGE );
if( attributeListPtr != NULL )
{
if( !( attributeListPtr->value & issuerCertInfoPtr->trustedUsage & \
CRYPT_KEYUSAGE_KEYCERTSIGN ) )
{
setErrorInfo( subjectCertInfoPtr,
( attributeListPtr->value & CRYPT_KEYUSAGE_KEYCERTSIGN ) ? \
CRYPT_CERTINFO_TRUSTED_USAGE : CRYPT_CERTINFO_KEYUSAGE,
CRYPT_ERRTYPE_ISSUERCONSTRAINT );
return( CRYPT_ERROR_INVALID );
}
}
else
/* There's no key usage present, make sure the issuer is at least
trusted to sign certs */
if( !( issuerCertInfoPtr->trustedUsage & CRYPT_KEYUSAGE_KEYCERTSIGN ) )
{
setErrorInfo( subjectCertInfoPtr, CRYPT_CERTINFO_TRUSTED_USAGE,
CRYPT_ERRTYPE_ISSUERCONSTRAINT );
return( CRYPT_ERROR_INVALID );
}
/* If a basic constraints attribute is present, make sure the issuer
is a CA */
if( findAttribute( issuerAttributes, CRYPT_CERTINFO_CA ) != NULL && \
!issuerIsCA )
{
setErrorInfo( subjectCertInfoPtr, CRYPT_CERTINFO_CA,
CRYPT_ERRTYPE_ISSUERCONSTRAINT );
return( CRYPT_ERROR_INVALID );
}
}
else
/* There is one special case in which a self-signed cert is regarded
as an invalid issuer cert and that's when the cert is explicitly
not trusted for this purpose */
if( !( subjectCertInfoPtr->trustedUsage & CRYPT_KEYUSAGE_KEYCERTSIGN ) )
{
setErrorInfo( subjectCertInfoPtr, CRYPT_CERTINFO_TRUSTED_USAGE,
CRYPT_ERRTYPE_CONSTRAINT );
return( CRYPT_ERROR_INVALID );
}
/* Remember that we've passed all the checks so we can avoid performing
as many as possible again in the future */
subjectCertInfoPtr->flags |= CERT_FLAG_CERTCHECKED;
return( CRYPT_OK );
}
/* Check that a key cert is valid for a particular purpose. This is used
mainly to check that contexts and certs are valid for key exchange/sig.
generation/cert signing, and isn't as rigorous as the cert/issuer cert
check in checkCert(). In some instances we need to check for specific
types of usage which are dependant on the peculiarities of object types,
so if it's available we pass in the exact requested cryptlib-level usage
as well */
int checkCertUsage( const CERT_INFO *certInfoPtr, const int keyUsage,
const RESOURCE_MESSAGE_CHECK_TYPE exactUsage,
CRYPT_ATTRIBUTE_TYPE *errorLocus,
CRYPT_ERRTYPE_TYPE *errorType )
{
ATTRIBUTE_LIST *attributeListPtr;
const BOOLEAN isV1selfSigned = \
( certInfoPtr->version == 1 && \
( certInfoPtr->flags & CERT_FLAG_SELFSIGNED ) ) ? TRUE : FALSE;
/* PKCS #10 cert requests are special-case objects in that the key they
contain is usable only for signature checking of the self-signature
on the object. This is problematic because the keyUsage may indicate
that the key is valid for other things as well, or not valid for
signature checking. To get around this, we indicate that the key has
a single trusted usage, signature checking, and disallow any other
usage regardless of what the keyUsage says. The keyUsage usage is
only valid once the request has been converted into a cert */
if( certInfoPtr->type == CRYPT_CERTTYPE_CERTREQUEST )
{
if( exactUsage == RESOURCE_MESSAGE_CHECK_PKC_SIGCHECK )
return( CRYPT_OK );
if( errorLocus != NULL )
{
/* PKCS #10 requests have a single implicit trusted usage which
is sig-checking the self-signature on the object */
*errorLocus = CRYPT_CERTINFO_TRUSTED_USAGE;
*errorType = CRYPT_ERRTYPE_CONSTRAINT;
}
return( CRYPT_ERROR_INVALID );
}
/* If we're looking for a CA cert, make sure that either the
basicConstraints CA flag is set or if there's no basicConstraints
present that it's a v1 self-signed cert. We can't do a relatively
straightforward yes/no check for a self-signed v1 cert (which by
convention is a CA root cert) because there are some (theoretically
illegal) variations such as the presence of v3 extensions which can
modify this, so we have to treat it as a special case of a v3 cert */
if( exactUsage == RESOURCE_MESSAGE_CHECK_CA )
{
attributeListPtr = findAttributeField( certInfoPtr->attributes,
CRYPT_CERTINFO_CA, CRYPT_ATTRIBUTE_NONE );
if( attributeListPtr != NULL && \
!( attributeListPtr->value || isV1selfSigned ) )
{
if( errorLocus != NULL )
{
*errorLocus = CRYPT_CERTINFO_CA;
*errorType = CRYPT_ERRTYPE_CONSTRAINT;
}
return( CRYPT_ERROR_INVALID );
}
}
/* Check and enforce the keyUsage attribute if there's one present */
attributeListPtr = findAttributeField( certInfoPtr->attributes,
CRYPT_CERTINFO_KEYUSAGE, CRYPT_ATTRIBUTE_NONE );
if( attributeListPtr != NULL && keyUsage != CRYPT_UNUSED )
{
const int trustedUsage = \
attributeListPtr->value & certInfoPtr->trustedUsage;
BOOLEAN usageOK = FALSE;
/* If it's a key agreement usage the checking gets a bit complex, we
have to make sure it's both a permitted usage and not an excluded
usage */
if( keyUsage == CRYPT_KEYUSAGE_ENCIPHERONLY || \
keyUsage == CRYPT_KEYUSAGE_DECIPHERONLY )
{
const int excludedUsage = \
( keyUsage == CRYPT_KEYUSAGE_ENCIPHERONLY ) ? \
CRYPT_KEYUSAGE_DECIPHERONLY : CRYPT_KEYUSAGE_ENCIPHERONLY;
if( ( trustedUsage & keyUsage ) && \
!( trustedUsage & excludedUsage ) )
usageOK = TRUE;
}
else
/* Conventional usage flag, do a straight check */
if( trustedUsage & keyUsage )
usageOK = TRUE;
if( !usageOK )
{
if( errorLocus != NULL )
{
*errorLocus = ( attributeListPtr->value & keyUsage ) ? \
CRYPT_CERTINFO_TRUSTED_USAGE : CRYPT_CERTINFO_KEYUSAGE;
*errorType = CRYPT_ERRTYPE_CONSTRAINT;
}
return( CRYPT_ERROR_INVALID );
}
}
else
{
/* There is one special case in which a cert with no explicit key
usage can't be used for a particular purpose and that's when the
cert is explicitly not trusted for the purpose */
if( keyUsage != CRYPT_UNUSED && \
!( certInfoPtr->trustedUsage & keyUsage ) )
{
*errorLocus = CRYPT_CERTINFO_TRUSTED_USAGE;
*errorType = CRYPT_ERRTYPE_CONSTRAINT;
return( CRYPT_ERROR_INVALID );
}
/* If we're looking for a CA and there's no keyUsage attribute
present, the cert either has to be v1 self-signed or an unsigned
(ie not-yet-completed) cert for which the appropriate key usage
will be added when the cert is signed */
if( exactUsage == RESOURCE_MESSAGE_CHECK_CA && \
!( isV1selfSigned || certInfoPtr->certificate == NULL ) )
{
if( errorLocus != NULL )
{
*errorLocus = CRYPT_CERTINFO_KEYUSAGE;
*errorType = CRYPT_ERRTYPE_CONSTRAINT;
}
return( CRYPT_ERROR_INVALID );
}
}
/* Check and enforce the privateKeyUsage attribute if there's one
present */
if( findAttributeField( certInfoPtr->attributes,
CRYPT_CERTINFO_PRIVATEKEYUSAGEPERIOD, CRYPT_ATTRIBUTE_NONE ) != NULL )
{
const time_t currentTime = time( NULL );
attributeListPtr = findAttributeField( certInfoPtr->attributes,
CRYPT_CERTINFO_PRIVATEKEY_NOTBEFORE, CRYPT_ATTRIBUTE_NONE );
if( attributeListPtr != NULL && \
currentTime < *( ( time_t * ) attributeListPtr->smallData ) )
{
*errorLocus = CRYPT_CERTINFO_PRIVATEKEY_NOTBEFORE;
*errorType = CRYPT_ERRTYPE_CONSTRAINT;
return( CRYPT_ERROR_INVALID );
}
attributeListPtr = findAttributeField( certInfoPtr->attributes,
CRYPT_CERTINFO_PRIVATEKEY_NOTAFTER, CRYPT_ATTRIBUTE_NONE );
if( attributeListPtr != NULL && \
currentTime > *( ( time_t * ) attributeListPtr->smallData ) )
{
if( errorLocus != NULL )
{
*errorLocus = CRYPT_CERTINFO_PRIVATEKEY_NOTAFTER;
*errorType = CRYPT_ERRTYPE_CONSTRAINT;
}
return( CRYPT_ERROR_INVALID );
}
}
return( CRYPT_OK );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -