📄 cryptcrt.c
字号:
if( cryptStatusError( status ) )
{
krnlSendNotifier( createInfo.cryptHandle, IMESSAGE_DECREFCOUNT );
return( status );
}
*iPubkeyContext = createInfo.cryptHandle;
assert( cryptStatusError( \
krnlSendMessage( createInfo.cryptHandle, IMESSAGE_CHECK,
NULL, MESSAGE_CHECK_PKC_PRIVATE ) ) );
return( CRYPT_OK );
}
/****************************************************************************
* *
* Certificate Management API Functions *
* *
****************************************************************************/
/* Handle data sent to or read from a cert object */
static int processCertData( CERT_INFO *certInfoPtr,
const MESSAGE_TYPE message,
void *messageDataPtr, const int messageValue )
{
RESOURCE_DATA *msgData = ( RESOURCE_DATA * ) messageDataPtr;
int *valuePtr = ( int * ) messageDataPtr;
/* Process get/set/delete attribute messages */
if( message == MESSAGE_GETATTRIBUTE )
{
if( messageValue == CRYPT_ATTRIBUTE_ERRORTYPE )
{
*valuePtr = certInfoPtr->errorType;
return( CRYPT_OK );
}
if( messageValue == CRYPT_ATTRIBUTE_ERRORLOCUS )
{
*valuePtr = certInfoPtr->errorLocus;
return( CRYPT_OK );
}
return( getCertComponent( certInfoPtr, messageValue, valuePtr, NULL ) );
}
if( message == MESSAGE_GETATTRIBUTE_S )
return( getCertComponent( certInfoPtr, messageValue,
msgData->data, &msgData->length ) );
if( message == MESSAGE_SETATTRIBUTE )
{
const BOOLEAN validCursorPosition = \
( certInfoPtr->type == CRYPT_CERTTYPE_CMS_ATTRIBUTES ) ? \
messageValue >= CRYPT_CERTINFO_FIRST_CMS && \
messageValue <= CRYPT_CERTINFO_LAST_CMS : \
messageValue >= CRYPT_CERTINFO_FIRST_EXTENSION && \
messageValue <= CRYPT_CERTINFO_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 );
/* If the passed-in value is a cursor-positioning code, make sure
that 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 == MESSAGE_SETATTRIBUTE_S )
return( addCertComponent( certInfoPtr, messageValue, msgData->data,
msgData->length ) );
if( message == 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 void *objectInfoPtr,
const MESSAGE_TYPE message,
void *messageDataPtr,
const int messageValue )
{
CERT_INFO *certInfoPtr = ( CERT_INFO * ) objectInfoPtr;
/* Process destroy object messages */
if( message == MESSAGE_DESTROY )
{
/* Clear the encoded certificate and miscellaneous components if
necessary. Note that there's no need to clear the associated
encryption context (if any) since this is a dependent object of
the cert and is destroyed by the kernel when the cert is
destroyed */
if( certInfoPtr->certificate != NULL )
{
zeroise( certInfoPtr->certificate, certInfoPtr->certificateSize );
clFree( "certificateMessageFunction", certInfoPtr->certificate );
}
if( certInfoPtr->serialNumber != NULL && \
certInfoPtr->serialNumber != certInfoPtr->serialNumberBuffer )
clFree( "certificateMessageFunction", certInfoPtr->serialNumber );
if( certInfoPtr->subjectUniqueID != NULL )
clFree( "certificateMessageFunction", certInfoPtr->subjectUniqueID );
if( certInfoPtr->issuerUniqueID != NULL )
clFree( "certificateMessageFunction", certInfoPtr->issuerUniqueID );
if( certInfoPtr->publicKeyData != NULL )
clFree( "certificateMessageFunction", certInfoPtr->publicKeyData );
if( certInfoPtr->subjectDNdata != NULL )
clFree( "certificateMessageFunction", certInfoPtr->subjectDNdata );
if( certInfoPtr->issuerDNdata != NULL )
clFree( "certificateMessageFunction", certInfoPtr->issuerDNdata );
if( certInfoPtr->responderUrl != NULL )
clFree( "certificateMessageFunction", certInfoPtr->responderUrl );
/* 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 ],
IMESSAGE_DECREFCOUNT );
}
/* Delete the object itself */
zeroise( certInfoPtr, sizeof( CERT_INFO ) );
clFree( "certificateMessageFunction", certInfoPtr );
return( CRYPT_OK );
}
/* Process attribute get/set/delete messages */
if( isAttributeMessage( message ) )
{
/* If it's a cert chain, lock the currently selected cert in the
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 >= 0 && \
!( ( message == MESSAGE_SETATTRIBUTE ) && \
( messageValue == CRYPT_CERTINFO_CURRENT_CERTIFICATE ) ) && \
!( ( message == MESSAGE_GETATTRIBUTE ) && \
( messageValue == CRYPT_CERTINFO_CERTTYPE || \
messageValue == CRYPT_CERTINFO_SELFSIGNED ) ) )
{
CERT_INFO *certChainInfoPtr;
int status;
status = krnlGetObject( certInfoPtr->certChain[ certInfoPtr->certChainPos ],
OBJECT_TYPE_CERTIFICATE,
( void ** ) &certChainInfoPtr,
CRYPT_ARGERROR_OBJECT );
if( cryptStatusError( status ) )
return( status );
status = processCertData( certChainInfoPtr, message, messageDataPtr,
messageValue );
krnlReleaseObject( certChainInfoPtr->objectHandle );
return( status );
}
return( processCertData( certInfoPtr, message, messageDataPtr,
messageValue ) );
}
/* Process messages that compare the object */
if( message == MESSAGE_COMPARE )
return( compareCertInfo( certInfoPtr, messageValue,
messageDataPtr ) );
/* Process messages that check a certificate */
if( message == MESSAGE_CHECK )
{
const int certCheckValue = \
( messageValue == MESSAGE_CHECK_PKC_ENCRYPT || \
messageValue == MESSAGE_CHECK_PKC_DECRYPT ) ? \
CRYPT_KEYUSAGE_KEYENCIPHERMENT : \
( messageValue == MESSAGE_CHECK_PKC_SIGN || \
messageValue == MESSAGE_CHECK_PKC_SIGCHECK ) ? \
( CRYPT_KEYUSAGE_DIGITALSIGNATURE | \
CRYPT_KEYUSAGE_NONREPUDIATION | \
CRYPT_KEYUSAGE_KEYCERTSIGN | CRYPT_KEYUSAGE_CRLSIGN ) : \
( messageValue == MESSAGE_CHECK_PKC_KA_EXPORT ) ? \
CRYPT_KEYUSAGE_ENCIPHERONLY : \
( messageValue == MESSAGE_CHECK_PKC_KA_IMPORT ) ? \
CRYPT_KEYUSAGE_DECIPHERONLY : \
( messageValue == 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 )
return( CRYPT_OK );
status = checkCertUsage( certInfoPtr, certCheckValue, messageValue,
&certInfoPtr->errorLocus, &certInfoPtr->errorType );
status = cryptStatusError( status ) ? \
CRYPT_ARGERROR_OBJECT : CRYPT_OK; /* Convert to correct form */
return( status );
}
/* Process internal notification messages */
if( message == MESSAGE_CHANGENOTIFY )
{
/* If the object has been locked/unlocked, save/restore the internal
state */
if( messageValue == CRYPT_IATTRIBUTE_LOCKED )
{
if( messageDataPtr == MESSAGE_VALUE_TRUE )
{
/* 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 );
}
else
{
/* Restore the volatile state from before the object was
locked */
restoreSelectionState( certInfoPtr->selectionState,
certInfoPtr );
}
return( CRYPT_OK );
}
assert( NOTREACHED );
return( CRYPT_ERROR ); /* Get rid of compiler warning */
}
/* Process object-specific messages */
if( message == MESSAGE_CRT_SIGN )
{
int status;
assert( certInfoPtr->certificate == NULL );
/* Make sure that the signing object can actually be used for
signing */
status = krnlSendMessage( messageValue, IMESSAGE_CHECK, NULL,
MESSAGE_CHECK_PKC_SIGN );
if( cryptStatusError( status ) )
{
/* The only time we can use a signing object that can't sign is
when we have a CRMF request, which can be created with an
encryption-only key if the private key POP is performed via
an out-of-band mechanism. If this is the case, we make sure
that the key can decrypt, which is the other way of performing
POP if a signing key isn't available */
if( certInfoPtr->type != CRYPT_CERTTYPE_REQUEST_CERT )
return( CRYPT_ARGERROR_VALUE );
status = krnlSendMessage( messageValue, IMESSAGE_CHECK, NULL,
MESSAGE_CHECK_PKC_DECRYPT );
if( cryptStatusError( status ) )
return( CRYPT_ARGERROR_VALUE );
}
/* We're changing data in a certificate, clear the error
information */
clearErrorInfo( certInfoPtr );
return( signCert( certInfoPtr, messageValue ) );
}
if( message == MESSAGE_CRT_SIGCHECK )
{
assert( certInfoPtr->certificate != NULL || \
certInfoPtr->type == CRYPT_CERTTYPE_RTCS_RESPONSE || \
certInfoPtr->type == CRYPT_CERTTYPE_OCSP_RESPONSE );
/* We're checking data in a certificate, clear the error
information */
clearErrorInfo( certInfoPtr );
return( checkCertValidity( certInfoPtr, messageValue ) );
}
if( message == MESSAGE_CRT_EXPORT )
{
RESOURCE_DATA *msgData = ( RESOURCE_DATA * ) messageDataPtr;
int status;
assert( messageValue > CRYPT_CERTFORMAT_NONE && \
messageValue < CRYPT_CERTFORMAT_LAST );
/* Unsigned object types like CMS attributes aren't signed like other
cert.objects so they aren't pre-encoded when we sign them, and
have the potential to change on each use if the same CMS
attributes are reused for multiple signatures. Because of this
we write them out on export rather than copying the pre-encoded
form from an internal buffer */
if( certInfoPtr->type == CRYPT_CERTTYPE_CMS_ATTRIBUTES )
{
STREAM stream;
int i;
assert( messageValue == CRYPT_ICERTFORMAT_DATA );
for( i = 0; \
certWriteTable[ i ].type != CRYPT_CERTTYPE_CMS_ATTRIBUTES && \
certWriteTable[ i ].type != CRYPT_CERTTYPE_NONE; i++ );
if( certWriteTable[ i ].type == CRYPT_CERTTYPE_NONE )
{
assert( NOTREACHED );
return( CRYPT_ERROR_NOTAVAIL );
}
sMemOpen( &stream, msgData->data, msgData->length );
status = certWriteTable[ i ].writeFunction( &stream, certInfoPtr,
NULL, CRYPT_UNUSED );
msgData->length = stell( &stream );
sMemDisconnect( &stream );
return( status );
}
/* Some objects aren't signed, or are pseudo-signed or optionally
signed, and have to be handled specially. RTCS requests and
responses are never signed (they're pure data containers like
CMS attributes, with protection being provided by CMS). OCSP
requests can be optionally signed but usually aren't, so if
we're fed an OCSP request without any associated encoded data we
pseudo-sign it to produce encoded data. PKI user data is never
signed but needs to go through a one-off setup process to
initialise the user data fields so it has the same semantics as a
pseudo-signed object. CRMF revocation requests are never signed
(thus ruling out suicide-note revocations) */
if( ( certInfoPtr->type == CRYPT_CERTTYPE_RTCS_REQUEST || \
certInfoPtr->type == CRYPT_CERTTYPE_RTCS_RESPONSE || \
certInfoPtr->type == CRYPT_CERTTYPE_OCSP_REQUEST || \
certInfoPtr->type == CRYPT_CERTTYPE_PKIUSER || \
certInfoPtr->type == CRYPT_CERTTYPE_REQUEST_REVOCATION ) && \
certInfoPtr->certificate == NULL )
{
status = signCert( certInfoPtr, CRYPT_UNUSED );
if( cryptStatusError( status ) )
return( status );
}
/* If we're exporting a single cert from a chain, lock the currently
selected cert in the chain and export that */
if( certInfoPtr->certChainPos >= 0 && \
( messageValue == CRYPT_CERTFORMAT_CERTIFICATE || \
messageValue == CRYPT_CERTFORMAT_TEXT_CERTIFICATE || \
messageValue == CRYPT_CERTFORMAT_XML_CERTIFICATE ) )
{
CERT_INFO *certChainInfoPtr;
status = krnlGetObject( certInfoPtr->certChain[ certInfoPtr->certChainPos ],
OBJECT_TYPE_CERTIFICATE,
( void ** ) &certChainInfoPtr,
CRYPT_ARGERROR_OBJECT );
if( cryptStatusError( status ) )
return( status );
status = exportCert( msgData->data, &msgData->length,
messageValue, certChainInfoPtr,
msgData->length );
krnlReleaseObject( certChainInfoPtr->objectHandle );
return( status );
}
assert( ( ( certInfoPtr->flags & CERT_FLAG_CERTCOLLECTION ) && \
certInfoPtr->certificate == NULL ) || \
certInfoPtr->certificate != NULL );
return( exportCert( msgData->data, &msgData->length,
messageValue, certInfoPtr, msgData->length ) );
}
assert( NOTREACHED );
return( CRYPT_ERROR ); /* Get rid of compiler warning */
}
/* Create a certificate object, returning a pointer to the locked cert info
ready for further initialisation */
int createCertificateInfo( CERT_INFO **certInfoPtrPtr,
const CRYPT_USER cryptOwner,
const CRYPT_CERTTYPE_TYPE certType )
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -