📄 imp_exp.c
字号:
/* If we've hit a [1] it's an attribute certificate, if we've hit a
GeneralizedTime it's an OCSP response, if we've hit a SET it's PKI
user info, and if we've hit a [0] or [1] primitive tag (implicitly
tagged INTEGER) or [3]...[9] it's a CRMF revocation request */
tag = peekTag( &stream );
if( cryptStatusError( tag ) )
return( tag );
if( tag == MAKE_CTAG( 1 ) || tag == BER_TIME_GENERALIZED || \
tag == BER_SET )
{
sMemDisconnect( &stream );
*objectType = \
( tag == MAKE_CTAG( 1 ) ) ? CRYPT_CERTTYPE_ATTRIBUTE_CERT : \
( tag == BER_TIME_GENERALIZED ) ? \
CRYPT_CERTTYPE_OCSP_RESPONSE : CRYPT_CERTTYPE_PKIUSER;
return( isLongData ? CRYPT_ERROR_OVERFLOW : CRYPT_OK );
}
if( tag == MAKE_CTAG_PRIMITIVE( 0 ) || \
tag == MAKE_CTAG_PRIMITIVE( 1 ) || \
( tag >= MAKE_CTAG( 3 ) && tag <= MAKE_CTAG( 9 ) ) )
{
sMemDisconnect( &stream );
*objectType = CRYPT_CERTTYPE_REQUEST_REVOCATION;
return( isLongData ? CRYPT_ERROR_OVERFLOW : CRYPT_OK );
}
/* Read the next SEQUENCE. If it's followed by an OID it's the
AlgorithmIdentifier in a certificate or CRL. If it's followed by a
SET it's the Name in a certificate request or attribute certificate.
If it's followed by a tag in the range [0]...[9] it's a horror from
CRMF */
status = readSequence( &stream, &length );
if( cryptStatusOK( status ) && length <= 0 )
status = CRYPT_ERROR_BADDATA;
if( cryptStatusError( status ) )
{
sMemDisconnect( &stream );
return( status );
}
tag = peekTag( &stream );
if( cryptStatusError( tag ) )
return( tag );
if( tag == BER_OBJECT_IDENTIFIER )
{
/* Skip the AlgorithmIdentifier data and the following Name. For a
certificate we now have a SEQUENCE (from the Validity), for a CRL
a UTCTime or GeneralizedTime */
sSkip( &stream, length );
readUniversal( &stream );
tag = readTag( &stream );
sMemDisconnect( &stream );
if( cryptStatusError( tag ) )
return( tag );
if( tag == BER_SEQUENCE )
{
*objectType = CRYPT_CERTTYPE_CERTIFICATE;
return( isLongData ? CRYPT_ERROR_OVERFLOW : CRYPT_OK );
}
if( tag == BER_TIME_UTC || tag == BER_TIME_GENERALIZED )
{
*objectType = CRYPT_CERTTYPE_CRL;
return( CRYPT_OK );
}
return( CRYPT_ERROR_BADDATA );
}
if( isLongData )
{
/* Beyond this point we shouldn't be seeing long-length objects */
return( CRYPT_ERROR_OVERFLOW );
}
if( tag >= MAKE_CTAG( 0 ) && tag <= MAKE_CTAG( 9 ) )
{
/* Certificate requests and revocation requests have the same
format, however revocation requests should have the certificate
serial number present while certificate requests shouldn't (at
least in any normal implementation) so we use this to
distinguish the two. If this ever fails in the future we can
also look for things like [6] (the public key) as a clue that
it's a certificate request */
sMemDisconnect( &stream );
*objectType = ( tag == MAKE_CTAG( 1 ) ) ? \
CRYPT_CERTTYPE_REQUEST_REVOCATION : CRYPT_CERTTYPE_REQUEST_CERT;
return( CRYPT_OK );
}
if( tag == BER_SET )
{
sSkip( &stream, length );
readSequence( &stream, NULL );
tag = readTag( &stream );
sMemDisconnect( &stream );
if( cryptStatusError( tag ) )
return( tag );
if( tag == BER_OBJECT_IDENTIFIER )
{
*objectType = CRYPT_CERTTYPE_ATTRIBUTE_CERT;
return( CRYPT_OK );
}
if( tag == BER_SEQUENCE )
{
*objectType = CRYPT_CERTTYPE_CERTREQUEST;
return( CRYPT_OK );
}
return( CRYPT_ERROR_BADDATA );
}
/* Read the next SEQUENCE. If it's followed by a yet another SEQUENCE
or a tag from [0] ... [3] it's an OCSP request, if it's followed by
an OCTET STRING it's a cryptlib OCSP response */
readSequence( &stream, NULL );
tag = readTag( &stream );
sMemDisconnect( &stream );
if( cryptStatusError( tag ) )
return( tag );
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 );
}
/* Decode a base64/PEM/SMIME-encoded certificate into a temporary buffer */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3, 4 ) ) \
static int decodeCertificate( IN_BUFFER( certObjectLength ) const void *certObject,
IN_LENGTH const int certObjectLength,
OUT_PTR void **newObject,
OUT_LENGTH_Z int *newObjectLength,
IN_ENUM( CRYPT_CERTFORMAT ) \
const CRYPT_CERTFORMAT_TYPE format )
{
void *decodedObjectPtr;
int decodedLength, status;
assert( isReadPtr( certObject, certObjectLength ) );
assert( isWritePtr( newObject, sizeof( void * ) ) );
assert( isWritePtr( newObjectLength, sizeof( int ) ) );
REQUIRES( certObjectLength > 0 && certObjectLength < MAX_INTLENGTH );
REQUIRES( format > CRYPT_CERTFORMAT_NONE && \
format < CRYPT_CERTFORMAT_LAST );
/* Clear return values */
*newObject = NULL;
*newObjectLength = 0;
/* Decode the base64/PEM/SMIME-encoded certificate into a temporary
buffer */
status = base64decodeLen( certObject, certObjectLength,
&decodedLength );
if( cryptStatusError( status ) )
return( status );
if( decodedLength < 64 || decodedLength >= MAX_INTLENGTH_SHORT )
return( CRYPT_ERROR_UNDERFLOW );
if( ( decodedObjectPtr = clAlloc( "checkTextEncoding", \
decodedLength + 8 ) ) == NULL )
return( CRYPT_ERROR_MEMORY );
status = base64decode( decodedObjectPtr, decodedLength, &decodedLength,
certObject, certObjectLength, format );
if( cryptStatusOK( status ) && \
( decodedLength < 64 || decodedLength >= MAX_INTLENGTH_SHORT ) )
status = CRYPT_ERROR_BADDATA;
if( cryptStatusError( status ) )
{
clFree( "checkTextEncoding", decodedObjectPtr );
return( status );
}
*newObject = decodedObjectPtr;
*newObjectLength = decodedLength;
return( CRYPT_OK );
}
/* Detect the encoded form of certificate data, either raw binary, raw
binary with a MIME header, or some form of text encoding. Autodetection
in the presence of EBCDIC gets a bit more complicated because the text
content can potentially be either EBCDIC or ASCII so we have to add an
extra layer of checking for EBCDIC */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3, 4 ) ) \
static int checkTextEncoding( IN_BUFFER( certObjectLength ) const void *certObject,
IN_LENGTH const int certObjectLength,
OUT_PTR void **newObject,
OUT_LENGTH int *newObjectLength )
{
CRYPT_CERTFORMAT_TYPE format;
#ifdef EBCDIC_CHARS
void *asciiObject = NULL;
#endif /* EBCDIC_CHARS */
int offset, status;
assert( isReadPtr( certObject, certObjectLength ) );
assert( isWritePtr( newObject, sizeof( void * ) ) );
assert( isWritePtr( newObjectLength, sizeof( int ) ) );
REQUIRES( certObjectLength > 0 && certObjectLength < MAX_INTLENGTH );
/* Initialise the return values to the default settings, the identity
transformation */
*newObject = ( void * ) certObject;
*newObjectLength = certObjectLength;
/* Check for a header that identifies some form of encoded object */
status = base64checkHeader( certObject, certObjectLength, &format, &offset );
#ifdef EBCDIC_CHARS
if( cryptStatusError( status ) )
{
int status;
/* If we get a decoding error (i.e. it's not either an unencoded
object or some form of ASCII encoded object) try again assuming
that the source is EBCDIC */
if( ( asciiObject = clAlloc( "checkTextEncoding",
certObjectLength + 8 ) ) == NULL )
return( CRYPT_ERROR_MEMORY );
status = ebcdicToAscii( asciiObject, certObject, certObjectLength );
if( cryptStatusError( status ) )
return( status );
certObject = asciiObject;
status = base64checkHeader( certObject, certObjectLength, &format,
&offset );
if( cryptStatusOK( status ) && \
( format != CRYPT_ICERTFORMAT_SMIME_CERTIFICATE && \
format != CRYPT_CERTFORMAT_TEXT_CERTIFICATE ) )
{
clFree( "checkTextEncoding", asciiObject );
asciiObject = NULL;
}
}
#endif /* EBCDIC_CHARS */
if( cryptStatusError( status ) )
return( status );
/* Make sure that the length after (potentially) skipping the header is
still valid, since this will now be different from the length that
was validated by the kernel */
if( certObjectLength - offset < 64 || \
certObjectLength - offset > MAX_INTLENGTH )
{
#ifdef EBCDIC_CHARS
if( asciiObject != NULL )
clFree( "checkTextEncoding", asciiObject );
#endif /* EBCDIC_CHARS */
return( CRYPT_ERROR_UNDERFLOW );
}
if( format == CRYPT_ICERTFORMAT_SMIME_CERTIFICATE || \
format == CRYPT_CERTFORMAT_TEXT_CERTIFICATE )
{
status = decodeCertificate( ( const char * ) certObject + offset,
certObjectLength - offset, newObject,
newObjectLength, format );
#ifdef EBCDIC_CHARS
if( asciiObject != NULL )
clFree( "checkTextEncoding", asciiObject );
#endif /* EBCDIC_CHARS */
if( cryptStatusError( status ) )
return( status );
/* Let the caller know that they have to free the temporary decoding
buffer before they exit */
return( OK_SPECIAL );
}
/* If it's binary-encoded MIME data we don't need to decode it but still
need to skip the MIME header */
if( format == CRYPT_CERTFORMAT_CERTIFICATE || \
format == CRYPT_CERTFORMAT_CERTCHAIN )
{
assert( offset > 0 );
*newObject = ( BYTE * ) certObject + offset;
*newObjectLength -= offset;
}
return( CRYPT_OK );
}
/****************************************************************************
* *
* Import/Export Functions *
* *
****************************************************************************/
/* Import a certificate object. If the import type is set to create a data-
only certificate, 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 */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3 ) ) \
int importCert( IN_BUFFER( certObjectLength ) const void *certObject,
IN_LENGTH const int certObjectLength,
OUT_HANDLE_OPT CRYPT_CERTIFICATE *certificate,
IN_HANDLE const CRYPT_USER iCryptOwner,
IN_KEYID const CRYPT_KEYID_TYPE keyIDtype,
IN_BUFFER_OPT( keyIDlength ) const void *keyID,
IN_LENGTH_KEYID_Z const int keyIDlength,
IN_ENUM_OPT( CRYPT_CERTTYPE ) \
const CRYPT_CERTTYPE_TYPE formatHint )
{
CERT_INFO *certInfoPtr;
CRYPT_CERTTYPE_TYPE type;
STREAM stream;
READCERT_FUNCTION readCertFunction;
BOOLEAN isDecodedObject = FALSE;
void *certObjectPtr = ( void * ) certObject, *certBuffer;
int objectLength = certObjectLength, length, offset = 0;
int complianceLevel, initStatus = CRYPT_OK, status;
assert( isReadPtr( certObject, certObjectLength ) );
assert( isWritePtr( certificate, sizeof( CRYPT_CERTIFICATE ) ) );
assert( ( keyIDtype == CRYPT_KEYID_NONE && \
keyID == NULL && keyIDlength == 0 ) || \
( keyIDtype != CRYPT_KEYID_NONE && \
isReadPtr( keyID, keyIDlength ) ) );
REQUIRES( certObjectLength > 0 && certObjectLength < MAX_INTLENGTH );
REQUIRES( iCryptOwner == DEFAULTUSER_OBJECT_HANDLE || \
isHandleRangeValid( iCryptOwner ) );
REQUIRES( ( keyIDtype == CRYPT_KEYID_NONE && \
keyID == NULL && keyIDlength == 0 ) || \
( ( keyIDtype > CRYPT_KEYID_NONE && \
keyIDtype < CRYPT_KEYID_LAST ) && \
keyID != NULL && \
keyIDlength >= MIN_NAME_LENGTH && \
keyIDlength < MAX_ATTRIBUTE_SIZE ) );
REQUIRES( formatHint >= CRYPT_CERTTYPE_NONE && \
formatHint < CRYPT_CERTTYPE_LAST );
/* Clear return value */
*certificate = CRYPT_ERROR;
/* Determine how much checking we need to perform */
status = krnlSendMessage( iCryptOwner, IMESSAGE_GETATTRIBUTE,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -