📄 certchk.c
字号:
already been done at a lower level */
if( subjectCertInfoPtr->maxCheckLevel < CRYPT_COMPLIANCELEVEL_PKIX_PARTIAL && \
subjectCertInfoPtr->type != CRYPT_CERTTYPE_ATTRIBUTE_CERT )
{
status = checkKeyUsageFlags( subjectCertInfoPtr, complianceLevel,
errorLocus, errorType );
if( cryptStatusError( status ) )
return( status );
}
/* If we're not doing at least partial PKIX checking, we're done */
if( complianceLevel < CRYPT_COMPLIANCELEVEL_PKIX_PARTIAL )
{
if( subjectCertInfoPtr->maxCheckLevel < complianceLevel )
subjectCertInfoPtr->maxCheckLevel = complianceLevel;
return( CRYPT_OK );
}
/* Check various CA vs. non-CA restrictions: Name, policy, and path-
length constraints can only be present in CA certs */
if( !subjectIsCA )
{
if( checkAttributePresent( subjectAttributes, \
CRYPT_CERTINFO_NAMECONSTRAINTS ) )
{
setErrorValues( CRYPT_CERTINFO_CA, CRYPT_ERRTYPE_CONSTRAINT );
return( CRYPT_ERROR_INVALID );
}
if( checkAttributePresent( subjectAttributes, \
CRYPT_CERTINFO_POLICYCONSTRAINTS ) )
{
setErrorValues( CRYPT_CERTINFO_CA, CRYPT_ERRTYPE_CONSTRAINT );
return( CRYPT_ERROR_INVALID );
}
if( findAttributeField( subjectAttributes,
CRYPT_CERTINFO_PATHLENCONSTRAINT,
CRYPT_ATTRIBUTE_NONE ) )
{
setErrorValues( CRYPT_CERTINFO_CA, CRYPT_ERRTYPE_CONSTRAINT );
return( CRYPT_ERROR_INVALID );
}
}
if( !issuerIsCA )
{
if( checkAttributePresent( issuerAttributes, \
CRYPT_CERTINFO_NAMECONSTRAINTS ) )
{
setErrorValues( CRYPT_CERTINFO_CA, CRYPT_ERRTYPE_ISSUERCONSTRAINT );
return( CRYPT_ERROR_INVALID );
}
if( checkAttributePresent( issuerAttributes, \
CRYPT_CERTINFO_POLICYCONSTRAINTS ) )
{
setErrorValues( CRYPT_CERTINFO_CA,
CRYPT_ERRTYPE_ISSUERCONSTRAINT );
return( CRYPT_ERROR_INVALID );
}
if( findAttributeField( issuerAttributes,
CRYPT_CERTINFO_PATHLENCONSTRAINT,
CRYPT_ATTRIBUTE_NONE ) )
{
setErrorValues( CRYPT_CERTINFO_CA, CRYPT_ERRTYPE_ISSUERCONSTRAINT );
return( CRYPT_ERROR_INVALID );
}
}
/* If there's a path length constraint present and set to zero, make
sure that the subject is a non-CA cert */
attributeListPtr = findAttributeField( issuerAttributes,
CRYPT_CERTINFO_PATHLENCONSTRAINT,
CRYPT_ATTRIBUTE_NONE );
if( attributeListPtr != NULL && attributeListPtr->intValue <= 0 && \
!selfSigned && subjectIsCA )
{
setErrorValues( CRYPT_CERTINFO_PATHLENCONSTRAINT,
CRYPT_ERRTYPE_ISSUERCONSTRAINT );
return( CRYPT_ERROR_INVALID );
}
/* If we're not doing full PKIX checking, we're done */
if( complianceLevel < CRYPT_COMPLIANCELEVEL_PKIX_FULL )
{
if( subjectCertInfoPtr->maxCheckLevel < complianceLevel )
subjectCertInfoPtr->maxCheckLevel = complianceLevel;
return( CRYPT_OK );
}
/* If the cert isn't self-signed and an issuer altname is present, check
that it chains correctly. No-one can quite agree on how chaining of
altNames is really supposed to work, it's only their rarity that
prevents this from being much of a problem */
if( !selfSigned && \
subjectCertInfoPtr->type != CRYPT_CERTTYPE_ATTRIBUTE_CERT )
{
const BOOLEAN boolean1 = checkAttributePresent( issuerAttributes,
CRYPT_CERTINFO_SUBJECTALTNAME );
const BOOLEAN boolean2 = checkAttributePresent( subjectAttributes,
CRYPT_CERTINFO_ISSUERALTNAME );
/* If present, the attribute must be present and match in both
certs */
if( boolean1 && !boolean2 )
{
setErrorValues( CRYPT_CERTINFO_ISSUERALTNAME,
CRYPT_ERRTYPE_CONSTRAINT );
return( CRYPT_ERROR_INVALID );
}
if( boolean2 && !boolean1 )
{
setErrorValues( CRYPT_CERTINFO_SUBJECTALTNAME,
CRYPT_ERRTYPE_ISSUERCONSTRAINT );
return( CRYPT_ERROR_INVALID );
}
if( boolean1 && boolean2 )
{
const CRYPT_ATTRIBUTE_TYPE altNameComponent = \
compareAltNames( subjectAttributes,
issuerAttributes );
if( altNameComponent != CRYPT_ATTRIBUTE_NONE )
{
setErrorValues( altNameComponent,
CRYPT_ERRTYPE_CONSTRAINT );
return( CRYPT_ERROR_INVALID );
}
}
}
/* If the issuing cert has name constraints and isn't self-signed, make
sure that the subject name and altName falls within the constrained
subtrees. Since excluded subtrees override permitted subtrees, we
check these first */
if( !selfSigned )
{
attributeListPtr = findAttributeField( issuerAttributes,
CRYPT_CERTINFO_EXCLUDEDSUBTREES,
CRYPT_ATTRIBUTE_NONE );
if( attributeListPtr != NULL )
{
if( cryptStatusError( \
checkNameConstraints( subjectCertInfoPtr, attributeListPtr,
TRUE, errorLocus, errorType ) ) )
return( CRYPT_ERROR_INVALID );
}
attributeListPtr = findAttributeField( issuerAttributes,
CRYPT_CERTINFO_PERMITTEDSUBTREES,
CRYPT_ATTRIBUTE_NONE );
if( attributeListPtr != NULL )
{
if( cryptStatusError( \
checkNameConstraints( subjectCertInfoPtr, attributeListPtr,
FALSE, errorLocus, errorType ) ) )
return( CRYPT_ERROR_INVALID );
}
}
/* If there's a policy constraint present and the skip count is set to
zero (i.e. the constraint applies to the current cert), check the
issuer constraints against the subject */
attributeListPtr = findAttributeField( issuerAttributes,
CRYPT_CERTINFO_REQUIREEXPLICITPOLICY,
CRYPT_ATTRIBUTE_NONE );
if( attributeListPtr != NULL && attributeListPtr->intValue <= 0 )
{
status = checkPolicyConstraints( subjectCertInfoPtr,
issuerAttributes,
errorLocus, errorType );
if( cryptStatusError( status ) )
return( status );
}
if( subjectCertInfoPtr->maxCheckLevel < complianceLevel )
subjectCertInfoPtr->maxCheckLevel = complianceLevel;
return( CRYPT_OK );
}
/* Check that a certificate 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 that 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 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;
int complianceLevel, status;
assert( isReadPtr( certInfoPtr, CERT_INFO ) );
assert( isWritePtr( errorLocus, sizeof( CRYPT_ATTRIBUTE_TYPE ) ) );
assert( isWritePtr( errorType, sizeof( CRYPT_ERRTYPE_TYPE ) ) );
/* 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 (it can't be used for general-purpose usages, which
would make it equivalent to a trusted self-signed cert). 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 actual keyUsage usage is only valid once the
request has been converted into a cert */
if( certInfoPtr->type == CRYPT_CERTTYPE_CERTREQUEST )
{
if( exactUsage == MESSAGE_CHECK_PKC_SIGCHECK )
return( CRYPT_OK );
setErrorValues( CRYPT_CERTINFO_TRUSTED_USAGE,
CRYPT_ERRTYPE_CONSTRAINT );
return( CRYPT_ERROR_INVALID );
}
/* Determine how much checking we need to perform */
status = krnlSendMessage( certInfoPtr->ownerHandle, IMESSAGE_GETATTRIBUTE,
&complianceLevel,
CRYPT_OPTION_CERT_COMPLIANCELEVEL );
if( cryptStatusError( status ) )
return( status );
/* If we're looking for a CA cert, make sure that either the
basicConstraints CA flag is set and the keyUsage indicates a CA usage,
or if there's no basicConstraints/keyUsage present that it's a v1
self-signed cert (PKIX sections 4.2.1.3 and 4.2.1.10) */
if( exactUsage == MESSAGE_CHECK_CA && \
complianceLevel >= CRYPT_COMPLIANCELEVEL_REDUCED && \
!isV1selfSigned )
{
attributeListPtr = findAttributeField( certInfoPtr->attributes,
CRYPT_CERTINFO_CA,
CRYPT_ATTRIBUTE_NONE );
if( attributeListPtr == NULL || !attributeListPtr->intValue )
{
setErrorValues( CRYPT_CERTINFO_CA, CRYPT_ERRTYPE_CONSTRAINT );
return( CRYPT_ERROR_INVALID );
}
attributeListPtr = findAttributeField( certInfoPtr->attributes,
CRYPT_CERTINFO_KEYUSAGE,
CRYPT_ATTRIBUTE_NONE );
if( attributeListPtr == NULL || \
!( attributeListPtr->intValue & certInfoPtr->trustedUsage & \
( CRYPT_KEYUSAGE_CRLSIGN | CRYPT_KEYUSAGE_KEYCERTSIGN ) ) )
{
setErrorValues( CRYPT_CERTINFO_KEYUSAGE,
CRYPT_ERRTYPE_CONSTRAINT );
return( CRYPT_ERROR_INVALID );
}
}
/* Check and enforce the keyUsage if required */
if( keyUsage != CRYPT_UNUSED )
{
attributeListPtr = findAttributeField( certInfoPtr->attributes,
CRYPT_CERTINFO_KEYUSAGE,
CRYPT_ATTRIBUTE_NONE );
if( attributeListPtr != NULL )
{
const int trustedUsage = \
attributeListPtr->intValue & 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( complianceLevel >= CRYPT_COMPLIANCELEVEL_PKIX_PARTIAL && \
( 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 )
{
setErrorValues( ( attributeListPtr->intValue & keyUsage ) ? \
CRYPT_CERTINFO_TRUSTED_USAGE : \
CRYPT_CERTINFO_KEYUSAGE,
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( !( certInfoPtr->trustedUsage & keyUsage ) )
{
setErrorValues( CRYPT_CERTINFO_TRUSTED_USAGE,
CRYPT_ERRTYPE_CONSTRAINT );
return( CRYPT_ERROR_INVALID );
}
}
}
/* If we're not doing at least partial PKIX checking, we're done */
if( complianceLevel < CRYPT_COMPLIANCELEVEL_PKIX_PARTIAL )
return( CRYPT_OK );
/* If we're being asked for a private-key op, check and enforce the
privateKeyUsage attribute if there's one present */
if( ( exactUsage == MESSAGE_CHECK_PKC_PRIVATE || \
exactUsage == MESSAGE_CHECK_PKC_DECRYPT || \
exactUsage == MESSAGE_CHECK_PKC_SIGN ) && \
findAttributeField( certInfoPtr->attributes,
CRYPT_CERTINFO_PRIVATEKEYUSAGEPERIOD,
CRYPT_ATTRIBUTE_NONE ) != NULL )
{
const time_t currentTime = getTime();
if( currentTime < MIN_TIME_VALUE )
{
/* Time is broken, we can't reliably check for expiry times */
setErrorValues( CRYPT_CERTINFO_PRIVATEKEY_NOTBEFORE,
CRYPT_ERRTYPE_CONSTRAINT );
return( CRYPT_ERROR_INVALID );
}
attributeListPtr = findAttributeField( certInfoPtr->attributes,
CRYPT_CERTINFO_PRIVATEKEY_NOTBEFORE,
CRYPT_ATTRIBUTE_NONE );
if( attributeListPtr != NULL && \
currentTime < *( ( time_t * ) attributeListPtr->value ) )
{
setErrorValues( CRYPT_CERTINFO_PRIVATEKEY_NOTBEFORE,
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->value ) )
{
setErrorValues( CRYPT_CERTINFO_PRIVATEKEY_NOTAFTER,
CRYPT_ERRTYPE_CONSTRAINT );
return( CRYPT_ERROR_INVALID );
}
}
return( CRYPT_OK );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -