📄 cryptcrt.c
字号:
getCertWriteFunction( CRYPT_CERTTYPE_CMS_ATTRIBUTES );
ENSURES( writeCertFunction != NULL );
sMemOpenOpt( &stream, certData, certDataMaxLength );
status = writeCertFunction( &stream, certInfoPtr, NULL,
CRYPT_UNUSED );
if( cryptStatusOK( status ) )
*certDataLength = 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 certificate from a chain, lock the
currently selected certificate in the chain and export that */
if( certInfoPtr->type == CRYPT_CERTTYPE_CERTCHAIN && \
certInfoPtr->cCertCert->chainPos >= 0 && \
( certFormat == CRYPT_CERTFORMAT_CERTIFICATE || \
certFormat == CRYPT_CERTFORMAT_TEXT_CERTIFICATE || \
certFormat == CRYPT_CERTFORMAT_XML_CERTIFICATE ) )
{
CERT_INFO *certChainInfoPtr;
ENSURES( certInfoPtr->cCertCert->chainPos >= 0 && \
certInfoPtr->cCertCert->chainPos < MAX_CHAINLENGTH );
status = krnlAcquireObject( certInfoPtr->cCertCert->chain[ certInfoPtr->cCertCert->chainPos ],
OBJECT_TYPE_CERTIFICATE,
( void ** ) &certChainInfoPtr,
CRYPT_ARGERROR_OBJECT );
if( cryptStatusError( status ) )
return( status );
status = exportCert( certData, certDataMaxLength, certDataLength,
certFormat, certChainInfoPtr );
krnlReleaseObject( certChainInfoPtr->objectHandle );
return( status );
}
ENSURES( ( ( certInfoPtr->flags & CERT_FLAG_CERTCOLLECTION ) && \
certInfoPtr->certificate == NULL ) || \
certInfoPtr->certificate != NULL );
return( exportCert( certData, certDataMaxLength, certDataLength,
certFormat, certInfoPtr ) );
}
/****************************************************************************
* *
* Internal Certificate/Key Management Functions *
* *
****************************************************************************/
/* Import a certificate blob or certificate chain by sending get_next_cert
messages to the source object to obtain all the certificates in a chain.
Returns the length of the certificate.
This isn't really a direct certificate function since the control flow
sequence is:
import indirect:
GETNEXTCERT -> source object
source object:
CREATEOBJECT_INDIRECT -> system device
system device: createCertificate()
GETNEXTCERT -> source object
source object:
CREATEOBJECT_INDIRECT -> system device
system device: createCertificate()
[...]
however this seems to be the best place to put the code (sol lucet
omnibus) */
CHECK_RETVAL_BOOL STDC_NONNULL_ARG( ( 1, 4 ) ) \
int iCryptImportCertIndirect( OUT_HANDLE_OPT CRYPT_CERTIFICATE *iCertificate,
IN_HANDLE const CRYPT_HANDLE iCertSource,
IN_ENUM( CRYPT_KEYID ) \
const CRYPT_KEYID_TYPE keyIDtype,
IN_BUFFER( keyIDlength ) const void *keyID,
IN_LENGTH_SHORT const int keyIDlength,
IN_FLAGS_Z( KEYMGMT ) const int options )
{
assert( isWritePtr( iCertificate, sizeof( CRYPT_CERTIFICATE ) ) );
assert( isReadPtr( keyID, keyIDlength ) );
REQUIRES( isHandleRangeValid( iCertSource ) );
REQUIRES( keyIDtype > CRYPT_KEYID_NONE && keyIDtype < CRYPT_KEYID_LAST );
REQUIRES( keyIDlength > 0 && keyIDlength < MAX_INTLENGTH_SHORT );
REQUIRES( options >= KEYMGMT_FLAG_NONE && options < KEYMGMT_FLAG_MAX && \
( options & ~KEYMGMT_MASK_CERTOPTIONS ) == 0 );
/* Clear return value */
*iCertificate = CRYPT_ERROR;
/* We're importing a sequence of certificates as a chain from a source
object, assemble the collection via the object */
return( assembleCertChain( iCertificate, iCertSource, keyIDtype,
keyID, keyIDlength, options ) );
}
/* Read a public key from an X.509 SubjectPublicKeyInfo record, creating the
context necessary to contain it in the process. Like the certificate
import function above this is another function of no fixed abode that
exists here because it's the least inappropriate location.
The use of the void * instead of STREAM * is necessary because the STREAM
type isn't visible at the global level */
CHECK_RETVAL_BOOL STDC_NONNULL_ARG( ( 1, 2 ) ) \
int iCryptReadSubjectPublicKey( INOUT TYPECAST( STREAM * ) void *streamPtr,
OUT_HANDLE_OPT CRYPT_CONTEXT *iPubkeyContext,
const BOOLEAN deferredLoad )
{
CRYPT_ALGO_TYPE cryptAlgo;
CRYPT_CONTEXT iCryptContext;
MESSAGE_CREATEOBJECT_INFO createInfo;
MESSAGE_DATA msgData;
STREAM *stream = streamPtr;
void *spkiPtr = DUMMY_INIT_PTR;
int length, spkiLength, status;
assert( isReadPtr( stream, sizeof( STREAM ) ) );
assert( isWritePtr( iPubkeyContext, sizeof( CRYPT_CONTEXT ) ) );
/* Clear return value */
*iPubkeyContext = CRYPT_ERROR;
/* Pre-parse the SubjectPublicKeyInfo, both to ensure that its valid
before we go tothe extent of creating an encryption context to
contain it and to get access to the SubjectPublicKeyInfo data and
algorithm info. Because all sorts of bizarre tagging exists due to
things like CRMF we read the wrapper as a generic hole rather than
the more obvious SEQUENCE. The length values are only approximate
because there's wrapper data involved and (for the maximum length)
several of the DLP PKC values are only a fraction of
CRYPT_MAX_PKCSIZE, the rest of the space requirement being allocated
to the wrapper */
status = getStreamObjectLength( stream, &spkiLength );
if( cryptStatusOK( status ) )
status = sMemGetDataBlock( stream, &spkiPtr, spkiLength );
if( cryptStatusOK( status ) )
status = readGenericHole( stream, NULL, 16, DEFAULT_TAG );
if( cryptStatusError( status ) )
return( status );
if( spkiLength < 8 + MIN_PKCSIZE || \
spkiLength > CRYPT_MAX_PKCSIZE * 4 )
{
/* If we're reading a certificate with a comically short public key
we should try and return something a bit more informative than a
generic bad-data error. If we find a key like this we return
an insecure-key error instead */
if( isShortPKCKey( spkiLength - 8 ) )
return( CRYPT_ERROR_NOSECURE );
return( CRYPT_ERROR_BADDATA );
}
status = readAlgoIDparams( stream, &cryptAlgo, &length );
if( cryptStatusOK( status ) && length > 0 )
{
/* There are algorithm parameters present, skip them */
status = readUniversal( stream );
}
if( cryptStatusOK( status ) )
{
/* Read the public-key data */
status = readUniversal( stream );
}
if( cryptStatusError( status ) )
return( status );
/* Create the public-key context and send the public-key data to it */
setMessageCreateObjectInfo( &createInfo, cryptAlgo );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
IMESSAGE_DEV_CREATEOBJECT, &createInfo,
OBJECT_TYPE_CONTEXT );
if( cryptStatusError( status ) )
return( status );
iCryptContext = createInfo.cryptHandle;
setMessageData( &msgData, spkiPtr, spkiLength );
status = krnlSendMessage( iCryptContext, IMESSAGE_SETATTRIBUTE_S,
&msgData, deferredLoad ? \
CRYPT_IATTRIBUTE_KEY_SPKI_PARTIAL : \
CRYPT_IATTRIBUTE_KEY_SPKI );
if( cryptStatusError( status ) )
{
krnlSendNotifier( iCryptContext, IMESSAGE_DECREFCOUNT );
return( status );
}
*iPubkeyContext = iCryptContext;
assert( cryptStatusError( \
krnlSendMessage( iCryptContext, IMESSAGE_CHECK,
NULL, MESSAGE_CHECK_PKC_PRIVATE ) ) );
return( CRYPT_OK );
}
/****************************************************************************
* *
* Certificate Management API Functions *
* *
****************************************************************************/
/* Handle attribute data sent to or read from a certificate object. We have
to do this in a standalone function since it's called from several places
in the certificate message handler */
CHECK_RETVAL_BOOL STDC_NONNULL_ARG( ( 1, 3 ) ) \
static int processCertAttribute( INOUT CERT_INFO *certInfoPtr,
IN_MESSAGE const MESSAGE_TYPE message,
INOUT void *messageDataPtr,
IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE attribute )
{
MESSAGE_DATA *msgData = ( MESSAGE_DATA * ) messageDataPtr;
int *valuePtr = ( int * ) messageDataPtr;
assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
REQUIRES( message == MESSAGE_GETATTRIBUTE || \
message == MESSAGE_GETATTRIBUTE_S || \
message == MESSAGE_SETATTRIBUTE || \
message == MESSAGE_SETATTRIBUTE_S || \
message == MESSAGE_DELETEATTRIBUTE );
REQUIRES( isAttribute( attribute ) || \
isInternalAttribute( attribute ) );
/* Process get/set/delete attribute messages */
if( message == MESSAGE_GETATTRIBUTE )
{
int dummy;
if( attribute == CRYPT_ATTRIBUTE_ERRORTYPE )
{
*valuePtr = certInfoPtr->errorType;
return( CRYPT_OK );
}
if( attribute == CRYPT_ATTRIBUTE_ERRORLOCUS )
{
*valuePtr = certInfoPtr->errorLocus;
return( CRYPT_OK );
}
return( getCertComponent( certInfoPtr, attribute, valuePtr,
sizeof( int ), &dummy ) );
}
if( message == MESSAGE_GETATTRIBUTE_S )
return( getCertComponent( certInfoPtr, attribute,
msgData->data, msgData->length,
&msgData->length ) );
if( message == MESSAGE_SETATTRIBUTE )
{
BOOLEAN validCursorPosition;
if( certInfoPtr->type == CRYPT_CERTTYPE_CMS_ATTRIBUTES )
{
validCursorPosition = \
( attribute >= CRYPT_CERTINFO_FIRST_CMS && \
attribute <= CRYPT_CERTINFO_LAST_CMS ) ? TRUE : FALSE;
}
else
{
validCursorPosition = \
( attribute >= CRYPT_CERTINFO_FIRST_EXTENSION && \
attribute <= CRYPT_CERTINFO_LAST_EXTENSION ) ? TRUE : FALSE;
}
/* If it's a completed certificate we can only add a restricted
class of component selection control values to the object. We
don't use continuation characters for the more complex isXYZ()
expressions because the resulting string is too long for some
broken compilers */
REQUIRES( certInfoPtr->certificate == NULL || \
isDNSelectionComponent( attribute ) ||
isGeneralNameSelectionComponent( attribute ) ||
isCursorComponent( attribute ) ||
isControlComponent( attribute ) ||
attribute == CRYPT_IATTRIBUTE_INITIALISED || \
attribute == CRYPT_IATTRIBUTE_PKIUSERINFO );
/* If it's an initialisation message, there's nothing to do (we get
these when importing a certificate, 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( attribute == 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 && attribute != CRYPT_CERTINFO_SELFSIGNED )
return( CRYPT_ARGERROR_NUM1 );
return( addCertComponent( certInfoPtr, attribute, valuePtr,
CRYPT_UNUSED ) );
}
if( message == MESSAGE_SETATTRIBUTE_S )
return( addCertComponent( certInfoPtr, attribute, msgData->data,
msgData->length ) );
if( message == MESSAGE_DELETEATTRIBUTE )
return( deleteCertComponent( certInfoPtr, attribute ) );
retIntError();
}
/* Handle a message sent to a certificate context */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
static int certificateMessageFunction( INOUT TYPECAST( CERT_INFO * ) \
void *objectInfoPtr,
IN_MESSAGE const MESSAGE_TYPE message,
void *messageDataPtr,
IN_INT_Z const int messageValue )
{
CERT_INFO *certInfoPtr = ( CERT_INFO * ) objectInfoPtr;
assert( isWritePtr( objectInfoPtr, sizeof( CERT_INFO ) ) );
REQUIRES( message > MESSAGE_NONE && message < MESSAGE_LAST );
REQUIRES( ( message == MESSAGE_CRT_SIGCHECK && \
messageValue == CRYPT_UNUSED ) || \
( messageValue >= 0 && messageValue < MAX_INTLENGTH ) );
/* 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 certificate 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->type == CRYPT_CERTTYPE_CERTIFICATE || \
certInfoPtr->type == CRYPT_CERTTYPE_ATTRIBUTE_CERT || \
certInfoPtr->type == CRYPT_CERTTYPE_CERTCHAIN )
{
if( certInfoPtr->cCertCert->serialNumber != NULL && \
certInfoPtr->cCertCert->serialNumber != \
certInfoPtr->cCertCert->serialNumberBuffer )
clFree( "certificateMessageFunction",
certInfoPtr->cCertCert->serialNumber );
}
if( certInfoPtr->type == CRYPT_CERTTYPE_REQUEST_REVOCATION )
{
if( certInfoPtr->cCertReq->serialNumber != NULL && \
certInfoPtr->cCertReq->serialNumber != \
certInfoPtr->cCertReq->serialNumberBuffer )
clFree( "certificateMessageFunction",
certInfoPtr->cCertReq->serialNumber );
}
if( certInfoPtr->type == CRYPT_CERTTYPE_CERTIFICATE )
{
if( certInfoPtr->cCertCert->subjectUniqueID != NULL )
clFree( "certificateMessageFunction",
certInfoPtr->cCertCert->subjectUniqueID );
if( certInfoPtr->cCertCert->issuerUniqueID != NULL )
clFree( "certificateMessageFunction",
certInfoPtr->cCertCert->issuerUniqueID );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -