📄 chk_cert.c
字号:
nothing to check (yet) */
switch( subjectCertInfoPtr->type )
{
case CRYPT_CERTTYPE_CERTIFICATE:
case CRYPT_CERTTYPE_ATTRIBUTE_CERT:
case CRYPT_CERTTYPE_CERTCHAIN:
/* It's an issuer-signed object, there must be an issuer cert
present */
assert( isReadPtr( issuerCertInfoPtr, sizeof( CERT_INFO ) ) );
if( subjectCertInfoPtr->flags & CERT_FLAG_CERTCOLLECTION )
{
/* Cert collections are pure container objects for which the
base cert object doesn't correspond to an actual cert */
assert( NOTREACHED );
return( CRYPT_ERROR_INVALID );
}
break;
case CRYPT_CERTTYPE_CERTREQUEST:
case CRYPT_CERTTYPE_REQUEST_CERT:
case CRYPT_CERTTYPE_REQUEST_REVOCATION:
/* These are merely templates submitted to a CA, there's nothing
to check. For example the template could contain constraints
that only make sense once the issuer cert is incorporated
into a chain, or a future-dated validity time, or a CA
keyUsage for which the CA provides the appropriate matching
basicConstraints value(s), so we can't really perform much
checking here */
return( CRYPT_OK );
case CRYPT_CERTTYPE_CRL:
/* There must be an issuer cert present unless we're checking a
standalone CRL entry that acts purely as a container for
revocation data */
assert( issuerCertInfoPtr == NULL || \
isReadPtr( issuerCertInfoPtr, sizeof( CERT_INFO ) ) );
/* CRL checking is handled specially */
return( checkCRL( subjectCertInfoPtr, issuerCertInfoPtr,
complianceLevel, errorLocus, errorType ) );
case CRYPT_CERTTYPE_CMS_ATTRIBUTES:
case CRYPT_CERTTYPE_PKIUSER:
assert( NOTREACHED );
return( CRYPT_ERROR_INVALID );
case CRYPT_CERTTYPE_RTCS_REQUEST:
case CRYPT_CERTTYPE_RTCS_RESPONSE:
case CRYPT_CERTTYPE_OCSP_REQUEST:
case CRYPT_CERTTYPE_OCSP_RESPONSE:
/* These aren't normal cert types, there's nothing to check - we
can't even check the issuer since they're not normally issued
by CAs */
return( CRYPT_OK );
default:
assert( NOTREACHED );
return( CRYPT_ERROR_INVALID );
}
/* There is one universal case in which a cert is regarded as invalid
and that's when it's explicitly not trusted for the purpose. We
perform the check at this point in oblivious mode to ensure that only
the basic trusted usage gets checked */
if( issuerCertInfoPtr->cCertCert->trustedUsage != CRYPT_ERROR )
{
status = checkKeyUsage( issuerCertInfoPtr, CHECKKEY_FLAG_CA,
CRYPT_KEYUSAGE_KEYCERTSIGN,
CRYPT_COMPLIANCELEVEL_OBLIVIOUS,
errorLocus, errorType );
if( cryptStatusError( status ) )
{
/* There was a problem with the issuer cert, convert the problem
to an issuer constraint */
*errorType = CRYPT_ERRTYPE_ISSUERCONSTRAINT;
return( status );
}
}
/* If we're 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 if we're doing a short-circuit check of
a cert in a chain that's already been checked, and we've already
checked it at the appropriate level, there's no need to perform any
further checks */
if( ( subjectSelfSigned || shortCircuitCheck ) && \
( subjectCertInfoPtr->cCertCert->maxCheckLevel >= complianceLevel ) )
return( CRYPT_OK );
/* If the cert isn't self-signed, check name chaining */
if( !subjectSelfSigned )
{
/* Check that the subject issuer name and issuer subject name 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 we're doing a reduced level of checking, we're done */
if( complianceLevel < CRYPT_COMPLIANCELEVEL_STANDARD )
{
if( subjectCertInfoPtr->cCertCert->maxCheckLevel < complianceLevel )
subjectCertInfoPtr->cCertCert->maxCheckLevel = complianceLevel;
return( CRYPT_OK );
}
/* Check that the cert usage flags are present and consistent. The key
usage checking level ranges up to CRYPT_COMPLIANCELEVEL_PKIX_PARTIAL
so we re-do the check even if it's already been done at a lower
level */
if( subjectCertInfoPtr->cCertCert->maxCheckLevel < CRYPT_COMPLIANCELEVEL_PKIX_PARTIAL && \
subjectCertInfoPtr->type != CRYPT_CERTTYPE_ATTRIBUTE_CERT )
{
status = checkKeyUsage( subjectCertInfoPtr, CHECKKEY_FLAG_GENCHECK,
CRYPT_UNUSED, complianceLevel,
errorLocus, errorType );
if( cryptStatusError( status ) )
return( status );
}
/* If the cert isn't self-signed, check that issuer is a CA */
if( !subjectSelfSigned )
{
status = checkKeyUsage( issuerCertInfoPtr, CHECKKEY_FLAG_CA,
CRYPT_KEYUSAGE_KEYCERTSIGN, complianceLevel,
errorLocus, errorType );
if( cryptStatusError( status ) )
{
/* There was a problem with the issuer cert, convert the problem
to an issuer constraint */
*errorType = CRYPT_ERRTYPE_ISSUERCONSTRAINT;
return( status );
}
}
/* Check all the blob (unrecognised) attributes to see if any are marked
critical. We only do this if it's an existing cert that we've
imported rather than one that we've just created, since applying this
check to the latter would make it impossible to create certs with
unrecognised critical extensions */
if( subjectCertInfoPtr->certificate != NULL )
{
for( attributeListPtr = subjectAttributes; \
attributeListPtr != NULL && !isBlobAttribute( attributeListPtr ); \
attributeListPtr = attributeListPtr->next );
while( attributeListPtr != NULL )
{
/* If we've found an unrecognised critical extension, reject the
cert (PKIX section 4.2). The one exception to this is if the
attribute was recognised but has been ignored at this
compliance level, in which case it's treated as a blob
attribute */
if( ( attributeListPtr->flags & ATTR_FLAG_CRITICAL ) && \
!( attributeListPtr->flags & ATTR_FLAG_IGNORED ) )
{
setErrorValues( CRYPT_ATTRIBUTE_NONE,
CRYPT_ERRTYPE_CONSTRAINT );
return( CRYPT_ERROR_INVALID );
}
attributeListPtr = attributeListPtr->next;
}
}
/* If we're not doing at least partial PKIX checking, we're done */
if( complianceLevel < CRYPT_COMPLIANCELEVEL_PKIX_PARTIAL )
{
if( subjectCertInfoPtr->cCertCert->maxCheckLevel < complianceLevel )
subjectCertInfoPtr->cCertCert->maxCheckLevel = complianceLevel;
return( CRYPT_OK );
}
/* Constraints can only be present in CA certs. The issuer may not be
a proper CA if it's a self-signed end entity cert or an X.509v1 CA
cert, which is why we also check for !issuerIsCA */
if( !subjectIsCA && invalidAttributesPresent( subjectAttributes, FALSE,
errorLocus, errorType ) )
return( CRYPT_ERROR_INVALID );
if( !issuerIsCA && invalidAttributesPresent( subjectAttributes, TRUE,
errorLocus, errorType ) )
return( CRYPT_ERROR_INVALID );
/* From this point onwards if we're doing a short-circuit check of
certs in a chain we don't apply constraint checks. This is because
the cert-chain code has already performed far more complete checks
of the various constraints set by all the certs in the chain rather
than just the current cert issuer : subject pair */
/* If there's a path length constraint present, apply it */
attributeListPtr = findAttributeField( issuerAttributes,
CRYPT_CERTINFO_PATHLENCONSTRAINT,
CRYPT_ATTRIBUTE_NONE );
if( attributeListPtr != NULL && !shortCircuitCheck )
{
status = checkPathConstraints( subjectCertInfoPtr, attributeListPtr,
complianceLevel, errorLocus,
errorType );
if( cryptStatusError( status ) )
return( status );
}
/* In order to dig itself out of a hole caused by a circular definition,
RFC 3280 added a new extKeyUsage anyExtendedKeyUsage (rather than the
more obvious fix of removing the problematic definition).
Unfortunately this causes more problems than it solves because the exact
semantics of this new usage aren't precisely defined. To fix this
problem we invent some plausible ones ourselves: If the only eKU is
anyKU, we treat the overall extKeyUsage as empty, i.e. there are no
particular restrictions on usage. If any other usage is present the
extension has become self-contradictory, so we treat the anyKU as
being absent. See the comment for getExtendedKeyUsageFlags() for how
this is handled */
attributeListPtr = findAttributeField( subjectAttributes,
CRYPT_CERTINFO_EXTKEY_ANYKEYUSAGE,
CRYPT_ATTRIBUTE_NONE );
if( attributeListPtr != NULL && \
( attributeListPtr->flags & ATTR_FLAG_CRITICAL ) )
{
/* If anyKU is present the extension must be non-critical
(PKIX section 4.2.1.13) */
setErrorValues( CRYPT_CERTINFO_EXTKEY_ANYKEYUSAGE,
CRYPT_ERRTYPE_CONSTRAINT );
return( CRYPT_ERROR_INVALID );
}
/* If we're not doing full PKIX checking, we're done. In addition since
all of the remaining checks are constraint checks we can exit at this
point if we're doing a short-circuit check */
if( complianceLevel < CRYPT_COMPLIANCELEVEL_PKIX_FULL || \
shortCircuitCheck )
{
if( subjectCertInfoPtr->cCertCert->maxCheckLevel < complianceLevel )
subjectCertInfoPtr->cCertCert->maxCheckLevel = complianceLevel;
return( CRYPT_OK );
}
/* 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( !subjectSelfSigned )
{
attributeListPtr = findAttributeField( issuerAttributes,
CRYPT_CERTINFO_EXCLUDEDSUBTREES,
CRYPT_ATTRIBUTE_NONE );
if( attributeListPtr != NULL && \
cryptStatusError( \
checkNameConstraints( subjectCertInfoPtr, attributeListPtr,
TRUE, errorLocus, errorType ) ) )
return( CRYPT_ERROR_INVALID );
attributeListPtr = findAttributeField( issuerAttributes,
CRYPT_CERTINFO_PERMITTEDSUBTREES,
CRYPT_ATTRIBUTE_NONE );
if( attributeListPtr != NULL && \
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 )
{
POLICY_TYPE policyType = POLICY_SUBJECT;
/* Check whether use of the the wildcard anyPolicy has been
disallowed */
attributeListPtr = findAttribute( issuerCertInfoPtr->attributes, \
CRYPT_CERTINFO_INHIBITANYPOLICY,
TRUE );
if( attributeListPtr != NULL && attributeListPtr->intValue <= 0 )
policyType = POLICY_SUBJECT_SPECIFIC;
/* Apply the appropriate policy constraint */
status = checkPolicyConstraints( subjectCertInfoPtr,
issuerAttributes, policyType,
errorLocus, errorType );
if( cryptStatusError( status ) )
return( status );
}
if( subjectCertInfoPtr->cCertCert->maxCheckLevel < complianceLevel )
subjectCertInfoPtr->cCertCert->maxCheckLevel = complianceLevel;
return( CRYPT_OK );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -