📄 chain.c
字号:
CRYPT_ICERTTYPE_DATAONLY : \
CRYPT_CERTTYPE_CERTIFICATE );
}
if( cryptStatusOK( status ) )
{
MESSAGE_DATA msgData;
/* Add the newly-read certificate 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 certificate 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;
}
}
}
ENSURES( iterationCount < FAILSAFE_ITERATIONS_MED );
/* We must have read at least one certificate in order to create a
chain */
if( certChainEnd <= 0 )
return( CRYPT_ERROR_BADDATA );
/* Build the complete chain from the individual certificates */
return( buildCertChain( iCryptCert, iCertChain, certChainEnd,
keyIDtype, keyID, keyIDlength ) );
}
/* Fetch a sequence of certificates from an object to create a certificate
chain */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 4 ) ) \
int assembleCertChain( OUT CRYPT_CERTIFICATE *iCertificate,
IN_HANDLE const CRYPT_HANDLE iCertSource,
IN_KEYID const CRYPT_KEYID_TYPE keyIDtype,
IN_BUFFER( keyIDlength ) const void *keyID,
IN_LENGTH_KEYID const int keyIDlength,
IN_FLAGS( KEYMGMT ) const int options )
{
CRYPT_CERTIFICATE iCertChain[ MAX_CHAINLENGTH + 8 ], lastCert;
MESSAGE_KEYMGMT_INFO getnextcertInfo;
const int chainOptions = options & KEYMGMT_FLAG_DATAONLY_CERT;
int stateInfo = CRYPT_ERROR, certChainEnd = 1;
int iterationCount, status;
assert( isWritePtr( iCertificate, sizeof( CRYPT_CERTIFICATE ) ) );
assert( isReadPtr( keyID, keyIDlength ) && \
keyIDlength >= MIN_NAME_LENGTH );
REQUIRES( isHandleRangeValid( iCertSource ) );
REQUIRES( keyIDtype > CRYPT_KEYID_NONE && \
keyIDtype < CRYPT_KEYID_LAST );
REQUIRES( keyIDlength >= MIN_NAME_LENGTH && \
keyIDlength < MAX_ATTRIBUTE_SIZE );
REQUIRES( options >= KEYMGMT_FLAG_NONE && options < KEYMGMT_FLAG_MAX && \
( options & ~KEYMGMT_MASK_CERTOPTIONS ) == 0 );
/* Get the initial certificate 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 certificates that make up the chain based on the
state information. Since the basic options apply only to the leaf
certificate we only allow the data-only-cert flag at this point. See
the comment in readCertChain() for the use of FAILSAFE_ITERATIONS_MED
for the bounds check */
setMessageKeymgmtInfo( &getnextcertInfo, CRYPT_KEYID_NONE, NULL, 0,
&stateInfo, sizeof( int ), chainOptions );
for( iterationCount = 0;
cryptStatusOK( status ) && \
iterationCount < FAILSAFE_ITERATIONS_MED;
iterationCount++ )
{
int selfSigned;
/* If we've reached a self-signed (CA root) certificate, stop. Note
that this can't detect PKIX path-kludge certificates which look
identical to CA root certificates 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 > 0 )
break;
/* Get the next certificate 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;
}
ENSURES( iterationCount < FAILSAFE_ITERATIONS_MED );
if( cryptStatusError( status ) && status != CRYPT_ERROR_NOTFOUND )
{
freeCertChain( iCertChain, certChainEnd );
return( status );
}
/* Build the complete chain from the individual certificates */
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
certificate up to the root */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
static int sizeofCertPath( const CERT_INFO *certInfoPtr,
OUT_ARRAY_OPT( MAX_CHAINLENGTH ) int *certSizeInfo )
{
int length = 0, i;
assert( isReadPtr( certInfoPtr, sizeof( CERT_INFO ) ) );
assert( certSizeInfo == NULL || \
isWritePtr( certSizeInfo, sizeof( int ) * MAX_CHAINLENGTH ) );
/* Clear return value */
if( certSizeInfo != NULL )
memset( certSizeInfo, 0, sizeof( int ) * MAX_CHAINLENGTH );
/* Evaluate the size of the current certificate and the issuer
certificates in the chain. If it's a certificate collection it's
just a container for random certificates but not a certificate in its
own right so we skip the leaf certificate */
if( !( certInfoPtr->flags & CERT_FLAG_CERTCOLLECTION ) )
{
length = certInfoPtr->certificateSize;
if( certSizeInfo != NULL )
length += 3;
}
for( i = 0; i < certInfoPtr->cCertCert->chainEnd && \
i < MAX_CHAINLENGTH; i++ )
{
MESSAGE_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;
}
}
ENSURES( i < MAX_CHAINLENGTH );
return( length );
}
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
static int writeCertPath( INOUT STREAM *stream,
const CERT_INFO *certInfoPtr,
IN_ARRAY_OPT( MAX_CHAINLENGTH ) \
const int *certSizeInfo )
{
int i, status = CRYPT_OK;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( isReadPtr( certInfoPtr, sizeof( CERT_INFO ) ) );
assert( certSizeInfo == NULL || \
isReadPtr( certSizeInfo, sizeof( int ) * MAX_CHAINLENGTH ) );
/* Write the current certificate and the associated certificate chain up
to the root. If it's a certificate collection it's just a container
for random certificates but not a certificate in its own right so we
skip the leaf certificate */
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 < MAX_CHAINLENGTH; i++ )
{
if( certSizeInfo != NULL )
{
sputc( stream, 0 );
writeUint16( stream, certSizeInfo[ i ] );
}
status = exportCertToStream( stream,
certInfoPtr->cCertCert->chain[ i ],
CRYPT_CERTFORMAT_CERTIFICATE );
}
ENSURES( i < MAX_CHAINLENGTH );
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)
} */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
int sizeofCertCollection( const CERT_INFO *certInfoPtr,
IN_ENUM( CRYPT_CERTFORMAT ) \
const CRYPT_CERTFORMAT_TYPE certFormatType )
{
assert( isReadPtr( certInfoPtr, sizeof( CERT_INFO ) ) );
REQUIRES( certFormatType == CRYPT_ICERTFORMAT_CERTSET || \
certFormatType == CRYPT_ICERTFORMAT_CERTSEQUENCE || \
certFormatType == CRYPT_ICERTFORMAT_SSL_CERTCHAIN );
if( certFormatType == CRYPT_ICERTFORMAT_SSL_CERTCHAIN )
{
int certSizeInfo[ MAX_CHAINLENGTH + 8 ];
return( sizeofCertPath( certInfoPtr, certSizeInfo ) );
}
return( sizeofObject( sizeofCertPath( certInfoPtr, NULL ) ) );
}
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
int writeCertCollection( INOUT STREAM *stream,
const CERT_INFO *certInfoPtr,
IN_ENUM( CRYPT_CERTFORMAT ) \
const CRYPT_CERTFORMAT_TYPE certFormatType )
{
int certSizeInfo[ MAX_CHAINLENGTH + 8 ];
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 ) ) );
REQUIRES( 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:
retIntError();
}
return( writeCertPath( stream, certInfoPtr, certSizePtr ) );
}
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
int writeCertChain( INOUT 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 certificate 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 + -