📄 certsig.c
字号:
issuerID, which is an SHA-1 hash of the IssuerAndSerialNumber and is used
for CRLs and CMS */
static int generateCertID( const void *dn, const int dnLength,
const void *serialNumber,
const int serialNumberLength, BYTE *certID )
{
HASHFUNCTION hashFunction;
HASHINFO hashInfo;
STREAM stream;
BYTE buffer[ MAX_SERIALNO_SIZE + 8 ];
int status;
assert( isReadPtr( dn, dnLength ) );
assert( ( serialNumber == NULL && serialNumberLength == 0 ) || \
( isReadPtr( serialNumber, serialNumberLength ) && \
serialNumberLength <= MAX_SERIALNO_SIZE ) );
/* Get the hash algorithm information */
getHashParameters( CRYPT_ALGO_SHA, &hashFunction, NULL );
/* If it's a pure DN hash, we don't have to perform any encoding */
if( serialNumber == NULL )
{
hashFunction( NULL, certID, dn, dnLength, HASH_ALL );
return( CRYPT_OK );
}
/* Write the relevant information to a buffer and hash the data to get
the ID */
sMemOpen( &stream, buffer, MAX_SERIALNO_SIZE + 8 );
writeSequence( &stream, dnLength + \
sizeofInteger( serialNumber, serialNumberLength ) );
hashFunction( hashInfo, NULL, buffer, stell( &stream ), HASH_START );
hashFunction( hashInfo, NULL, dn, dnLength, HASH_CONTINUE );
sseek( &stream, 0 );
status = writeInteger( &stream, serialNumber, serialNumberLength,
DEFAULT_TAG );
hashFunction( hashInfo, certID, buffer, stell( &stream ), HASH_END );
sMemClose( &stream );
return( status );
}
/* Check the entries in an RTCS or OCSP response object against a cert
store. The semantics for this one are a bit odd, the source information
for the check is from a request, but the destination information is in a
response, since we don't have a copy-and-verify function we do the
checking from the response even though, technically, it's the request
data which is being checked */
int checkRTCSResponse( CERT_INFO *certInfoPtr,
const CRYPT_KEYSET cryptKeyset )
{
VALIDITY_INFO *validityInfo;
BOOLEAN isInvalid = FALSE;
/* Walk down the list of validity entries fetching status information
on each one from the cert store */
for( validityInfo = certInfoPtr->validityInfo;
validityInfo != NULL; validityInfo = validityInfo->next )
{
MESSAGE_KEYMGMT_INFO getkeyInfo;
int status;
/* Determine the validity of the object */
setMessageKeymgmtInfo( &getkeyInfo, CRYPT_IKEYID_CERTID,
validityInfo->data, KEYID_SIZE, NULL, 0,
KEYMGMT_FLAG_CHECK_ONLY );
status = krnlSendMessage( cryptKeyset, IMESSAGE_KEY_GETKEY,
&getkeyInfo, KEYMGMT_ITEM_PUBLICKEY );
if( cryptStatusOK( status ) )
{
/* The cert is present and OK, we're done */
validityInfo->status = TRUE;
validityInfo->extStatus = CRYPT_CERTSTATUS_VALID;
}
else
{
/* The cert isn't present/OK, record the fact that we've seen at
least one invalid cert */
validityInfo->status = FALSE;
validityInfo->extStatus = CRYPT_CERTSTATUS_NOTVALID;
isInvalid = TRUE;
}
}
/* If at least one cert was invalid, indicate this to the caller. Note
that if there are multiple certs present in the query, it's up to the
caller to step through the list to find out which ones were invalid */
return( isInvalid ? CRYPT_ERROR_INVALID : CRYPT_OK );
}
int checkOCSPResponse( CERT_INFO *certInfoPtr,
const CRYPT_KEYSET cryptKeyset )
{
REVOCATION_INFO *revocationInfo;
BOOLEAN isRevoked = FALSE;
/* Walk down the list of revocation entries fetching status information
on each one from the cert store */
for( revocationInfo = certInfoPtr->revocations;
revocationInfo != NULL; revocationInfo = revocationInfo->next )
{
MESSAGE_KEYMGMT_INFO getkeyInfo;
CERT_INFO *crlEntryInfoPtr;
REVOCATION_INFO *crlRevocationInfo;
int status;
assert( revocationInfo->type == CRYPT_KEYID_NONE || \
revocationInfo->type == CRYPT_IKEYID_CERTID || \
revocationInfo->type == CRYPT_IKEYID_ISSUERID );
/* If it's an OCSPv1 ID, we can't really do anything with it because
the one-way hashing process required by the standard destroys the
information */
if( revocationInfo->type == CRYPT_KEYID_NONE )
{
revocationInfo->status = CRYPT_OCSPSTATUS_UNKNOWN;
continue;
}
/* Determine the revocation status of the object. Unfortunately
because of the way OCSP returns status information we can't just
return a yes/no response but have to perform multiple queries to
determine whether a cert is not revoked, revoked, or unknown.
Optimising the query strategy is complicated by the fact that
although in theory the most common status will be not-revoked, we
could also get a large number of unknown queries, for example if
a widely-deployed implementation which is pointed at a cryptlib-
based server gets its ID-hashing wrong and submits huge numbers of
queries with IDs that match no known cert. The best we can do is
assume that a not-revoked status will be the most common, and if
that fails fall back to a revoked status check */
setMessageKeymgmtInfo( &getkeyInfo, revocationInfo->type,
revocationInfo->dataPtr, KEYID_SIZE, NULL, 0,
KEYMGMT_FLAG_CHECK_ONLY );
status = krnlSendMessage( cryptKeyset, IMESSAGE_KEY_GETKEY,
&getkeyInfo, KEYMGMT_ITEM_PUBLICKEY );
if( cryptStatusOK( status ) )
{
/* The cert is present and not revoked/OK, we're done */
revocationInfo->status = CRYPT_OCSPSTATUS_NOTREVOKED;
continue;
}
/* The cert isn't a currently active cert, if it weren't for the need
to return the CRL-based OCSP status values we could just return
not-OK now, but as it is we have to differentiate between revoked
and unknown, so we perform a second query, this time of the
revocation information */
setMessageKeymgmtInfo( &getkeyInfo, revocationInfo->type,
revocationInfo->dataPtr, KEYID_SIZE, NULL, 0,
KEYMGMT_FLAG_NONE );
status = krnlSendMessage( cryptKeyset, IMESSAGE_KEY_GETKEY,
&getkeyInfo, KEYMGMT_ITEM_REVOCATIONINFO );
if( cryptStatusError( status ) )
{
/* No revocation information found, status is unknown */
revocationInfo->status = CRYPT_OCSPSTATUS_UNKNOWN;
continue;
}
/* The cert has been revoked, copy the revocation information across
from the CRL entry. We don't check for problems in copying the
attributes since bailing out at this late stage is worse than
missing a few obscure annotations to the revocation */
status = krnlGetObject( getkeyInfo.cryptHandle,
OBJECT_TYPE_CERTIFICATE,
( void ** ) &crlEntryInfoPtr,
CRYPT_ERROR_SIGNALLED );
if( cryptStatusError( status ) )
return( status );
crlRevocationInfo = crlEntryInfoPtr->revocations;
if( crlRevocationInfo != NULL )
{
revocationInfo->revocationTime = \
crlRevocationInfo->revocationTime;
if( crlRevocationInfo->attributes != NULL )
copyRevocationAttributes( &revocationInfo->attributes,
crlRevocationInfo->attributes,
&certInfoPtr->errorLocus, &certInfoPtr->errorType );
}
krnlReleaseObject( crlEntryInfoPtr->objectHandle );
krnlSendNotifier( getkeyInfo.cryptHandle, IMESSAGE_DECREFCOUNT );
/* Record the fact that we've seen at least one revoked cert */
revocationInfo->status = CRYPT_OCSPSTATUS_REVOKED;
isRevoked = TRUE;
}
/* If at least one cert was revoked, indicate this to the caller. Note
that if there are multiple certs present in the query, it's up to the
caller to step through the list to find out which ones were revoked */
return( isRevoked ? CRYPT_ERROR_INVALID : CRYPT_OK );
}
/* Check a certificate using an RTCS or OCSP responder */
static int checkResponder( CERT_INFO *certInfoPtr,
const CRYPT_SESSION cryptSession )
{
CRYPT_CERTIFICATE cryptResponse;
MESSAGE_CREATEOBJECT_INFO createInfo;
int type, status;
status = krnlSendMessage( cryptSession, IMESSAGE_GETATTRIBUTE, &type,
CRYPT_IATTRIBUTE_SUBTYPE );
if( cryptStatusError( status ) )
return( status );
assert( ( type == SUBTYPE_SESSION_RTCS ) || \
( type == SUBTYPE_SESSION_OCSP ) );
/* Create the request, add the certificate, and add the request to the
session */
setMessageCreateObjectInfo( &createInfo,
( type == SUBTYPE_SESSION_RTCS ) ? \
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( cryptSession, 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( cryptSession, IMESSAGE_SETATTRIBUTE,
MESSAGE_VALUE_TRUE, CRYPT_SESSINFO_ACTIVE );
if( cryptStatusOK( status ) )
status = krnlSendMessage( cryptSession, 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 */
static int checkCRL( CERT_INFO *certInfoPtr, const CRYPT_CERTIFICATE cryptCRL )
{
CERT_INFO *crlInfoPtr;
int i, status;
/* Check that the CRL is a complete, signed CRL and not a newly-created
CRL object */
status = krnlGetObject( cryptCRL, 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 cert against the CRL. If it's been revoked or there's
only a single cert present, exit */
status = checkRevocation( certInfoPtr, crlInfoPtr );
if( cryptStatusError( status ) || \
certInfoPtr->type != CRYPT_CERTTYPE_CERTCHAIN )
{
krnlReleaseObject( crlInfoPtr->objectHandle );
return( status );
}
/* It's a cert chain, check every remaining cert in the chain against the
CRL. In theory this is pointless because a CRL can only contain
information for a single cert in the chain, however the caller may
have passed us a CRL for an intermediate cert (in which case the check
for the leaf cert was pointless). In any case it's easier to just do
the check for all certs than to determine which cert the CRL applies
to, so we check for all certs */
for( i = 0; i < certInfoPtr->certChainEnd; i++ )
{
CERT_INFO *certChainInfoPtr;
/* Check this cert against the CRL */
status = krnlGetObject( certInfoPtr->certChain[ i ],
OBJECT_TYPE_CERTIFICATE,
( void ** ) &certChainInfoPtr,
CRYPT_ERROR_SIGNALLED );
if( cryptStatusOK( status ) )
{
status = checkRevocation( certChainInfoPtr, crlInfoPtr );
krnlReleaseObject( certChainInfoPtr->objectHandle );
}
/* If the cert has been revoked, remember which one is the revoked
cert and exit */
if( cryptStatusError( status ) )
{
certInfoPtr->certChainPos = i;
krnlReleaseObject( crlInfoPtr->objectHandle );
return( status );
}
}
krnlReleaseObject( crlInfoPtr->objectHandle );
return( CRYPT_OK );
}
/* Check a self-signed certificate like a cert request or a self-signed
cert */
static int checkSelfSignedCert( CERT_INFO *certInfoPtr,
const int formatInfo )
{
CRYPT_CONTEXT iCryptContext;
CERT_INFO *issuerCertInfoPtr;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -