📄 chk_cert.c
字号:
/* Check name constraints placed by an issuer, checked if complianceLevel >=
CRYPT_COMPLIANCELEVEL_PKIX_FULL */
int checkNameConstraints( const CERT_INFO *subjectCertInfoPtr,
const ATTRIBUTE_LIST *issuerAttributes,
const BOOLEAN isExcluded,
CRYPT_ATTRIBUTE_TYPE *errorLocus,
CRYPT_ERRTYPE_TYPE *errorType )
{
const ATTRIBUTE_LIST *subjectAttributes = subjectCertInfoPtr->attributes;
const CRYPT_ATTRIBUTE_TYPE constraintType = isExcluded ? \
CRYPT_CERTINFO_EXCLUDEDSUBTREES : CRYPT_CERTINFO_PERMITTEDSUBTREES;
ATTRIBUTE_LIST *attributeListPtr;
BOOLEAN isMatch = FALSE;
assert( isReadPtr( subjectCertInfoPtr, sizeof( CERT_INFO ) ) );
assert( isReadPtr( issuerAttributes, sizeof( ATTRIBUTE_LIST ) ) );
assert( isWritePtr( errorLocus, sizeof( CRYPT_ATTRIBUTE_TYPE ) ) );
assert( isWritePtr( errorType, sizeof( CRYPT_ERRTYPE_TYPE ) ) );
/* If this is a PKIX path-kludge CA cert, the name constraints don't
apply to it (PKIX section 4.2.1.11). This is required in order to
allow extra certs to be kludged into the path without violating the
constraint. For example with the chain:
Issuer Subject Constraint
------ ------- ----------
Root CA permitted = "EE"
CA' CA'
CA EE
the kludge cert CA' must be excluded from name constraint
restrictions in order for the path to be valid. Obviously this is
only necessary for constraints set by the immediate parent, but PKIX
says it's for constraints set by all certs in the chain (!!), thus
making the pathkludge cert exempt from any name constraints, not just
the one that would cause problems */
if( isPathKludge( subjectCertInfoPtr ) )
return( CRYPT_OK );
/* Check the subject DN if constraints exist. If it's an excluded
subtree then none can match, if it's a permitted subtree then at
least one must match */
attributeListPtr = findAttributeField( issuerAttributes, constraintType,
CRYPT_CERTINFO_DIRECTORYNAME );
if( attributeListPtr != NULL )
{
while( attributeListPtr != NULL && !isMatch )
{
isMatch = compareDN( subjectCertInfoPtr->subjectName,
attributeListPtr->value, TRUE );
attributeListPtr = findNextFieldInstance( attributeListPtr );
}
if( isExcluded == isMatch )
{
setErrorValues( CRYPT_CERTINFO_SUBJECTNAME,
CRYPT_ERRTYPE_CONSTRAINT );
return( CRYPT_ERROR_INVALID );
}
}
/* DN constraints apply to both the main subject DN and any other DNs
that may be present as subject altNames, so after we've checked the
main DN we check any altName DNs as well */
if( !checkAltnameConstraints( subjectAttributes, issuerAttributes,
CRYPT_CERTINFO_DIRECTORYNAME, isExcluded ) )
{
setErrorValues( CRYPT_CERTINFO_SUBJECTALTNAME,
CRYPT_ERRTYPE_CONSTRAINT );
return( CRYPT_ERROR_INVALID );
}
/* Compare the Internet-related names if constraints exist. We don't
have to check for the special case of an email address in the DN
since the cert import code transparently maps this to the
appropriate altName component */
if( !checkAltnameConstraints( subjectAttributes, issuerAttributes,
CRYPT_CERTINFO_RFC822NAME, isExcluded ) || \
!checkAltnameConstraints( subjectAttributes, issuerAttributes,
CRYPT_CERTINFO_DNSNAME, isExcluded ) || \
!checkAltnameConstraints( subjectAttributes, issuerAttributes,
CRYPT_CERTINFO_UNIFORMRESOURCEIDENTIFIER,
isExcluded ) )
{
setErrorValues( CRYPT_CERTINFO_SUBJECTALTNAME,
CRYPT_ERRTYPE_CONSTRAINT );
return( CRYPT_ERROR_INVALID );
}
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,
const POLICY_TYPE policyType,
CRYPT_ATTRIBUTE_TYPE *errorLocus,
CRYPT_ERRTYPE_TYPE *errorType )
{
const ATTRIBUTE_LIST *attributeListPtr = \
findAttributeField( issuerAttributes,
CRYPT_CERTINFO_CERTPOLICYID,
CRYPT_ATTRIBUTE_NONE );
const ATTRIBUTE_LIST *constrainedAttributeListPtr = \
findAttributeField( subjectCertInfoPtr->attributes,
CRYPT_CERTINFO_CERTPOLICYID,
CRYPT_ATTRIBUTE_NONE );
ATTRIBUTE_LIST *attributeCursor;
BOOLEAN subjectHasPolicy, issuerHasPolicy;
BOOLEAN subjectHasAnyPolicy, issuerHasAnyPolicy;
assert( isReadPtr( subjectCertInfoPtr, sizeof( CERT_INFO ) ) );
assert( isReadPtr( issuerAttributes, sizeof( ATTRIBUTE_LIST ) ) );
assert( policyType >= POLICY_NONE && policyType < POLICY_LAST );
assert( isWritePtr( errorLocus, sizeof( CRYPT_ATTRIBUTE_TYPE ) ) );
assert( isWritePtr( errorType, sizeof( CRYPT_ERRTYPE_TYPE ) ) );
/* If there's a policy mapping present, neither the issuer nor subject
domain policies can be the wildcard anyPolicy (PKIX section
4.2.1.6) */
if( containsAnyPolicy( issuerAttributes,
CRYPT_CERTINFO_ISSUERDOMAINPOLICY ) || \
containsAnyPolicy( issuerAttributes,
CRYPT_CERTINFO_SUBJECTDOMAINPOLICY ) )
{
setErrorValues( CRYPT_CERTINFO_POLICYMAPPINGS,
CRYPT_ERRTYPE_ISSUERCONSTRAINT );
return( CRYPT_ERROR_INVALID );
}
/* If there's no requirement for a policy and none set, we're done */
if( policyType == POLICY_NONE && constrainedAttributeListPtr == NULL )
return( CRYPT_OK );
/* Check the subject policy */
if( !checkPolicyType( constrainedAttributeListPtr, &subjectHasPolicy,
&subjectHasAnyPolicy,
( policyType == POLICY_NONE_SPECIFIC || \
policyType == POLICY_SUBJECT_SPECIFIC || \
policyType == POLICY_BOTH_SPECIFIC ) ? \
TRUE : FALSE ) )
{
setErrorValues( CRYPT_CERTINFO_CERTPOLICYID,
CRYPT_ERRTYPE_CONSTRAINT );
return( CRYPT_ERROR_INVALID );
}
/* If there's no requirement for an issuer policy and none set by the
issuer, we're done */
if( ( ( policyType == POLICY_SUBJECT ) || \
( policyType == POLICY_SUBJECT_SPECIFIC ) ) && \
attributeListPtr == NULL )
return( CRYPT_OK );
/* Check the subject policy */
if( !checkPolicyType( attributeListPtr , &issuerHasPolicy,
&issuerHasAnyPolicy,
( policyType == POLICY_BOTH_SPECIFIC ) ? \
TRUE : FALSE ) )
{
setErrorValues( CRYPT_CERTINFO_CERTPOLICYID,
CRYPT_ERRTYPE_CONSTRAINT );
return( CRYPT_ERROR_INVALID );
}
/* Both the issuer and subject have some sort of policy, if either are
anyPolicy wildcards (introduced in RFC 3280 section 4.2.1.5) then
it's considered a match */
if( subjectHasAnyPolicy || issuerHasAnyPolicy )
return( CRYPT_OK );
/* An explicit policy is required, make sure that at least one of the
issuer policies matches at least one of the subject policies. Note
that there's no exception for PKIX path-kludge certs, this is an
error in the RFC, for which the text at this point is unchanged from
RFC 2459. In fact this contradicts the path-processing pesudocode,
but since that in turn contradicts the main text in a number of
places we take the main text as definitive, not the buggy
pseudocode */
for( attributeCursor = ( ATTRIBUTE_LIST * ) attributeListPtr; \
attributeCursor != NULL; \
attributeCursor = findNextFieldInstance( attributeCursor ) )
{
ATTRIBUTE_LIST *constrainedAttributeCursor;
assert( attributeCursor->fieldID == CRYPT_CERTINFO_CERTPOLICYID );
for( constrainedAttributeCursor = \
( ATTRIBUTE_LIST * ) constrainedAttributeListPtr; \
constrainedAttributeCursor != NULL; \
constrainedAttributeCursor = \
findNextFieldInstance( constrainedAttributeCursor ) )
{
assert( constrainedAttributeCursor->fieldID == \
CRYPT_CERTINFO_CERTPOLICYID );
if( attributeCursor->valueLength == \
constrainedAttributeCursor->valueLength && \
!memcmp( attributeCursor->value,
constrainedAttributeCursor->value,
attributeCursor->valueLength ) )
return( CRYPT_OK );
}
}
/* We couldn't find a matching policy, report an error */
setErrorValues( CRYPT_CERTINFO_CERTPOLICYID, CRYPT_ERRTYPE_CONSTRAINT );
return( CRYPT_ERROR_INVALID );
}
/* Check path constraints placed by an issuer, checked if complianceLevel
>= CRYPT_COMPLIANCELEVEL_PKIX_PARTIAL */
int checkPathConstraints( const CERT_INFO *subjectCertInfoPtr,
const ATTRIBUTE_LIST *issuerAttributes,
const int complianceLevel,
CRYPT_ATTRIBUTE_TYPE *errorLocus,
CRYPT_ERRTYPE_TYPE *errorType )
{
ATTRIBUTE_LIST *attributeListPtr;
assert( isReadPtr( subjectCertInfoPtr, sizeof( CERT_INFO ) ) );
assert( isReadPtr( issuerAttributes, sizeof( ATTRIBUTE_LIST ) ) );
assert( isWritePtr( errorLocus, sizeof( CRYPT_ATTRIBUTE_TYPE ) ) );
assert( isWritePtr( errorType, sizeof( CRYPT_ERRTYPE_TYPE ) ) );
/* If this is a PKIX path-kludge cert, the path length constraints don't
apply to it (PKIX section 4.2.1.10). This is required in order to
allow extra certs to be kludged into the path without violating the
name constraint */
if( isPathKludge( subjectCertInfoPtr ) )
return( CRYPT_OK );
/* If the path length constraint hasn't been triggered yet, we're OK */
if( issuerAttributes->intValue > 0 )
return( CRYPT_OK );
/* The path length constraint is in effect, the next cert down the chain
must be an end-entity cert */
attributeListPtr = findAttributeField( subjectCertInfoPtr->attributes,
CRYPT_CERTINFO_CA,
CRYPT_ATTRIBUTE_NONE );
if( attributeListPtr != NULL && attributeListPtr->intValue )
{
setErrorValues( CRYPT_CERTINFO_PATHLENCONSTRAINT,
CRYPT_ERRTYPE_ISSUERCONSTRAINT );
return( CRYPT_ERROR_INVALID );
}
return( CRYPT_OK );
}
/****************************************************************************
* *
* Check a Certificate Object *
* *
****************************************************************************/
/* 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 );
/* Make sure that the issuer can sign CRLs and the issuer cert in
general is in order */
return( checkKeyUsage( issuerCertInfoPtr,
CHECKKEY_FLAG_CA | CHECKKEY_FLAG_GENCHECK,
CRYPT_KEYUSAGE_CRLSIGN, complianceLevel,
errorLocus, errorType ) );
}
/* Check the validity of a subject cert based on an issuer cert, with the
level of checking performed depending on the complianceLevel setting. If
the shortCircuitCheck flag is set (used for cert issuer : subject pairs
that may already have been checked) we skip the constant-result checks if
the combination has already been checked at this compliance level */
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;
const ATTRIBUTE_LIST *attributeListPtr;
const BOOLEAN subjectSelfSigned = \
( subjectCertInfoPtr->flags & CERT_FLAG_SELFSIGNED ) ? \
TRUE : FALSE;
BOOLEAN subjectIsCA = FALSE, issuerIsCA = FALSE;
const time_t currentTime = getTime();
int complianceLevel, status;
assert( isReadPtr( subjectCertInfoPtr, sizeof( CERT_INFO ) ) );
assert( isWritePtr( errorLocus, sizeof( CRYPT_ATTRIBUTE_TYPE ) ) );
assert( isWritePtr( errorType, sizeof( CRYPT_ERRTYPE_TYPE ) ) );
/* Determine how much checking we need to perform. If this is a
currently-under-construction cert we use the maximum compliance level
to ensure that cryptlib never produces broken certs */
if( subjectCertInfoPtr->certificate == NULL )
complianceLevel = CRYPT_COMPLIANCELEVEL_PKIX_FULL;
else
{
status = krnlSendMessage( subjectCertInfoPtr->ownerHandle,
IMESSAGE_GETATTRIBUTE, &complianceLevel,
CRYPT_OPTION_CERT_COMPLIANCELEVEL );
if( cryptStatusError( status ) )
return( status );
}
/* If it's some form of certificate request or an OCSP object (which
means that it isn't signed by an issuer in the normal sense), there's
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -