📄 certschk.c
字号:
CRYPT_CERTTYPE_RTCS_REQUEST : \
CRYPT_CERTTYPE_OCSP_REQUEST );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_DEV_CREATEOBJECT,
&createInfo, OBJECT_TYPE_CERTIFICATE );
if( cryptStatusError( status ) )
return( status );
status = krnlSendMessage( createInfo.cryptHandle, IMESSAGE_SETATTRIBUTE,
&certInfoPtr->objectHandle, CRYPT_CERTINFO_CERTIFICATE );
if( cryptStatusOK( status ) )
status = krnlSendMessage( iCryptSession, IMESSAGE_SETATTRIBUTE,
&createInfo.cryptHandle, CRYPT_SESSINFO_REQUEST );
krnlSendNotifier( createInfo.cryptHandle, IMESSAGE_DECREFCOUNT );
if( cryptStatusError( status ) )
return( status );
/* Activate the session and get the response info */
status = krnlSendMessage( iCryptSession, IMESSAGE_SETATTRIBUTE,
MESSAGE_VALUE_TRUE, CRYPT_SESSINFO_ACTIVE );
if( cryptStatusOK( status ) )
status = krnlSendMessage( iCryptSession, IMESSAGE_GETATTRIBUTE,
&cryptResponse, CRYPT_SESSINFO_RESPONSE );
if( cryptStatusError( status ) )
return( status );
if( type == SUBTYPE_SESSION_RTCS )
{
int certStatus;
status = krnlSendMessage( cryptResponse, IMESSAGE_GETATTRIBUTE,
&certStatus, CRYPT_CERTINFO_CERTSTATUS );
if( cryptStatusOK( status ) && \
( certStatus != CRYPT_CERTSTATUS_VALID ) )
status = CRYPT_ERROR_INVALID;
}
else
{
int revocationStatus;
status = krnlSendMessage( cryptResponse, IMESSAGE_GETATTRIBUTE,
&revocationStatus,
CRYPT_CERTINFO_REVOCATIONSTATUS );
if( cryptStatusOK( status ) && \
( revocationStatus != CRYPT_OCSPSTATUS_NOTREVOKED ) )
status = CRYPT_ERROR_INVALID;
}
krnlSendNotifier( cryptResponse, IMESSAGE_DECREFCOUNT );
return( status );
}
/* Check a certificate against a CRL */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
static int checkCRL( INOUT CERT_INFO *certInfoPtr,
IN_HANDLE const CRYPT_CERTIFICATE iCryptCRL )
{
CERT_INFO *crlInfoPtr;
int i, status;
assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
REQUIRES( isHandleRangeValid( iCryptCRL ) );
/* Check that the CRL is a complete signed CRL and not a newly-created
CRL object */
status = krnlAcquireObject( iCryptCRL, OBJECT_TYPE_CERTIFICATE,
( void ** ) &crlInfoPtr,
CRYPT_ARGERROR_VALUE );
if( cryptStatusError( status ) )
return( status );
if( crlInfoPtr->certificate == NULL )
{
krnlReleaseObject( crlInfoPtr->objectHandle );
return( CRYPT_ERROR_NOTINITED );
}
/* Check the base certificate against the CRL. If it's been revoked or
there's only a single certificate present, exit */
status = checkRevocation( certInfoPtr, crlInfoPtr );
if( cryptStatusError( status ) || \
certInfoPtr->type != CRYPT_CERTTYPE_CERTCHAIN )
{
krnlReleaseObject( crlInfoPtr->objectHandle );
return( status );
}
/* It's a certificate chain, check every remaining certificate in the
chain against the CRL. In theory this is pointless because a CRL can
only contain information for a single certificate in the chain,
however the caller may have passed us a CRL for an intermediate
certificate (in which case the check for the leaf certificate was
pointless). In any case it's easier to just do the check for all
certificates than to determine which certificate the CRL applies to
so we check for all certificates */
for( i = 0; i < certInfoPtr->cCertCert->chainEnd && \
i < MAX_CHAINLENGTH; i++ )
{
CERT_INFO *certChainInfoPtr;
/* Check this certificate against the CRL */
status = krnlAcquireObject( certInfoPtr->cCertCert->chain[ i ],
OBJECT_TYPE_CERTIFICATE,
( void ** ) &certChainInfoPtr,
CRYPT_ERROR_SIGNALLED );
if( cryptStatusOK( status ) )
{
status = checkRevocation( certChainInfoPtr, crlInfoPtr );
krnlReleaseObject( certChainInfoPtr->objectHandle );
}
/* If the certificate has been revoked remember which one is the
revoked certificate and exit */
if( cryptStatusError( status ) )
{
certInfoPtr->cCertCert->chainPos = i;
break;
}
}
ENSURES( i < MAX_CHAINLENGTH );
krnlReleaseObject( crlInfoPtr->objectHandle );
return( status );
}
/****************************************************************************
* *
* Signature Checking Functions *
* *
****************************************************************************/
/* Check a certificate against an issuer certificate. The trustAnchorCheck
flag is used when we're checking an explicit trust anchor, for which we
only need to check the signature if it's self-signed. The
shortCircuitCheck flag is used when checking subject:issuer pairs inside
certificate chains, which have already been checked by the chain-handling
code so a full (re-)check isn't necessary any more */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 7, 8 ) ) \
int checkCertDetails( INOUT CERT_INFO *subjectCertInfoPtr,
INOUT_OPT CERT_INFO *issuerCertInfoPtr,
IN_HANDLE_OPT const CRYPT_CONTEXT iIssuerPubKey,
IN_OPT const X509SIG_FORMATINFO *formatInfo,
const BOOLEAN trustAnchorCheck,
const BOOLEAN shortCircuitCheck,
OUT_ENUM_OPT( CRYPT_ATTRIBUTE ) \
CRYPT_ATTRIBUTE_TYPE *errorLocus,
OUT_ENUM_OPT( CRYPT_ERRTYPE ) \
CRYPT_ERRTYPE_TYPE *errorType )
{
int status;
assert( isWritePtr( subjectCertInfoPtr, sizeof( CERT_INFO ) ) );
assert( issuerCertInfoPtr == NULL || \
isWritePtr( issuerCertInfoPtr, sizeof( CERT_INFO ) ) );
assert( formatInfo == NULL || \
isReadPtr( formatInfo, sizeof( X509SIG_FORMATINFO ) ) );
assert( isWritePtr( errorLocus, sizeof( CRYPT_ATTRIBUTE_TYPE ) ) );
assert( isWritePtr( errorType, sizeof( CRYPT_ERRTYPE_TYPE ) ) );
REQUIRES( iIssuerPubKey == CRYPT_UNUSED || \
isHandleRangeValid( iIssuerPubKey ) );
/* If there's an issuer certificate present check the validity of the
subject certificate based on it. If it's not present all that we can
do is perform a pure signature check with the context */
if( issuerCertInfoPtr != NULL )
{
status = checkCert( subjectCertInfoPtr, issuerCertInfoPtr,
shortCircuitCheck, errorLocus, errorType );
if( cryptStatusError( status ) )
return( status );
}
/* If the signature has already been checked or there's no signature-
check key present we're done. The latter can occur when we're
checking a data-only certificate in a cert chain chain. This is safe
because these certificates can only occur when we're reading them
from an (implicitly trusted) private key store */
if( ( subjectCertInfoPtr->flags & CERT_FLAG_SIGCHECKED ) || \
iIssuerPubKey == CRYPT_UNUSED )
return( CRYPT_OK );
/* If we're checking an explicit trust anchor and the certificate isn't
self-signed there's nothing further left to check */
if( trustAnchorCheck && issuerCertInfoPtr != NULL && \
!( issuerCertInfoPtr->flags & CERT_FLAG_SELFSIGNED ) )
return( CRYPT_OK );
/* If we're performing a standard check and it's an explicitly-trusted
certificate we're done. If we're performing a check of a certificate
chain then the chain-handling code will have performed its own
handling of trusted certificates/trust anchors so we don't peform a
second check here */
if( !shortCircuitCheck )
{
if( cryptStatusOK( \
krnlSendMessage( subjectCertInfoPtr->ownerHandle,
IMESSAGE_USER_TRUSTMGMT,
&subjectCertInfoPtr->objectHandle,
MESSAGE_TRUSTMGMT_CHECK ) ) )
return( CRYPT_OK );
}
/* Check the signature on the certificate. If there's a problem with
the issuer's public key it'll be reported as a CRYPT_ARGERROR_NUM1,
which the caller has to convert into an appropriate error code */
status = checkX509signature( subjectCertInfoPtr->certificate,
subjectCertInfoPtr->certificateSize,
iIssuerPubKey, formatInfo );
if( cryptStatusError( status ) )
{
MESSAGE_DATA msgData;
BYTE subjectIssuerID[ CRYPT_MAX_HASHSIZE + 8 ];
BYTE issuerSubjectID[ CRYPT_MAX_HASHSIZE + 8 ];
int subjectIDlength, issuerIDlength;
/* There's on special-case situation in which we can get a
signature-check failure that looks like data corruption and
that's when a CA quietly changes its issuing key without changing
anything else so the certificates chain but the signature check
produces garbage as output due to the use of the incorrect key.
Although it could be argued that a CA that does this is broken,
we try and accomodate it by performing a backup check using
keyIDs if the signature check produces garbled output. Because
of the complete chaos present in keyIDs we can't do this by
default (it would result in far too many false positives) but
it's safe as a fallback at this point since we're about to report
an error anyway and the worst that can happen is that we return
a slightly inappropriate error message.
If there's no issuer certificate provided we also have to exit at
this point because we can't go any further without it */
if( status != CRYPT_ERROR_BADDATA || issuerCertInfoPtr == NULL )
return( status );
/* Get the subject certificate's issuerID and the issuer cert's
subjectID. We don't bother with the alternative awkward
DN-based ID since what we're really interested in is the ID of
the signing key and it's not worth the extra pain of dealing with
these awkward cert IDs just to try and fix up a slight difference
in error codes */
setMessageData( &msgData, subjectIssuerID, CRYPT_MAX_HASHSIZE );
status = krnlSendMessage( subjectCertInfoPtr->objectHandle,
IMESSAGE_GETATTRIBUTE_S, &msgData,
CRYPT_CERTINFO_AUTHORITY_KEYIDENTIFIER );
if( cryptStatusError( status ) )
return( CRYPT_ERROR_BADDATA );
issuerIDlength = msgData.length;
setMessageData( &msgData, issuerSubjectID, CRYPT_MAX_HASHSIZE );
status = krnlSendMessage( issuerCertInfoPtr->objectHandle,
IMESSAGE_GETATTRIBUTE_S, &msgData,
CRYPT_CERTINFO_SUBJECTKEYIDENTIFIER );
if( cryptStatusError( status ) )
return( CRYPT_ERROR_BADDATA );
subjectIDlength = msgData.length;
/* If the keyIDs don't match then it's a signature error due to
false-positive chaining rather than a data corruption error */
return( ( ( issuerIDlength != subjectIDlength ) || \
memcmp( subjectIssuerID, issuerSubjectID, \
issuerIDlength ) ) ? \
CRYPT_ERROR_SIGNATURE : CRYPT_ERROR_BADDATA );
}
/* The signature is OK, we don't need to check it again. There is a
theoretical situation in which this can lead to a false positive
which requires first checking the certificate using the correct
issuing CA (which will set the CERT_FLAG_SIGCHECKED flag) and then
checking it again using a second CA cert identical to the first but
with a different key. In other words the issuer DN chains correctly
but the issuer key is different. The appropriate behaviour here is
somewhat unclear. It could be argued that a CA that uses two
otherwise identical certificates but with different keys is broken
and therefore behaviour in this situation is undefined. However we
need to do something with the resulting check and returning the
result of the check with the correct CA certificate even if we're
later passed a second incorrect certificate from the CA seems to be
the most appropriate action since it has in the past been validated
by a certificate from the same CA. If we want to force the check to
be done with a specific CA key (rather than just the issuing CA's
certificate in general) we could store the fingerprint of the
signing key alongside the CERT_FLAG_SIGCHECKED flag */
subjectCertInfoPtr->flags |= CERT_FLAG_SIGCHECKED;
return( CRYPT_OK );
}
/* Check a self-signed certificate object like a cert request or a
self-signed certificate */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
static int checkSelfSignedCert( INOUT CERT_INFO *certInfoPtr,
IN_OPT const X509SIG_FORMATINFO *formatInfo )
{
CRYPT_CONTEXT iCryptContext = CRYPT_UNUSED;
CERT_INFO *issuerCertInfoPtr;
BOOLEAN trustedCertAcquired = FALSE;
int status;
assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
assert( formatInfo == NULL || \
isReadPtr( formatInfo, sizeof( X509SIG_FORMATINFO ) ) );
/* Since there's no signer certificate provided it has to be either
explicitly self-signed or signed by a trusted certificate */
if( certInfoPtr->flags & CERT_FLAG_SELFSIGNED )
{
if( certInfoPtr->iPubkeyContext != CRYPT_ERROR )
iCryptContext = certInfoPtr->iPubkeyContext;
issuerCertInfoPtr = certInfoPtr;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -