📄 certio.c
字号:
sMemDisconnect( &stream );
if( tag == BER_SEQUENCE || \
( tag >= MAKE_CTAG( 0 ) && tag <= MAKE_CTAG( 3 ) ) )
{
*objectType = CRYPT_CERTTYPE_OCSP_REQUEST;
return( CRYPT_OK );
}
if( tag == BER_OCTETSTRING )
{
*objectType = CRYPT_CERTTYPE_OCSP_RESPONSE;
return( CRYPT_OK );
}
/* It's nothing identifiable */
return( CRYPT_ERROR_BADDATA );
}
/****************************************************************************
* *
* Import/Export Functions *
* *
****************************************************************************/
/* Import a certificate object. If the import type is set to create a data-
only cert, its publicKeyInfo pointer is set to the start of the encoded
public key to allow it to be decoded later. Returns the length of the
certificate */
int importCert( const void *certObject, const int certObjectLength,
CRYPT_CERTIFICATE *certificate,
const CRYPT_USER cryptOwner,
const CRYPT_KEYID_TYPE keyIDtype,
const void *keyID, const int keyIDlength,
const CERTFORMAT_TYPE formatType )
{
CERT_INFO *certInfoPtr;
CRYPT_CERTTYPE_TYPE type;
STREAM stream;
int ( *readCertObjectFunction )( STREAM *stream, CERT_INFO *certInfoPtr );
void *certObjectPtr = ( void * ) certObject, *certBuffer;
int complianceLevel, length, offset = 0, initStatus = CRYPT_OK, i, status;
*certificate = CRYPT_ERROR;
/* Determine how much checking we need to perform */
status = krnlSendMessage( cryptOwner, IMESSAGE_GETATTRIBUTE,
&complianceLevel,
CRYPT_OPTION_CERT_COMPLIANCELEVEL );
if( cryptStatusError( status ) )
return( status );
/* If it's not a pre-specified or special-case format, check whether it's
some form of encoded certificate object */
if( formatType == CRYPT_CERTTYPE_NONE )
{
const CRYPT_CERTFORMAT_TYPE format = \
base64checkHeader( certObject, certObjectLength, &offset );
if( format == CRYPT_ICERTFORMAT_SMIME_CERTIFICATE || \
format == CRYPT_CERTFORMAT_TEXT_CERTIFICATE )
{
const char *certObjectDataPtr = \
( const char * ) certObject + offset;
int decodedLength;
/* It's base64/PEM/SMIME-encoded, decode it into a temporary
buffer */
decodedLength = base64decodeLen( certObjectDataPtr,
certObjectLength );
if( decodedLength <= 128 || decodedLength > 8192 )
return( CRYPT_ERROR_BADDATA );
if( ( certObjectPtr = clAlloc( "importCert",
decodedLength ) ) == NULL )
return( CRYPT_ERROR_MEMORY );
if( !base64decode( certObjectPtr, certObjectDataPtr, 0,
format ) )
{
clFree( "importCert", certObjectPtr );
return( CRYPT_ERROR_BADDATA );
}
}
}
/* Determine the object's type and length and check the encoding unless
we're running in oblivious mode */
status = getCertObjectInfo( certObjectPtr, certObjectLength, &offset,
&length, &type, formatType );
if( cryptStatusOK( status ) && \
complianceLevel > CRYPT_COMPLIANCELEVEL_OBLIVIOUS && \
formatType != CRYPT_ICERTTYPE_SSL_CERTCHAIN )
status = checkObjectEncoding( ( BYTE * ) certObjectPtr + offset,
length );
if( cryptStatusError( status ) )
{
if( certObjectPtr != certObject )
clFree( "importCert", certObjectPtr );
return( status );
}
status = CRYPT_OK; /* checkEncoding() returns a length */
/* If it's a cert chain, this is handled specially since we need to
import a plurality of certs at once */
if( type == CRYPT_CERTTYPE_CERTCHAIN || \
type == CRYPT_ICERTTYPE_CMS_CERTSET || \
type == CRYPT_ICERTTYPE_SSL_CERTCHAIN )
{
/* Read the cert chain into a collection of internal cert objects
This returns a handle to the leaf cert in the chain, with the
remaining certs being accessible within it via the cert cursor
functions. Because the different chain types are only used to
distinguish the chain wrapper type on import, the final object
type which is created is always a CRYPT_CERTTYPE_CERTCHAIN no
matter what the import format was */
sMemConnect( &stream, ( BYTE * ) certObjectPtr + offset, length );
if( type == CRYPT_CERTTYPE_CERTCHAIN )
readSequence( &stream, NULL ); /* Skip the outer wrapper */
status = readCertChain( &stream, certificate, cryptOwner, type,
keyIDtype, keyID, keyIDlength,
( formatType == CERTFORMAT_DATAONLY ||
formatType == CERTFORMAT_CTL ) ? \
TRUE : FALSE );
sMemDisconnect( &stream );
if( certObjectPtr != certObject )
clFree( "importCert", certObjectPtr );
return( status );
}
assert( keyIDtype == CRYPT_KEYID_NONE && keyID == NULL && \
keyIDlength == 0 );
/* Select the function to use to read the certificate object */
for( i = 0; certReadTable[ i ].type != type && \
certReadTable[ i ].type != CRYPT_CERTTYPE_NONE; i++ );
if( certReadTable[ i ].type == CRYPT_CERTTYPE_NONE || \
certReadTable[ i ].readFunction == NULL )
{
assert( NOTREACHED );
return( CRYPT_ERROR_NOTAVAIL );
}
readCertObjectFunction = certReadTable[ i ].readFunction;
/* Allocate a buffer to store a copy of the object so we can preserve the
original for when it's needed again later, and try and create the
certificate object. All the objects (including the CMS attributes,
that in theory aren't needed for anything further) need to be kept
around in their encoded form, which is often incorrect and therefore
can't be reconstructed from the decoded info. The readXXX() functions
record pointers to the required encoded fields so they can be
recovered later in their (possibly incorrect) form, and these pointers
need to be to a persistent copy of the encoded object. In addition the
cert objects need to be kept around anyway for sig checks and possible
re-export */
if( ( certBuffer = clAlloc( "importCert", length ) ) == NULL )
status = CRYPT_ERROR_MEMORY;
else
/* Create the certificate object */
status = createCertificateInfo( &certInfoPtr, cryptOwner, type );
if( cryptStatusError( status ) )
{
if( certObjectPtr != certObject )
clFree( "importCert", certObjectPtr );
clFree( "importCert", certBuffer );
return( status );
}
*certificate = status;
/* If we're doing a deferred read of the public key components (they'll
be decoded later when we know whether we need them), set the data-only
flag to ensure we don't try to decode them */
if( formatType == CERTFORMAT_DATAONLY || formatType == CERTFORMAT_CTL )
certInfoPtr->flags |= CERT_FLAG_DATAONLY;
/* If we're reading a single entry from a CRL, indicate that the
resulting object is a standalone single CRL entry rather than a proper
CRL */
if( formatType == CERTFORMAT_REVINFO )
certInfoPtr->flags |= CERT_FLAG_CRLENTRY;
/* Copy in the certificate object for later use */
memcpy( certBuffer, ( BYTE * ) certObjectPtr + offset, length );
certInfoPtr->certificate = certBuffer;
certInfoPtr->certificateSize = length;
/* Parse the object into the certificate. Note that we have to use the
copy in the certBuffer rather than the original since the readXXX()
functions record pointers to various encoded fields */
sMemConnect( &stream, certBuffer, length );
if( type != CRYPT_CERTTYPE_CMS_ATTRIBUTES && \
type != CRYPT_CERTTYPE_RTCS_REQUEST && \
type != CRYPT_CERTTYPE_RTCS_RESPONSE )
/* Skip the outer wrapper */
readLongSequence( &stream, NULL );
status = readCertObjectFunction( &stream, certInfoPtr );
sMemDisconnect( &stream );
if( certObjectPtr != certObject )
clFree( "importCert", certObjectPtr );
if( cryptStatusError( status ) )
{
/* The import failed, make sure that the object gets destroyed when
we notify the kernel that the setup process is complete. We also
have to explicitly destroy the attached context since at this
point it hasn't been associated with the certificate yet, so it
won't be automatically destroyed by the kernel when the cert is
destroyed */
krnlSendNotifier( *certificate, IMESSAGE_DESTROY );
if( certInfoPtr->iPubkeyContext != CRYPT_ERROR )
{
krnlSendNotifier( certInfoPtr->iPubkeyContext,
IMESSAGE_DECREFCOUNT );
certInfoPtr->iPubkeyContext = CRYPT_ERROR;
}
initStatus = status;
}
/* We've finished setting up the object-type-specific info, tell the
kernel that the object is ready for use */
status = krnlSendMessage( *certificate, IMESSAGE_SETATTRIBUTE,
MESSAGE_VALUE_OK, CRYPT_IATTRIBUTE_STATUS );
if( cryptStatusError( initStatus ) || cryptStatusError( status ) )
{
*certificate = CRYPT_ERROR;
return( cryptStatusError( initStatus ) ? initStatus : status );
}
/* If this is a type of object that has a public key associated with it,
notify the kernel that the given context is attached to the cert.
Note that we can only do this at this point because the cert object
can't receive general messages until its status is set to OK. In
addition since this is an internal object used only by the cert we
tell the kernel not to increment its reference count when it attaches
it to the cert object. Finally, we're ready to go so we mark the
object as initialised (we can't do this before the initialisation is
complete because the kernel won't forward the message to a not-ready-
for-use object)*/
if( certInfoPtr->iPubkeyContext != CRYPT_ERROR )
krnlSendMessage( *certificate, IMESSAGE_SETDEPENDENT,
&certInfoPtr->iPubkeyContext,
SETDEP_OPTION_NOINCREF );
return( krnlSendMessage( *certificate, IMESSAGE_SETATTRIBUTE,
MESSAGE_VALUE_UNUSED,
CRYPT_IATTRIBUTE_INITIALISED ) );
}
/* Export a certificate/certification request. This just writes the
internal encoded object to an external buffer. For cert/cert chain export
the possibilities are as follows:
Export
Type | Cert Chain
------+--------------------+---------------
Cert | Cert | Cert as chain
| |
Chain | Currently selected | Chain
| cert in chain | */
int exportCert( void *certObject, int *certObjectLength,
const CRYPT_CERTFORMAT_TYPE certFormatType,
const CERT_INFO *certInfoPtr, const int maxLength )
{
const CRYPT_CERTFORMAT_TYPE baseFormatType = \
( certFormatType == CRYPT_CERTFORMAT_TEXT_CERTIFICATE || \
certFormatType == CRYPT_CERTFORMAT_XML_CERTIFICATE ) ? \
CRYPT_CERTFORMAT_CERTIFICATE : \
( certFormatType == CRYPT_CERTFORMAT_TEXT_CERTCHAIN || \
certFormatType == CRYPT_CERTFORMAT_XML_CERTCHAIN ) ? \
CRYPT_CERTFORMAT_CERTCHAIN : \
certFormatType;
STREAM stream;
void *buffer;
int length, encodedLength, status;
/* If it's an internal format, write it and exit */
if( certFormatType == CRYPT_ICERTFORMAT_CERTSET || \
certFormatType == CRYPT_ICERTFORMAT_CERTSEQUENCE )
{
*certObjectLength = ( int ) sizeofCertSet( certInfoPtr );
if( certObject == NULL )
return( CRYPT_OK );
if( *certObjectLength > maxLength )
return( CRYPT_ERROR_OVERFLOW );
sMemOpen( &stream, certObject, *certObjectLength );
if( certFormatType == CRYPT_ICERTFORMAT_CERTSET )
status = writeCertSet( &stream, certInfoPtr );
else
status = writeCertSequence( &stream, certInfoPtr );
sMemDisconnect( &stream );
return( status );
}
/* Determine how big the output object will be */
if( baseFormatType == CRYPT_CERTFORMAT_CERTCHAIN )
{
STREAM nullStream;
assert( certInfoPtr->type == CRYPT_CERTTYPE_CERTIFICATE || \
certInfoPtr->type == CRYPT_CERTTYPE_CERTCHAIN );
sMemOpen( &nullStream, NULL, 0 );
status = writeCertChain( &nullStream, certInfoPtr );
length = stell( &nullStream );
sMemClose( &nullStream );
if( cryptStatusError( status ) )
return( status );
}
else
length = certInfoPtr->certificateSize;
encodedLength = ( baseFormatType != certFormatType ) ? \
base64encodeLen( length, certInfoPtr->type ) : length;
/* Set up the length information */
*certObjectLength = encodedLength;
if( certObject == NULL )
return( CRYPT_OK );
if( encodedLength > maxLength )
return( CRYPT_ERROR_OVERFLOW );
if( checkBadPtrWrite( certObject, encodedLength ) )
return( CRYPT_ARGERROR_STR1 );
/* If it's a simple object, write either the DER-encoded object or its
base64 / S/MIME-encoded form directly to the output */
if( certFormatType == CRYPT_CERTFORMAT_CERTIFICATE || \
certFormatType == CRYPT_ICERTFORMAT_DATA )
{
memcpy( certObject, certInfoPtr->certificate, length );
return( CRYPT_OK );
}
if( certFormatType == CRYPT_CERTFORMAT_TEXT_CERTIFICATE || \
certFormatType == CRYPT_CERTFORMAT_XML_CERTIFICATE )
{
base64encode( certObject, certInfoPtr->certificate,
certInfoPtr->certificateSize, certInfoPtr->type );
return( CRYPT_OK );
}
/* It's a straight cert chain, write it directly to the output */
if( certFormatType == CRYPT_CERTFORMAT_CERTCHAIN )
{
sMemOpen( &stream, certObject, length );
status = writeCertChain( &stream, certInfoPtr );
sMemDisconnect( &stream );
return( status );
}
/* It's a base64 / S/MIME-encoded cert chain, write it to a temporary
buffer and then encode it to the output */
assert( certFormatType == CRYPT_CERTFORMAT_TEXT_CERTCHAIN || \
certFormatType == CRYPT_CERTFORMAT_XML_CERTCHAIN );
if( ( buffer = clAlloc( "exportCert", length ) ) == NULL )
return( CRYPT_ERROR_MEMORY );
sMemOpen( &stream, buffer, length );
status = writeCertChain( &stream, certInfoPtr );
if( cryptStatusOK( status ) )
base64encode( certObject, buffer, length, CRYPT_CERTTYPE_CERTCHAIN );
sMemClose( &stream );
clFree( "exportCert", buffer );
return( status );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -