📄 cryptcrt.c
字号:
messageValue >= CRYPT_FIRST_EXTENSION && messageValue <= CRYPT_LAST_EXTENSION;
/* If it's a completed certificate, we can only add a restricted
class of component selection control values to the object */
assert( certInfoPtr->certificate == NULL || \
isDNSelectionComponent( messageValue ) || \
isGeneralNameSelectionComponent( messageValue ) || \
isCursorComponent( messageValue ) || \
isControlComponent( messageValue ) || \
messageValue == CRYPT_IATTRIBUTE_INITIALISED || \
messageValue == CRYPT_IATTRIBUTE_PKIUSERINFO );
/* If it's an initialisation message, there's nothing to do (we get
these when importing a cert, when the import is complete the
import code sends this message to move the cert into the high
state because it's already signed) */
if( messageValue == CRYPT_IATTRIBUTE_INITIALISED )
return( CRYPT_OK );
/* Handle internal attributes */
if( messageValue == CRYPT_IATTRIBUTE_OCSPREQUEST )
{
CERT_INFO *ocspRequestInfoPtr;
int status;
assert( certInfoPtr->type == CRYPT_CERTTYPE_OCSP_RESPONSE );
/* Copy the revocation information from the request to the
response */
getCheckInternalResource( *valuePtr, ocspRequestInfoPtr,
OBJECT_TYPE_CERTIFICATE );
assert( ocspRequestInfoPtr->type == CRYPT_CERTTYPE_OCSP_REQUEST );
status = copyRevocationEntries( &certInfoPtr->revocations,
ocspRequestInfoPtr->revocations,
&certInfoPtr->errorLocus, &certInfoPtr->errorType );
if( cryptStatusOK( status ) )
status = copyRequestAttributes( &certInfoPtr->attributes,
ocspRequestInfoPtr->attributes,
&certInfoPtr->errorLocus, &certInfoPtr->errorType );
unlockResource( ocspRequestInfoPtr );
return( status );
}
/* If the passed-in value is a cursor-positioning code, make sure
it's valid */
if( *valuePtr < 0 && *valuePtr != CRYPT_UNUSED && \
( *valuePtr > CRYPT_CURSOR_FIRST || *valuePtr < CRYPT_CURSOR_LAST ) &&
!validCursorPosition && messageValue != CRYPT_CERTINFO_SELFSIGNED )
return( CRYPT_ARGERROR_NUM1 );
return( addCertComponent( certInfoPtr, messageValue, valuePtr,
CRYPT_UNUSED ) );
}
if( message == RESOURCE_MESSAGE_SETATTRIBUTE_S )
return( addCertComponent( certInfoPtr, messageValue, msgData->data,
msgData->length ) );
if( message == RESOURCE_MESSAGE_DELETEATTRIBUTE )
return( deleteCertComponent( certInfoPtr, messageValue ) );
assert( NOTREACHED );
return( CRYPT_ERROR ); /* Get rid of compiler warning */
}
/* Handle a message sent to a certificate context */
static int certificateMessageFunction( const CRYPT_CERTIFICATE certificate,
const RESOURCE_MESSAGE_TYPE message,
void *messageDataPtr,
const int messageValue )
{
CERT_INFO *certInfoPtr;
getCheckInternalResource( certificate, certInfoPtr, OBJECT_TYPE_CERTIFICATE );
/* Process destroy object messages */
if( message == RESOURCE_MESSAGE_DESTROY )
{
/* Clear the encoded certificate and miscellaneous components if
necessary */
if( certInfoPtr->certificate != NULL )
{
zeroise( certInfoPtr->certificate, certInfoPtr->certificateSize );
free( certInfoPtr->certificate );
}
if( certInfoPtr->serialNumber != NULL )
free( certInfoPtr->serialNumber );
if( certInfoPtr->subjectUniqueID != NULL )
free( certInfoPtr->subjectUniqueID );
if( certInfoPtr->issuerUniqueID != NULL )
free( certInfoPtr->issuerUniqueID );
if( certInfoPtr->subjectDNdata != NULL )
free( certInfoPtr->subjectDNdata );
if( certInfoPtr->issuerDNdata != NULL )
free( certInfoPtr->issuerDNdata );
if( certInfoPtr->ocspUrl != NULL )
free( certInfoPtr->ocspUrl );
/* Clear the DN's if necessary */
if( certInfoPtr->issuerName != NULL )
deleteDN( &certInfoPtr->issuerName );
if( certInfoPtr->subjectName != NULL )
deleteDN( &certInfoPtr->subjectName );
/* Clear the attributes and CRL's if necessary */
if( certInfoPtr->attributes != NULL )
deleteAttributes( &certInfoPtr->attributes );
if( certInfoPtr->revocations != NULL )
deleteRevocationEntries( &certInfoPtr->revocations );
/* Clear the cert chain if necessary */
if( certInfoPtr->certChainEnd )
{
int i;
for( i = 0; i < certInfoPtr->certChainEnd; i++ )
krnlSendNotifier( certInfoPtr->certChain[ i ],
RESOURCE_IMESSAGE_DECREFCOUNT );
}
/* Delete the objects locking variables and the object itself */
unlockResource( certInfoPtr );
deleteResourceLock( certInfoPtr );
zeroise( certInfoPtr, sizeof( CERT_INFO ) );
free( certInfoPtr );
return( CRYPT_OK );
}
/* Process attribute get/set/delete messages */
if( isAttributeMessage( message ) )
{
int status = CRYPT_OK;
/* Lock the currently selected cert in a cert chain unless the
message being processed is a certificate cursor movement command
or something specifically directed at the entire chain (for
example a get type or self-signed status command - we want to get
the type/status of the chain, not of the certs within it) */
if( certInfoPtr->certChainPos != CRYPT_ERROR && \
!( ( message == RESOURCE_MESSAGE_SETATTRIBUTE ) && \
( messageValue == CRYPT_CERTINFO_CURRENT_CERTIFICATE ) ) && \
!( ( message == RESOURCE_MESSAGE_GETATTRIBUTE ) && \
( messageValue == CRYPT_CERTINFO_CERTTYPE || \
messageValue == CRYPT_CERTINFO_SELFSIGNED ) ) && \
!( ( message == RESOURCE_MESSAGE_GETATTRIBUTE_S ) && \
( messageValue == CRYPT_IATTRIBUTE_CERTSET || \
messageValue == CRYPT_IATTRIBUTE_ENC_CERT || \
messageValue == CRYPT_IATTRIBUTE_ENC_CERTCHAIN || \
messageValue == CRYPT_IATTRIBUTE_ENC_OBJDATA || \
messageValue == CRYPT_IATTRIBUTE_TEXT_CERT || \
messageValue == CRYPT_IATTRIBUTE_TEXT_CERTCHAIN ) ) )
{
CERT_INFO *certChainInfoPtr;
getCheckInternalResource( certInfoPtr->certChain[ certInfoPtr->certChainPos ],
certChainInfoPtr, OBJECT_TYPE_CERTIFICATE );
unlockResource( certInfoPtr );
certInfoPtr = certChainInfoPtr;
}
status = processCertData( certInfoPtr, message, messageDataPtr,
messageValue );
unlockResourceExit( certInfoPtr, status );
}
/* Process messages which compare the object */
if( message == RESOURCE_MESSAGE_COMPARE )
{
const RESOURCE_DATA *msgData = ( RESOURCE_DATA * ) messageDataPtr;
CERT_INFO *certInfoPtr2;
STREAM stream;
const BYTE *dataStart;
int serialNoLength, length, status;
switch( messageValue )
{
case RESOURCE_MESSAGE_COMPARE_SUBJECT:
if( msgData->length != certInfoPtr->subjectDNsize || \
memcmp( msgData->data, certInfoPtr->subjectDNptr,
certInfoPtr->subjectDNsize ) )
unlockResourceExit( certInfoPtr, CRYPT_ERROR );
unlockResourceExit( certInfoPtr, CRYPT_OK );
case RESOURCE_MESSAGE_COMPARE_ISSUERANDSERIALNUMBER:
/* Comparing an iAndS can get quite tricky because of
assorted braindamage in encoding methods, so that two
dissimilar iAndSs aren't necessarily supposed to be
regarded as non-equal. First we try a trivial reject
check, if that passes we compare the issuerName and
serialNumber with corrections for common encoding
braindamage. Note that even this comparison can fail
since older versions of the Entegrity toolkit rewrote
T61Strings in certs as PrintableStrings in recipientInfo,
which means any kind of straight comparison fails. We
don't bother handling this sort of thing, and it's likely
that most other software won't either (this situation only
occurs when a cert issuerName contains PrintableString
text incorrectly encoded as T61String, which is rare
enough that it required artifically-created certs just to
reproduce the problem). In addition the trivial reject
check can also fail since in an extreme encoding
braindamage case a BMPString rewritten as a
PrintableString would experience a large enough change in
length to fail the check, but as with the Entegrity
problem this is a level of brokenness up with which we
will not put. If it's really necessary to handle this,
we'd need to use readDN() on the supplied isser name and
then use the full compareDN() for the comparison */
length = ( int ) sizeofObject( \
certInfoPtr->issuerDNsize + \
sizeofObject( certInfoPtr->serialNumberLength ) );
if( length < msgData->length - 2 || \
length > msgData->length + 2 )
/* Trivial reject, the lengths are two dissimilar for
any fixup attempts to work */
return( CRYPT_ERROR );
/* The trivial accept/reject checks failed, try a more
detailed check, first the issuerName */
sMemConnect( &stream, msgData->data, msgData->length );
readSequence( &stream, NULL );
dataStart = sMemBufPtr( &stream );
length = getObjectLength( dataStart, msgData->length - 2 );
status = readUniversal( &stream );
if( cryptStatusError( status ) || \
length != certInfoPtr->issuerDNsize || \
memcmp( dataStart, certInfoPtr->issuerDNptr,
certInfoPtr->issuerDNsize ) )
{
sMemDisconnect( &stream );
unlockResourceExit( certInfoPtr, CRYPT_ERROR );
}
/* Compare the serialNumber. This one can get a bit tricky
because Microsoft fairly consistently encode the serial
numbers incorrectly, so we normalise the values to have no
leading zero which is the lowest common denominator */
readGenericHole( &stream, &serialNoLength );
dataStart = sMemBufPtr( &stream );
status = sSkip( &stream, serialNoLength );
sMemDisconnect( &stream );
if( !*dataStart )
{ dataStart++; serialNoLength--; } /* Skip leading zero */
if( cryptStatusError( status ) || \
serialNoLength != certInfoPtr->serialNumberLength || \
memcmp( dataStart, certInfoPtr->serialNumber,
certInfoPtr->serialNumberLength ) )
unlockResourceExit( certInfoPtr, CRYPT_ERROR );
unlockResourceExit( certInfoPtr, CRYPT_OK );
case RESOURCE_MESSAGE_COMPARE_FINGERPRINT:
getCheckInternalResource( *( ( CRYPT_CERTIFICATE * ) messageDataPtr ),
certInfoPtr2, OBJECT_TYPE_CERTIFICATE );
if( certInfoPtr->certificate == NULL || \
certInfoPtr2->certificate == NULL )
{
/* If the cert objects haven't been signed yet, we can't
compare them */
unlockResource( certInfoPtr2 );
unlockResourceExit( certInfoPtr, CRYPT_ERROR_NOTINITED );
}
/* Compare the encoded certificate data. This is the same as
comparing the fingerprint without requiring any hashing */
status = ( certInfoPtr->certificateSize == \
certInfoPtr2->certificateSize && \
!memcmp( certInfoPtr->certificate, certInfoPtr2->certificate,
certInfoPtr->certificateSize ) ) ? \
CRYPT_OK : CRYPT_ERROR;
unlockResource( certInfoPtr2 );
unlockResourceExit( certInfoPtr, status );
}
assert( NOTREACHED );
}
/* Process messages which check a certificate */
if( message == RESOURCE_MESSAGE_CHECK )
{
const int certCheckValue = \
( messageValue == RESOURCE_MESSAGE_CHECK_PKC_ENCRYPT || \
messageValue == RESOURCE_MESSAGE_CHECK_PKC_DECRYPT ) ? \
CRYPT_KEYUSAGE_KEYENCIPHERMENT : \
( messageValue == RESOURCE_MESSAGE_CHECK_PKC_SIGN || \
messageValue == RESOURCE_MESSAGE_CHECK_PKC_SIGCHECK ) ? \
( CRYPT_KEYUSAGE_DIGITALSIGNATURE | \
CRYPT_KEYUSAGE_NONREPUDIATION | \
CRYPT_KEYUSAGE_KEYCERTSIGN | CRYPT_KEYUSAGE_CRLSIGN ) : \
( messageValue == RESOURCE_MESSAGE_CHECK_PKC_KA_EXPORT ) ? \
CRYPT_KEYUSAGE_ENCIPHERONLY : \
( messageValue == RESOURCE_MESSAGE_CHECK_PKC_KA_IMPORT ) ? \
CRYPT_KEYUSAGE_DECIPHERONLY : \
( messageValue == RESOURCE_MESSAGE_CHECK_CA ) ? \
CRYPT_KEYUSAGE_KEYCERTSIGN : 0;
/* enc/decOnly usage falls back to plain keyAgree if necessary */
int status;
/* If we're not checking for a specific type of functionality
restriction set by the cert then any kind of usage is OK */
if( !certCheckValue )
unlockResourceExit( certInfoPtr, CRYPT_OK );
status = checkCertUsage( certInfoPtr, certCheckValue, messageValue,
&certInfoPtr->errorLocus, &certInfoPtr->errorType );
status = cryptStatusError( status ) ? \
CRYPT_ARGERROR_OBJECT : CRYPT_OK; /* Convert to correct form */
unlockResourceExit( certInfoPtr, status );
}
/* Process messages which lock/unlock an object for exclusive use */
if( message == RESOURCE_MESSAGE_LOCK )
{
/* Save the current volatile state so that any changes made while
the object is locked aren't reflected back to the caller */
saveSelectionState( certInfoPtr->selectionState, certInfoPtr );
/* Exit without unlocking the object. Any other threads trying to
use the object after this point will be blocked */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -