📄 asn1_ext.c
字号:
RESOURCE_DATA msgData;
setMessageData( &msgData, queryInfoPtr->iv,
min( ivLength, queryInfoPtr->ivLength ) );
status = krnlSendMessage( createInfo.cryptHandle,
IMESSAGE_SETATTRIBUTE_S, &msgData,
CRYPT_CTXINFO_IV );
}
}
if( cryptStatusError( status ) )
{
/* If there's an error in the parameters stored with the key we'll
get an arg or attribute error when we try to set the attribute so
we translate it into an error code which is appropriate for the
situation. In addition since this is (arguably) a stream format
error (the data read from the stream is invalid), we also set the
stream status */
krnlSendNotifier( createInfo.cryptHandle, IMESSAGE_DECREFCOUNT );
if( cryptArgError( status ) )
{
sSetError( stream, CRYPT_ERROR_BADDATA );
status = CRYPT_ERROR_BADDATA;
}
}
else
*iCryptContext = createInfo.cryptHandle;
return( status );
}
/****************************************************************************
* *
* Message Digest Routines *
* *
****************************************************************************/
/* Read/write a message digest value. This is another one of those oddball
functions which is present here because it's the least inappropriate place
to put it */
int writeMessageDigest( STREAM *stream, const CRYPT_ALGO_TYPE hashAlgo,
const void *hash, const int hashSize )
{
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( hashAlgo >= CRYPT_ALGO_FIRST_HASH && \
hashAlgo <= CRYPT_ALGO_LAST_HASH );
assert( isReadPtr( hash, hashSize ) );
writeSequence( stream, sizeofAlgoID( hashAlgo ) + \
( int ) sizeofObject( hashSize ) );
writeAlgoID( stream, hashAlgo );
return( writeOctetString( stream, hash, hashSize, DEFAULT_TAG ) );
}
int readMessageDigest( STREAM *stream, CRYPT_ALGO_TYPE *hashAlgo, void *hash,
int *hashSize )
{
int status;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( isWritePtr( hash, 16 ) );
assert( isWritePtr( hashSize, sizeof( int ) ) );
/* Clear the return values */
memset( hash, 0, 16 );
*hashSize = 0;
/* Read the message digest, enforcing sensible size values */
readSequence( stream, NULL );
status = readAlgoID( stream, hashAlgo );
if( cryptStatusError( status ) )
return( status );
status = readOctetString( stream, hash, hashSize, CRYPT_MAX_HASHSIZE );
if( cryptStatusOK( status ) && \
( *hashSize < 16 || *hashSize > CRYPT_MAX_HASHSIZE ) )
{
sSetError( stream, CRYPT_ERROR_BADDATA );
status = CRYPT_ERROR_BADDATA;
}
return( status );
}
/****************************************************************************
* *
* CMS Header Routines *
* *
****************************************************************************/
/* Read and write CMS headers. When reading CMS headers we check a bit more
than just the header OID, which means that we need to provide additional
information alongside the OID information. This is provided as
CMS_CONTENT_INFO in the OID info extra data field */
int readCMSheader( STREAM *stream, const OID_INFO *oidInfo, long *dataSize,
const BOOLEAN isInnerHeader )
{
const OID_INFO *oidInfoPtr;
BOOLEAN isData = FALSE;
long length, value;
int tag, status;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( isReadPtr( oidInfo, sizeof( OID_INFO ) ) );
assert( dataSize == NULL || isWritePtr( dataSize, sizeof( long ) ) );
/* Clear the return value */
if( dataSize != NULL )
*dataSize = 0;
/* Read the outer SEQUENCE and OID. We can't use a normal
readSequence() here because the data length could be much longer than
the maximum allowed in the readSequence() sanity check */
readLongSequence( stream, &length );
status = readOIDEx( stream, oidInfo, &oidInfoPtr );
if( cryptStatusError( status ) )
return( status );
/* If the content type is data, the content is an OCTET STRING rather
than a SEQUENCE so we remember the type for later */
if( sizeofOID( oidInfoPtr->oid ) == sizeofOID( OID_CMS_DATA ) && \
!memcmp( oidInfoPtr->oid, OID_CMS_DATA, \
sizeofOID( OID_CMS_DATA ) ) )
isData = TRUE;
/* Some Microsoft software produces an indefinite encoding for a single
OID so we have to check for this */
if( length == CRYPT_UNUSED )
{
status = checkEOC( stream );
if( cryptStatusError( status ) )
return( status );
if( status == TRUE )
/* We've seen EOC octets, the item has zero length (for example
with a detached signature), we're done */
return( CRYPT_OK );
}
/* If the content is supplied externally (for example with a detached
signature), denoted by the fact that the total content consists only
of the OID, we're done */
if( length != CRYPT_UNUSED && length <= sizeofOID( oidInfoPtr->oid ) )
return( oidInfoPtr->selectionID );
/* Read the content [0] tag and OCTET STRING/SEQUENCE. This requires
some special-case handling, see the comment in writeCMSHeader() for
more details */
status = readLongConstructed( stream, NULL, 0 );
if( cryptStatusError( status ) )
return( status );
tag = peekTag( stream );
if( isData )
{
/* It's pure data content, it must be an OCTET STRING */
if( tag != BER_OCTETSTRING && \
tag != ( BER_OCTETSTRING | BER_CONSTRUCTED ) )
status = CRYPT_ERROR_BADDATA;
}
else
if( isInnerHeader )
{
/* It's an inner header, it should be an OCTET STRING but
alternative interpretations are possible based on the PKCS #7
definition of inner content */
if( tag != BER_OCTETSTRING && \
tag != ( BER_OCTETSTRING | BER_CONSTRUCTED ) && \
tag != BER_SEQUENCE )
status = CRYPT_ERROR_BADDATA;
}
else
/* It's an outer header containing other than data, it must be a
SEQUENCE */
if( tag != BER_SEQUENCE )
status = CRYPT_ERROR_BADDATA;
if( cryptStatusError( status ) )
return( sSetError( stream, status ) );
status = readLongGenericHole( stream, &length, tag );
if( cryptStatusError( status ) )
return( status );
if( dataSize != NULL )
*dataSize = length;
/* If it's structured (i.e. not data in an OCTET STRING), check the
version number of the content if required */
if( !isData && oidInfoPtr->extraInfo != NULL )
{
const CMS_CONTENT_INFO *contentInfoPtr = oidInfoPtr->extraInfo;
status = readShortInteger( stream, &value );
if( cryptStatusError( status ) )
return( status );
if( value < contentInfoPtr->minVersion || \
value > contentInfoPtr->maxVersion )
return( sSetError( stream, CRYPT_ERROR_BADDATA ) );
}
return( oidInfoPtr->selectionID );
}
int writeCMSheader( STREAM *stream, const BYTE *contentOID,
const long dataSize, const BOOLEAN isInnerHeader )
{
BOOLEAN isOctetString = ( isInnerHeader || \
( sizeofOID( contentOID ) == 11 && \
!memcmp( contentOID, OID_CMS_DATA, 11 ) ) ) ? \
TRUE : FALSE;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( isReadPtr( contentOID, sizeofOID( contentOID ) ) );
/* The handling of the wrapper type for the content is rather complex.
If it's an outer header, it's an OCTET STRING for data and a SEQUENCE
for everything else. If it's an inner header it usually follows the
same rule, however for signed data the content was changed from
content [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL
in PKCS #7 to
eContent [0] EXPLICIT OCTET STRING OPTIONAL
for CMS (it was always an OCTET STRING for encrypted data). To
complicate things, there are some older implementations based on the
PKCS #7 interpretation that use a SEQUENCE (namely AuthentiCode).
To resolve this, we use an OCTET STRING for inner content unless the
content type is spcIndirectDataContext */
if( isInnerHeader && sizeofOID( contentOID ) == 12 && \
!memcmp( contentOID, OID_MS_SPCINDIRECTDATACONTEXT, 12 ) )
isOctetString = FALSE;
/* If a size is given, write the definite form */
if( dataSize != CRYPT_UNUSED )
{
writeSequence( stream, sizeofOID( contentOID ) + ( ( dataSize ) ? \
( int ) sizeofObject( sizeofObject( dataSize ) ) : 0 ) );
writeOID( stream, contentOID );
if( dataSize <= 0 )
return( CRYPT_OK ); /* No content, exit */
writeConstructed( stream, sizeofObject( dataSize ), 0 );
if( isOctetString )
return( writeOctetStringHole( stream, dataSize, DEFAULT_TAG ) );
return( writeSequence( stream, dataSize ) );
}
/* No size given, write the indefinite form */
writeSequenceIndef( stream );
writeOID( stream, contentOID );
writeCtag0Indef( stream );
return( isOctetString ? writeOctetStringIndef( stream ) : \
writeSequenceIndef( stream ) );
}
/* Read and write an encryptedContentInfo header. The inner content may be
implicitly or explicitly tagged depending on the exact content type */
int sizeofCMSencrHeader( const BYTE *contentOID, const long dataSize,
const CRYPT_CONTEXT iCryptContext )
{
STREAM nullStream;
int status, cryptInfoSize;
assert( isReadPtr( contentOID, sizeofOID( contentOID ) ) );
assert( isHandleRangeValid( iCryptContext ) );
/* Determine the encoded size of the AlgorithmIdentifier */
sMemOpen( &nullStream, NULL, 0 );
status = writeContextCryptAlgoID( &nullStream, iCryptContext );
cryptInfoSize = stell( &nullStream );
sMemClose( &nullStream );
if( cryptStatusError( status ) )
return( status );
/* Calculate encoded size of SEQUENCE + OID + AlgoID + [0] for the
definite or indefinite forms (the size 2 is for the tag + 0x80
indefinite-length indicator) */
if( dataSize != CRYPT_UNUSED )
return( ( int ) \
( sizeofObject( sizeofOID( contentOID ) + \
cryptInfoSize + sizeofObject( dataSize ) ) - dataSize ) );
return( 2 + sizeofOID( contentOID ) + cryptInfoSize + 2 );
}
int readCMSencrHeader( STREAM *stream, const OID_INFO *oidInfo,
CRYPT_CONTEXT *iCryptContext, QUERY_INFO *queryInfo )
{
QUERY_INFO localQueryInfo, *queryInfoPtr = ( queryInfo == NULL ) ? \
&localQueryInfo : queryInfo;
long length;
int selectionID, tag, status;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( isReadPtr( oidInfo, sizeof( OID_INFO ) ) );
assert( iCryptContext == NULL || \
isWritePtr( iCryptContext, sizeof( CRYPT_CONTEXT ) ) );
assert( queryInfo == NULL || \
isWritePtr( queryInfo, sizeof( QUERY_INFO ) ) );
/* Clear the return values */
if( iCryptContext != NULL )
*iCryptContext = CRYPT_ERROR;
memset( queryInfoPtr, 0, sizeof( QUERY_INFO ) );
/* Read the outer SEQUENCE, OID, and AlgorithmIdentifier. We can't use
a normal readSequence() here because the data length could be much
longer than the maximum allowed in the readSequence() sanity check */
readLongSequence( stream, NULL );
status = readOID( stream, oidInfo, &selectionID );
if( cryptStatusOK( status ) )
status = readContextAlgoID( stream, iCryptContext, queryInfoPtr,
DEFAULT_TAG );
if( cryptStatusError( status ) )
return( status );
/* Read the content [0] tag, which may be either primitive or constructed
depending on the content */
tag = peekTag( stream );
status = readLongGenericHole( stream, &length, tag );
if( cryptStatusOK( status ) && \
( tag != MAKE_CTAG( 0 ) && tag != MAKE_CTAG_PRIMITIVE( 0 ) ) )
{
sSetError( stream, CRYPT_ERROR_BADDATA );
status = CRYPT_ERROR_BADDATA;
}
if( cryptStatusError( status ) )
{
if( iCryptContext != NULL )
krnlSendNotifier( *iCryptContext, IMESSAGE_DECREFCOUNT );
return( status );
}
queryInfoPtr->size = length;
return( selectionID );
}
int writeCMSencrHeader( STREAM *stream, const BYTE *contentOID,
const long dataSize,
const CRYPT_CONTEXT iCryptContext )
{
STREAM nullStream;
int cryptInfoSize, status;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( isReadPtr( contentOID, sizeofOID( contentOID ) ) );
assert( isHandleRangeValid( iCryptContext ) );
/* Determine the encoded size of the AlgorithmIdentifier */
sMemOpen( &nullStream, NULL, 0 );
status = writeContextCryptAlgoID( &nullStream, iCryptContext );
cryptInfoSize = stell( &nullStream );
sMemClose( &nullStream );
if( cryptStatusError( status ) )
return( status );
/* If a size is given, write the definite form */
if( dataSize != CRYPT_UNUSED )
{
writeSequence( stream, sizeofOID( contentOID ) + cryptInfoSize + \
( int ) sizeofObject( dataSize ) );
writeOID( stream, contentOID );
status = writeContextCryptAlgoID( stream, iCryptContext );
if( cryptStatusError( status ) )
return( status );
return( writeOctetStringHole( stream, dataSize, \
MAKE_CTAG_PRIMITIVE( 0 ) ) );
}
/* No size given, write the indefinite form */
writeSequenceIndef( stream );
writeOID( stream, contentOID );
status = writeContextCryptAlgoID( stream, iCryptContext );
if( cryptStatusError( status ) )
return( status );
return( writeCtag0Indef( stream ) );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -