📄 certio.c
字号:
CERT_INFO *certInfoPtr;
CRYPT_CERTFORMAT_TYPE format = CRYPT_CERTFORMAT_NONE;
CRYPT_CERTTYPE_TYPE type;
STREAM stream;
int ( *readCertObjectFunction )( STREAM *stream, CERT_INFO *certInfoPtr );
void *certObjectPtr = ( void * ) certObject, *certBuffer;
int length, offset, initStatus = CRYPT_OK, status;
*certificate = CRYPT_ERROR;
/* If it's not a special-case format, check whether it's an S/MIME or
base64-encoded certificate object */
if( formatType == CERTFORMAT_NORMAL )
{
if( ( length = smimeCheckHeader( certObject,
certObjectLength ) ) != 0 )
format = CRYPT_ICERTFORMAT_SMIME_CERTIFICATE;
else
if( ( length = base64checkHeader( certObject,
certObjectLength ) ) != 0 )
format = CRYPT_CERTFORMAT_TEXT_CERTIFICATE;
if( length )
{
int decodedLength;
/* It's base64 / S/MIME-encoded, decode it into a temporary
buffer */
decodedLength = base64decodeLen( ( const char * ) certObject + length,
certObjectLength );
if( decodedLength <= 128 || decodedLength > 8192 )
return( CRYPT_ERROR_BADDATA );
if( ( certObjectPtr = malloc( decodedLength ) ) == NULL )
return( CRYPT_ERROR_MEMORY );
if( !base64decode( certObjectPtr, ( const char * ) certObject +
length, 0, format ) )
{
free( certObjectPtr );
return( CRYPT_ERROR_BADDATA );
}
}
}
/* Check the object to determine its type and length, and check the
encoding if necessary */
status = getCertObjectInfo( certObjectPtr, certObjectLength, &offset,
&length, &type, formatType );
if( !cryptStatusError( status ) && formatType != CERTFORMAT_SSLCHAIN )
status = checkObjectEncoding( ( BYTE * ) certObjectPtr + offset,
length );
if( cryptStatusError( status ) )
{
if( certObjectPtr != certObject )
free( 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_CERTTYPE_CMS_CERTSET || \
type == CRYPT_CERTTYPE_SSL_CERTCHAIN )
{
/* Read the cert chain into a collection of internal cert resources.
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 ) ? \
TRUE : FALSE );
sMemDisconnect( &stream );
if( certObjectPtr != certObject )
free( certObjectPtr );
if( cryptStatusError( status ) )
return( status );
return( length );
}
/* Select the function to use to read the certificate object */
switch( type )
{
case CRYPT_CERTTYPE_CERTIFICATE:
readCertObjectFunction = readCertInfo;
break;
case CRYPT_CERTTYPE_ATTRIBUTE_CERT:
readCertObjectFunction = readAttributeCertInfo;
break;
case CRYPT_CERTTYPE_CERTREQUEST:
readCertObjectFunction = readCertRequestInfo;
break;
case CRYPT_CERTTYPE_REQUEST_CERT:
readCertObjectFunction = readCRMFRequestInfo;
break;
case CRYPT_CERTTYPE_REQUEST_REVOCATION:
readCertObjectFunction = readRevRequestInfo;
break;
case CRYPT_CERTTYPE_CRL:
readCertObjectFunction = readCRLInfo;
break;
case CRYPT_CERTTYPE_CMS_ATTRIBUTES:
readCertObjectFunction = readCMSAttributes;
break;
case CRYPT_CERTTYPE_OCSP_RESPONSE:
readCertObjectFunction = readOCSPResponseInfo;
break;
case CRYPT_CERTTYPE_OCSP_REQUEST:
readCertObjectFunction = readOCSPRequestInfo;
break;
case CRYPT_CERTTYPE_PKIUSER:
readCertObjectFunction = readPKIUserInfo;
break;
default:
assert( NOTREACHED );
}
/* 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,
which 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. The readXXX() function 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 = malloc( length ) ) == NULL )
status = CRYPT_ERROR_MEMORY;
if( cryptStatusOK( status ) )
/* Create the certificate object */
status = createCertificateInfo( &certInfoPtr, cryptOwner, type );
if( cryptStatusError( status ) )
{
if( certObjectPtr != certObject )
free( certObjectPtr );
free( 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 )
certInfoPtr->flags |= CERT_FLAG_DATAONLY;
/* 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 )
readSequence( &stream, NULL ); /* Skip the outer wrapper */
status = readCertObjectFunction( &stream, certInfoPtr );
sMemDisconnect( &stream );
if( certObjectPtr != certObject )
free( certObjectPtr );
if( cryptStatusError( status ) )
{
/* The import failed, make sure the object gets destroyed when we
notify the kernel that the setup process is complete */
krnlSendNotifier( *certificate, RESOURCE_IMESSAGE_DESTROY );
initStatus = status;
}
/* We've finished setting up the object-type-specific info, tell the
kernel the object is ready for use */
unlockResource( certInfoPtr );
status = krnlSendMessage( *certificate, RESOURCE_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 which 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. 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->iCryptContext != CRYPT_ERROR )
krnlSendMessage( *certificate, RESOURCE_IMESSAGE_SETDEPENDENT,
&certInfoPtr->iCryptContext,
SETDEP_OPTION_NOINCREF );
krnlSendMessage( *certificate, RESOURCE_IMESSAGE_SETATTRIBUTE,
MESSAGE_VALUE_UNUSED, CRYPT_IATTRIBUTE_INITIALISED );
return( length );
}
/* 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 )
{
/* If it's a binary format, the base format is the actual format type.
If it's a text (base64) format, the base format is given by subtracting
the difference between the text and binary formats */
const CRYPT_CERTFORMAT_TYPE baseFormatType = \
( certFormatType < CRYPT_CERTFORMAT_TEXT_CERTIFICATE ) ? \
certFormatType :
certFormatType - ( CRYPT_CERTFORMAT_TEXT_CERTIFICATE - 1 );
STREAM stream;
void *buffer;
int length, encodedLength, status;
/* Determine how big the output object will be */
if( baseFormatType == CRYPT_CERTFORMAT_CERTCHAIN )
{
STREAM nullStream;
int status;
assert( certInfoPtr->type == CRYPT_CERTTYPE_CERTIFICATE || \
certInfoPtr->type == CRYPT_CERTTYPE_CERTCHAIN );
sMemOpen( &nullStream, NULL, 0 );
status = writeCertChain( &nullStream, certInfoPtr );
length = ( int ) stell( &nullStream );
sMemClose( &nullStream );
if( cryptStatusError( status ) )
return( status );
}
else
length = certInfoPtr->certificateSize;
encodedLength = ( certFormatType >= CRYPT_CERTFORMAT_TEXT_CERTIFICATE ) ? \
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 )
{
memcpy( certObject, certInfoPtr->certificate, length );
return( CRYPT_OK );
}
if( certFormatType == CRYPT_CERTFORMAT_TEXT_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 );
if( ( buffer = malloc( 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 );
free( buffer );
return( status );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -