📄 asn1_ext.c
字号:
/****************************************************************************
* *
* ASN.1 Supplemental Read/Write Routines *
* Copyright Peter Gutmann 1992-2008 *
* *
****************************************************************************/
#if defined( INC_ALL )
#include "asn1.h"
#include "asn1_ext.h"
#else
#include "misc/asn1.h"
#include "misc/asn1_ext.h"
#endif /* Compiler-specific includes */
/****************************************************************************
* *
* 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 */
CHECK_RETVAL \
int sizeofMessageDigest( IN_ALGO const CRYPT_ALGO_TYPE hashAlgo,
IN_LENGTH_HASH const int hashSize )
{
int algoInfoSize, hashInfoSize;
REQUIRES( hashAlgo >= CRYPT_ALGO_FIRST_HASH && \
hashAlgo <= CRYPT_ALGO_LAST_HASH );
REQUIRES( hashSize >= 16 && hashSize <= CRYPT_MAX_HASHSIZE );
algoInfoSize = sizeofAlgoID( hashAlgo );
hashInfoSize = sizeofObject( hashSize );
ENSURES( algoInfoSize > 8 && algoInfoSize < MAX_INTLENGTH_SHORT );
ENSURES( hashInfoSize > hashSize && hashInfoSize < MAX_INTLENGTH_SHORT );
return( sizeofObject( algoInfoSize + hashInfoSize ) );
}
RETVAL STDC_NONNULL_ARG( ( 1, 3 ) ) \
int writeMessageDigest( INOUT STREAM *stream,
IN_ALGO const CRYPT_ALGO_TYPE hashAlgo,
IN_BUFFER( hashSize ) const void *hash,
IN_LENGTH_HASH const int hashSize )
{
int status;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( isReadPtr( hash, hashSize ) );
REQUIRES_S( hashAlgo >= CRYPT_ALGO_FIRST_HASH && \
hashAlgo <= CRYPT_ALGO_LAST_HASH );
REQUIRES_S( hashSize >= 16 && hashSize <= CRYPT_MAX_HASHSIZE );
writeSequence( stream, sizeofAlgoID( hashAlgo ) + \
( int ) sizeofObject( hashSize ) );
status = writeAlgoID( stream, hashAlgo );
if( cryptStatusOK( status ) )
status = writeOctetString( stream, hash, hashSize, DEFAULT_TAG );
return( status );
}
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 3, 5 ) ) \
int readMessageDigest( INOUT STREAM *stream,
OUT_ALGO_Z CRYPT_ALGO_TYPE *hashAlgo,
OUT_BUFFER( hashMaxLen, hashSize ) void *hash,
IN_LENGTH_HASH const int hashMaxLen,
OUT_LENGTH_SHORT_Z int *hashSize )
{
int status;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( isWritePtr( hashAlgo, sizeof( CRYPT_ALGO_TYPE ) ) );
assert( isWritePtr( hash, hashMaxLen ) );
assert( isWritePtr( hashSize, sizeof( int ) ) );
REQUIRES_S( hashMaxLen >= 16 && hashMaxLen <= 8192 );
/* Clear the return values */
memset( hash, 0, min( 16, hashMaxLen ) );
*hashSize = 0;
/* Read the message digest, enforcing sensible size values */
readSequence( stream, NULL );
status = readAlgoID( stream, hashAlgo );
if( cryptStatusError( status ) )
return( status );
return( readOctetString( stream, hash, hashSize, 16, hashMaxLen ) );
}
/****************************************************************************
* *
* 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 */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
int readCMSheader( INOUT STREAM *stream,
IN_ARRAY( noOidInfoEntries ) const OID_INFO *oidInfo,
IN_RANGE( 1, 50 ) const int noOidInfoEntries,
OUT_OPT_LENGTH_INDEF 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 ) * noOidInfoEntries ) );
assert( dataSize == NULL || isWritePtr( dataSize, sizeof( long ) ) );
REQUIRES_S( noOidInfoEntries > 0 && noOidInfoEntries <= 50 );
/* 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, noOidInfoEntries, &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. Since there
are a pile of CMS OIDs of the same length as OID_CMS_DATA, we check
for a match on the last byte before we perform a full OID match */
assert( sizeofOID( OID_CMS_DATA ) == 11 );
if( sizeofOID( oidInfoPtr->oid ) == sizeofOID( OID_CMS_DATA ) && \
oidInfoPtr->oid[ 10 ] == OID_CMS_DATA[ 10 ] && \
!memcmp( oidInfoPtr->oid, OID_CMS_DATA, \
sizeofOID( OID_CMS_DATA ) ) )
isData = TRUE;
/* If it's a definite length, check for special-case situations like
detached signatures */
if( length != CRYPT_UNUSED )
{
/* 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 <= sizeofOID( oidInfoPtr->oid ) )
return( oidInfoPtr->selectionID );
}
else
{
/* Some Microsoft software produces an indefinite encoding for a
single OID so we have to check for this */
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( 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( cryptStatusError( tag ) )
return( tag );
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 old
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 );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -