📄 chain.c
字号:
once we've got all the certs and know which cert is the leaf, we
can go back and decode the public key information for it */
status = importCert( sMemBufPtr( stream ), sMemDataLeft( stream ),
&iNewCert, cryptOwner, CRYPT_KEYID_NONE,
NULL, 0, dataOnlyCert ? \
CERTFORMAT_DATAONLY : \
CRYPT_CERTTYPE_CERTIFICATE );
if( cryptStatusOK( status ) )
{
RESOURCE_DATA msgData;
/* Add the newly-read cert to the chain and skip over its
encoded data. Unfortunately due to the mixing of stream and
non-stream functions we have to do this in a somewhat
roundabout manner by getting the length of the data in the
newly-created cert object and then skipping that far ahead in
the input stream */
iCertChain[ certChainEnd++ ] = iNewCert;
setMessageData( &msgData, NULL, 0 );
status = krnlSendMessage( iNewCert, IMESSAGE_CRT_EXPORT,
&msgData, CRYPT_CERTFORMAT_CERTIFICATE );
if( cryptStatusOK( status ) )
status = sSkip( stream, msgData.length );
}
if( cryptStatusError( status ) )
{
if( certChainEnd > 0 )
freeCertChain( iCertChain, certChainEnd );
return( status );
}
/* If it's encoded using the indefinite form and we find the EOC
octets, exit */
if( certSequenceLength == CRYPT_UNUSED )
{
status = checkEOC( stream );
if( cryptStatusError( status ) )
return( status );
if( status == TRUE )
/* We've seen EOC octets, we're done */
break;
}
}
/* We must have read at least one cert in order to create a chain */
if( certChainEnd <= 0 )
return( CRYPT_ERROR_BADDATA );
/* Build the complete chain from the individual certs */
return( buildCertChain( iCryptCert, iCertChain, certChainEnd,
keyIDtype, keyID, keyIDlength ) );
}
/* Fetch a sequence of certs from an object to create a cert chain */
int assembleCertChain( CRYPT_CERTIFICATE *iCertificate,
const CRYPT_HANDLE iCertSource,
const CRYPT_KEYID_TYPE keyIDtype,
const void *keyID, const int keyIDlength,
const int options )
{
CRYPT_CERTIFICATE iCertChain[ MAX_CHAINLENGTH ], lastCert;
MESSAGE_KEYMGMT_INFO getnextcertInfo;
const int chainOptions = options & KEYMGMT_FLAG_DATAONLY_CERT;
int stateInfo = CRYPT_ERROR, certChainEnd = 1, status;
assert( isWritePtr( iCertificate, sizeof( CRYPT_CERTIFICATE ) ) );
assert( isHandleRangeValid( iCertSource ) );
assert( isReadPtr( keyID, keyIDlength ) && keyIDlength > 1 );
/* Get the initial cert based on the key ID */
setMessageKeymgmtInfo( &getnextcertInfo, keyIDtype, keyID, keyIDlength,
&stateInfo, sizeof( int ),
options & KEYMGMT_MASK_CERTOPTIONS );
status = krnlSendMessage( iCertSource, IMESSAGE_KEY_GETFIRSTCERT,
&getnextcertInfo, KEYMGMT_ITEM_PUBLICKEY );
if( cryptStatusError( status ) )
return( status );
iCertChain[ 0 ] = lastCert = getnextcertInfo.cryptHandle;
/* Fetch subsequent certs that make up the chain based on the state
information. Since the basic options apply only to the leaf cert,
we only allow the data-only-cert flag at this point */
setMessageKeymgmtInfo( &getnextcertInfo, CRYPT_KEYID_NONE, NULL, 0,
&stateInfo, sizeof( int ), chainOptions );
while( cryptStatusOK( status ) )
{
int selfSigned;
/* If we've reached a self-signed (CA root) cert, stop. Note that
this can't detect PKIX path-kludge certs, which look identical
to CA root certs and can only be reliably identified if they're
present in the middle of a pre-built chain */
status = krnlSendMessage( lastCert, IMESSAGE_GETATTRIBUTE,
&selfSigned, CRYPT_CERTINFO_SELFSIGNED );
if( cryptStatusError( status ) || selfSigned )
break;
/* Get the next cert in the chain from the source, import it, and
add it to the collection */
getnextcertInfo.cryptHandle = CRYPT_ERROR; /* Reset result handle */
status = krnlSendMessage( iCertSource, IMESSAGE_KEY_GETNEXTCERT,
&getnextcertInfo, KEYMGMT_ITEM_PUBLICKEY );
if( cryptStatusError( status ) )
break;
/* Make sure that we don't overflow the chain */
if( certChainEnd >= MAX_CHAINLENGTH )
{
krnlSendNotifier( getnextcertInfo.cryptHandle,
IMESSAGE_DECREFCOUNT );
status = CRYPT_ERROR_OVERFLOW;
break;
}
iCertChain[ certChainEnd++ ] = lastCert = getnextcertInfo.cryptHandle;
}
if( cryptStatusError( status ) && status != CRYPT_ERROR_NOTFOUND )
{
freeCertChain( iCertChain, certChainEnd );
return( status );
}
/* Build the complete chain from the individual certs */
return( buildCertChain( iCertificate, iCertChain, certChainEnd,
CRYPT_KEYID_NONE, NULL, 0 ) );
}
/****************************************************************************
* *
* Write Certificate-bagging Records *
* *
****************************************************************************/
/* Determine the size of and write a certificate path from a base cert up to
the root */
static int sizeofCertPath( const CERT_INFO *certInfoPtr,
int *certSizeInfo )
{
int length = 0, i;
/* Evaluate the size of the current certificate and the issuer
certificates in the chain. If it's a cert collection, it's just a
container for random certs but not a cert in its own right, so we
skip the leaf cert */
if( !( certInfoPtr->flags & CERT_FLAG_CERTCOLLECTION ) )
{
length = certInfoPtr->certificateSize;
if( certSizeInfo != NULL )
length += 3;
}
for( i = 0; i < certInfoPtr->cCertCert->chainEnd; i++ )
{
RESOURCE_DATA msgData;
int status;
setMessageData( &msgData, NULL, 0 );
status = krnlSendMessage( certInfoPtr->cCertCert->chain[ i ],
IMESSAGE_CRT_EXPORT, &msgData,
CRYPT_CERTFORMAT_CERTIFICATE );
if( cryptStatusError( status ) )
return( status );
length += msgData.length;
if( certSizeInfo != NULL )
{
certSizeInfo[ i ] = msgData.length;
length += 3;
}
}
return( length );
}
static int writeCertPath( STREAM *stream, const CERT_INFO *certInfoPtr,
int *certSizeInfo )
{
int i, status = CRYPT_OK;
/* Write the current certificate and the associated cert chain up to the
root. If it's a cert collection, it's just a container for random
certs but not a cert in its own right, so we skip the leaf cert */
if( !( certInfoPtr->flags & CERT_FLAG_CERTCOLLECTION ) )
{
if( certSizeInfo != NULL )
{
sputc( stream, 0 );
writeUint16( stream, certInfoPtr->certificateSize );
}
status = swrite( stream, certInfoPtr->certificate,
certInfoPtr->certificateSize );
}
for( i = 0; cryptStatusOK( status ) && \
i < certInfoPtr->cCertCert->chainEnd; i++ )
{
if( certSizeInfo != NULL )
{
sputc( stream, 0 );
writeUint16( stream, certSizeInfo[ i ] );
}
status = exportCertToStream( stream,
certInfoPtr->cCertCert->chain[ i ],
CRYPT_CERTTYPE_CERTIFICATE );
}
return( status );
}
/* Write certificate chain/sequence information:
CertChain ::= SEQUENCE {
contentType OBJECT IDENTIFIER, -- signedData
content [ 0 ] EXPLICIT SEQUENCE {
version INTEGER (1),
digestAlgorithms SET OF AlgorithmIdentifier, -- SIZE(0)
contentInfo SEQUENCE {
signedData OBJECT IDENTIFIER -- data
}
certificates [ 0 ] SET OF {
Certificate
}
}
signerInfos SET OF SignerInfo -- SIZE(0)
} */
int sizeofCertCollection( const CERT_INFO *certInfoPtr,
const CRYPT_CERTFORMAT_TYPE certFormatType )
{
assert( isReadPtr( certInfoPtr, sizeof( CERT_INFO ) ) );
assert( certFormatType == CRYPT_ICERTFORMAT_CERTSET || \
certFormatType == CRYPT_ICERTFORMAT_CERTSEQUENCE || \
certFormatType == CRYPT_ICERTFORMAT_SSL_CERTCHAIN );
if( certFormatType == CRYPT_ICERTFORMAT_SSL_CERTCHAIN )
{
int certSizeInfo[ MAX_CHAINLENGTH ];
return( sizeofCertPath( certInfoPtr, certSizeInfo ) );
}
return( sizeofObject( sizeofCertPath( certInfoPtr, NULL ) ) );
}
int writeCertCollection( STREAM *stream, const CERT_INFO *certInfoPtr,
const CRYPT_CERTFORMAT_TYPE certFormatType )
{
int certSizeInfo[ MAX_CHAINLENGTH ];
int *certSizePtr = \
( certFormatType == CRYPT_ICERTFORMAT_SSL_CERTCHAIN ) ? \
certSizeInfo : NULL;
const int certCollectionLength = sizeofCertPath( certInfoPtr, \
certSizePtr );
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( isReadPtr( certInfoPtr, sizeof( CERT_INFO ) ) );
assert( certFormatType == CRYPT_ICERTFORMAT_CERTSET || \
certFormatType == CRYPT_ICERTFORMAT_CERTSEQUENCE || \
certFormatType == CRYPT_ICERTFORMAT_SSL_CERTCHAIN );
if( cryptStatusError( certCollectionLength ) )
return( certCollectionLength );
switch( certFormatType )
{
case CRYPT_ICERTFORMAT_CERTSET:
writeConstructed( stream, certCollectionLength, 0 );
break;
case CRYPT_ICERTFORMAT_CERTSEQUENCE:
writeSequence( stream, certCollectionLength );
break;
case CRYPT_ICERTFORMAT_SSL_CERTCHAIN:
break;
default:
assert( NOTREACHED );
return( CRYPT_ERROR_NOTAVAIL );
}
return( writeCertPath( stream, certInfoPtr, certSizePtr ) );
}
int writeCertChain( STREAM *stream, const CERT_INFO *certInfoPtr )
{
const int certSetLength = sizeofCertPath( certInfoPtr, NULL );
int innerLength, status;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( isReadPtr( certInfoPtr, sizeof( CERT_INFO ) ) );
if( cryptStatusError( certSetLength ) )
return( certSetLength );
/* Determine how big the encoded cert chain/sequence will be */
innerLength = sizeofShortInteger( 1 ) + ( int ) sizeofObject( 0 ) + \
( int ) sizeofObject( sizeofOID( OID_CMS_DATA ) ) + \
( int ) sizeofObject( certSetLength ) + \
( int ) sizeofObject( 0 );
/* Write the outer SEQUENCE wrapper and contentType and content wrapper */
writeSequence( stream,
sizeofOID( OID_CMS_SIGNEDDATA ) + \
( int ) sizeofObject( sizeofObject( innerLength ) ) );
swrite( stream, OID_CMS_SIGNEDDATA, sizeofOID( OID_CMS_SIGNEDDATA ) );
writeConstructed( stream, sizeofObject( innerLength ), 0 );
writeSequence( stream, innerLength );
/* Write the inner content */
writeShortInteger( stream, 1, DEFAULT_TAG );
writeSet( stream, 0 );
writeSequence( stream, sizeofOID( OID_CMS_DATA ) );
swrite( stream, OID_CMS_DATA, sizeofOID( OID_CMS_DATA ) );
writeConstructed( stream, certSetLength, 0 );
status = writeCertPath( stream, certInfoPtr, NULL );
if( cryptStatusOK( status ) )
status = writeSet( stream, 0 );
return( status );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -