📄 asn1oid.c
字号:
}
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,
RESOURCE_IMESSAGE_DECREFCOUNT );
if( cryptArgError( status ) )
{
sSetError( stream, CRYPT_ERROR_BADDATA );
status = CRYPT_ERROR_BADDATA;
}
}
else
*iCryptContext = createInfo.cryptHandle;
return( status );
}
/****************************************************************************
* *
* Read/Write CMS Headers *
* *
****************************************************************************/
/* Read an abnormally-long SEQUENCE header. This is used in place of the
usual readSequence() in places where potentially huge data quantities
would fail the sanity check enforced by readSequence() */
static long readLongSequence( STREAM *stream )
{
int tag;
tag = readTag( stream );
if( cryptStatusError( tag ) )
return( tag );
if( tag != BER_SEQUENCE )
{
sSetError( stream, CRYPT_ERROR_BADDATA );
return( CRYPT_ERROR_BADDATA );
}
return( readLength( stream ) );
}
/* Read and write CMS headers */
int readCMSheader( STREAM *stream, const OID_SELECTION *oidSelection,
long *dataSize, const BOOLEAN isInnerHeader )
{
BOOLEAN isData = FALSE;
BYTE oid[ MAX_OID_SIZE ];
long totalLength, value;
int length, oidEntry, status;
/* Clear return value */
if( dataSize != NULL )
*dataSize = 0;
/* Read the outer SEQUENCE and OID and try and find the entry for the
OID. Note that we can't use a normal readSequence() here since the
data length could be much longer than the maximum allowed in the
readSequence() sanity check. In addition we can't use
readOIDSelection() either since we have to identify and handle data
vs non-data content in different ways */
totalLength = readLongSequence( stream );
status = readRawObject( stream, oid, &length, MAX_OID_SIZE,
BER_OBJECT_IDENTIFIER );
if( cryptStatusError( status ) )
return( status );
for( oidEntry = 0; oidSelection[ oidEntry ].oid != NULL; oidEntry++ )
if( length == sizeofOID( oidSelection[ oidEntry ].oid ) && \
!memcmp( oid, oidSelection[ oidEntry ].oid, length ) )
break;
if( oidSelection[ oidEntry ].oid == NULL )
{
sSetError( stream, CRYPT_ERROR_BADDATA );
return( CRYPT_ERROR_BADDATA );
}
/* If the content type is data, the content is an OCTET STRING rather
than a SEQUENCE so we remember the type for later */
if( length == sizeofOID( OID_CMS_DATA ) && \
!memcmp( 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( !totalLength && checkEOC( stream ) )
totalLength = length;
/* If the content is supplied externally (for example with a detached
sig), there won't be any content present */
if( totalLength == length )
{
if( dataSize != NULL )
*dataSize = 0;
}
else
{
int tag;
/* Read the content [0] tag and OCTET STRING/SEQUENCE (this requires
some special-case handling, see the comment in writeCMSHeader()
for more details). Note that we can't use readConstructed() here
because that's only intended for short data objects and will
report an error with large amounts of encapsulated data */
tag = readTag( stream );
status = ( int ) readLength( stream );
if( cryptStatusError( status ) )
return( status );
if( tag != MAKE_CTAG( 0 ) )
status = CRYPT_ERROR_BADDATA;
else
{
tag = readTag( 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 ) )
{
sSetError( stream, status );
return( status );
}
value = readLength( stream );
if( cryptStatusError( value ) )
return( ( int ) value );
if( dataSize != NULL )
*dataSize = ( value ) ? value : CRYPT_UNUSED;
}
/* If it's not data in an OCTET STRING, check the version number of the
content if required */
if( !isData && oidSelection[ oidEntry ].minVersion != CRYPT_UNUSED )
{
readShortInteger( stream, &value );
if( value < oidSelection[ oidEntry ].minVersion || \
value > oidSelection[ oidEntry ].maxVersion )
{
sSetError( stream, CRYPT_ERROR_BADDATA );
return( CRYPT_ERROR_BADDATA );
}
}
return( sStatusOK( stream ) ? oidSelection[ oidEntry ].selection : \
sGetStatus( stream ) );
}
int writeCMSheader( STREAM *stream, const BYTE *oid, const long dataSize,
const BOOLEAN isInnerHeader )
{
BOOLEAN isOctetString = ( isInnerHeader || \
( sizeofOID( oid ) == 11 && \
!memcmp( oid, OID_CMS_DATA, 11 ) ) ) ? \
TRUE : FALSE;
/* 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 which 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( oid ) == 12 && \
!memcmp( oid, OID_MS_SPCINDIRECTDATACONTEXT, 12 ) )
isOctetString = FALSE;
/* If a size is given, write the definite form. Note that we can't use
any of the more useful functions like writeConstructed() or
writeGenericHole() since the length could be larger than the safe
upper limit enforced by these functions */
if( dataSize != CRYPT_UNUSED )
{
writeSequence( stream, sizeofOID( oid ) + ( ( dataSize ) ? \
( int ) sizeofObject( sizeofObject( dataSize ) ) : 0 ) );
writeOID( stream, oid );
if( !dataSize )
return( CRYPT_OK ); /* No content, exit */
writeCtag( stream, 0 );
writeLength( stream, sizeofObject( dataSize ) );
writeTag( stream, isOctetString ? BER_OCTETSTRING : BER_SEQUENCE );
writeLength( stream, dataSize );
return( sGetStatus( stream ) );
}
/* No size given, write the indefinite form */
writeSequenceIndef( stream );
writeOID( stream, oid );
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;
/* Determine the encoded size of the AlgorithmIdentifier */
sMemOpen( &nullStream, NULL, 0 );
status = writeContextCryptAlgoID( &nullStream, iCryptContext );
cryptInfoSize = ( int ) stell( &nullStream );
sMemClose( &nullStream );
if( cryptStatusError( status ) )
return( status );
/* Calculate encoded size of SEQUENCE + OID + AlgoID + [0] for the
definite or indefinite forms */
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_SELECTION *oidSelection,
CRYPT_CONTEXT *iCryptContext, QUERY_INFO *queryInfo )
{
QUERY_INFO localQueryInfo, *queryInfoPtr = ( queryInfo == NULL ) ? \
&localQueryInfo : queryInfo;
long value;
int oidEntry, tag, status;
/* Clear the return values */
if( iCryptContext != NULL )
*iCryptContext = CRYPT_ERROR;
memset( queryInfoPtr, 0, sizeof( QUERY_INFO ) );
/* Read the outer SEQUENCE and OID. Note that we can't use a normal
readSequence() here since the data length could be much longer
than the maximum allowed in the readSequence() sanity check */
readLongSequence( stream );
status = readOIDSelection( stream, oidSelection, &oidEntry );
if( cryptStatusError( status ) )
return( status );
/* Read the AlgorithmIdentifier. This can return non-stream-related
errors so if there's an error at this point we exit immediately */
status = readContextAlgoID( stream, iCryptContext, queryInfoPtr,
DEFAULT_TAG );
if( cryptStatusError( status ) )
return( status );
/* Read the content [0] tag. As with reading a standard CMS header, we
can't use readConstructed() because it treats the presence of
unexpectedly large data quantities as an error */
tag = readTag( stream );
value = readLength( stream );
if( cryptStatusError( value ) )
status = ( int ) value;
else
if( 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,
RESOURCE_IMESSAGE_DECREFCOUNT );
return( status );
}
queryInfoPtr->size = ( value ) ? value : CRYPT_UNUSED;
return( oidEntry );
}
int writeCMSencrHeader( STREAM *stream, const BYTE *contentOID,
const long dataSize,
const CRYPT_CONTEXT iCryptContext )
{
STREAM nullStream;
int cryptInfoSize, status;
/* Determine the encoded size of the AlgorithmIdentifier */
sMemOpen( &nullStream, NULL, 0 );
status = writeContextCryptAlgoID( &nullStream, iCryptContext );
cryptInfoSize = ( int ) 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 );
writeCtagPrimitive( stream, 0 );
writeLength( stream, dataSize );
return( status );
}
/* No size given, write the indefinite form */
writeSequenceIndef( stream );
writeOID( stream, contentOID );
status = writeContextCryptAlgoID( stream, iCryptContext );
writeCtag0Indef( stream );
return( status );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -