📄 asn1_ext.c
字号:
}
return( CRYPT_ALGO_NONE );
}
/* Map an algorithm and optional sub-algorithm to an OID. These functions
are almost identical, the only difference is that the one used for
checking only doesn't throw an exception when it encounters an algorithm
value that it can't encode as an OID */
static const BYTE *algorithmToOID( const CRYPT_ALGO_TYPE algorithm,
const CRYPT_ALGO_TYPE subAlgorithm )
{
int i;
for( i = 0; algoIDinfoTbl[ i ].algorithm != CRYPT_ALGO_NONE; i++ )
{
const ALGOID_INFO *algoIDinfoPtr = &algoIDinfoTbl[ i ];
if( algoIDinfoPtr->algorithm == algorithm && \
algoIDinfoPtr->subAlgorithm == subAlgorithm )
return( algoIDinfoPtr->oid );
}
assert( NOTREACHED );
return( NULL ); /* Get rid of compiler warning */
}
static const BYTE *algorithmToOIDcheck( const CRYPT_ALGO_TYPE algorithm,
const CRYPT_ALGO_TYPE subAlgorithm )
{
int i;
for( i = 0; algoIDinfoTbl[ i ].algorithm != CRYPT_ALGO_NONE; i++ )
if( algoIDinfoTbl[ i ].algorithm == algorithm && \
algoIDinfoTbl[ i ].subAlgorithm == subAlgorithm )
return( algoIDinfoTbl[ i ].oid );
return( NULL );
}
/* Read the start of an AlgorithmIdentifier record, used by a number of
routines */
static int readAlgoIDheader( STREAM *stream, CRYPT_ALGO_TYPE *algorithm,
CRYPT_ALGO_TYPE *subAlgorithm, int *extraLength,
const int tag )
{
CRYPT_ALGO_TYPE cryptAlgo;
BYTE buffer[ MAX_OID_SIZE + 8 ];
int bufferLength, cryptSubAlgo, length, status;
/* Clear the return values */
if( algorithm != NULL )
*algorithm = CRYPT_ALGO_NONE;
if( subAlgorithm != NULL )
*subAlgorithm = CRYPT_ALGO_NONE;
if( extraLength != NULL )
*extraLength = 0;
/* Determine the algorithm information based on the AlgorithmIdentifier
field */
if( tag == DEFAULT_TAG )
readSequence( stream, &length );
else
readConstructed( stream, &length, tag );
status = readRawObject( stream, buffer, &bufferLength, MAX_OID_SIZE,
BER_OBJECT_IDENTIFIER );
if( cryptStatusError( status ) )
return( status );
length -= bufferLength;
if( bufferLength != sizeofOID( buffer ) || length < 0 )
/* It's a stream-related error, make it persistent */
return( sSetError( stream, CRYPT_ERROR_BADDATA ) );
if( ( cryptAlgo = oidToAlgorithm( buffer, \
&cryptSubAlgo ) ) == CRYPT_ALGO_NONE )
return( CRYPT_ERROR_NOTAVAIL );
if( algorithm != NULL )
*algorithm = cryptAlgo;
if( subAlgorithm != NULL )
*subAlgorithm = cryptSubAlgo;
/* If the user isn't interested in the algorithm parameters, skip them */
if( extraLength == NULL )
return( ( length > 0 ) ? sSkip( stream, length ) : CRYPT_OK );
/* Handle any remaining parameters */
if( length == sizeofNull() )
return( readNull( stream ) );
*extraLength = ( int ) length;
return( CRYPT_OK );
}
/****************************************************************************
* *
* EncryptionAlgorithmIdentifier Routines *
* *
****************************************************************************/
/* EncryptionAlgorithmIdentifier parameters:
aesXcbc, aesXofb: AES FIPS
iv OCTET STRING SIZE (16)
aesXcfb: AES FIPS
SEQUENCE {
iv OCTET STRING SIZE (16),
noOfBits INTEGER (128)
}
cast5cbc: RFC 2144
SEQUENCE {
iv OCTET STRING DEFAULT 0,
keyLen INTEGER (128)
}
blowfishCBC, desCBC, desEDE3-CBC: Blowfish RFC/OIW
iv OCTET STRING SIZE (8)
blowfishCFB, blowfishOFB, desCFB, desOFB: Blowfish RFC/OIW
SEQUENCE {
iv OCTET STRING SIZE (8),
noBits INTEGER (64)
}
ideaCBC: Ascom Tech
SEQUENCE {
iv OCTET STRING OPTIONAL
}
ideaCFB: Ascom Tech
SEQUENCE {
r [ 0 ] INTEGER DEFAULT 64,
k [ 1 ] INTEGER DEFAULT 64,
j [ 2 ] INTEGER DEFAULT 64,
iv [ 3 ] OCTET STRING OPTIONAL
}
ideaOFB: Ascom Tech
SEQUENCE {
j INTEGER DEFAULT 64,
iv OCTET STRING OPTIONAL
}
rc2CBC: RFC 2311
SEQUENCE {
rc2Param INTEGER (58), -- 128 bit key
iv OCTET STRING SIZE (8)
}
rc4: (Unsure where this one is from)
NULL
rc5: RFC 2040
SEQUENCE {
version INTEGER (16),
rounds INTEGER (12),
blockSize INTEGER (64),
iv OCTET STRING OPTIONAL
}
skipjackCBC: SDN.701
SEQUENCE {
iv OCTET STRING
}
Because of the somewhat haphazard nature of encryption
AlgorithmIdentifier definitions, we can only handle the following
algorithm/mode combinations:
AES ECB, CBC, CFB, OFB
Blowfish ECB, CBC, CFB, OFB
CAST128 CBC
DES ECB, CBC, CFB, OFB
3DES ECB, CBC, CFB, OFB
IDEA ECB, CBC, CFB, OFB
RC2 ECB, CBC
RC4
RC5 CBC
Skipjack CBC */
/* Magic value to denote 128-bit RC2 keys */
#define RC2_KEYSIZE_MAGIC 58
/* Read an EncryptionAlgorithmIdentifier/DigestAlgorithmIdentifier */
static int readAlgoIDInfo( STREAM *stream, QUERY_INFO *queryInfo,
const int tag )
{
CRYPT_ALGO_TYPE mode;
int length, status;
/* Read the AlgorithmIdentifier header and OID. Since this function has
to handle a variety of algorithm ID info, we have to cast the return
value to the appropriate enumerated type (some compilers complain
about this) */
status = readAlgoIDheader( stream, &queryInfo->cryptAlgo, &mode,
&length, tag );
if( cryptStatusError( status ) )
return( status );
queryInfo->cryptMode = ( CRYPT_MODE_TYPE ) mode;
/* Some broken implementations use sign + hash algoIDs in places where
a hash algoID is called for, if we find one of these we modify the
read AlgorithmIdentifier information to make it look like a hash
algoID */
if( ( queryInfo->cryptAlgo >= CRYPT_ALGO_FIRST_PKC && \
queryInfo->cryptAlgo <= CRYPT_ALGO_LAST_PKC ) && \
( queryInfo->cryptMode >= CRYPT_ALGO_FIRST_HASH && \
queryInfo->cryptMode <= CRYPT_ALGO_LAST_HASH ) )
{
queryInfo->cryptAlgo = ( CRYPT_ALGO_TYPE ) queryInfo->cryptMode;
queryInfo->cryptMode = ( CRYPT_ALGO_TYPE ) CRYPT_ALGO_NONE;
}
/* Hash algorithms will either have NULL parameters or none at all
depending on which interpreation of which standard the sender used,
so if it's not a conventional encryption algorithm we just skip any
remaining parameter data and return */
if( ( queryInfo->cryptAlgo >= CRYPT_ALGO_FIRST_HASH && \
queryInfo->cryptAlgo <= CRYPT_ALGO_LAST_HASH ) || \
( queryInfo->cryptAlgo >= CRYPT_ALGO_FIRST_MAC && \
queryInfo->cryptAlgo <= CRYPT_ALGO_LAST_MAC ) )
return( ( length > 0 ) ? sSkip( stream, length ) : CRYPT_OK );
/* If it's not a hash/MAC algorithm, it has to be a conventional
encryption algorithm */
if( queryInfo->cryptAlgo < CRYPT_ALGO_FIRST_CONVENTIONAL || \
queryInfo->cryptAlgo > CRYPT_ALGO_LAST_CONVENTIONAL )
return( CRYPT_ERROR_NOTAVAIL );
/* Read the algorithm-specific parameters. In theory we should do
something with some of the values like the IV size parameter, but
since the standard never explains what to do if it's something other
than the algorithm block size (Left pad? Right pad? Sign-extend?
Repeat the data?) it's safer not to do anything ("Never check for an
error you don't know how to handle"). In any case there are no known
cases of these strange values ever being used (probably because all
existing software would break) so for now we just make sure that
they're present but otherwise ignore them */
switch( queryInfo->cryptAlgo )
{
case CRYPT_ALGO_3DES:
case CRYPT_ALGO_AES:
case CRYPT_ALGO_BLOWFISH:
case CRYPT_ALGO_DES:
if( queryInfo->cryptMode == CRYPT_MODE_ECB )
/* The NULL parameter has already been read in
readAlgoIDheader() */
return( CRYPT_OK );
if( ( queryInfo->cryptMode == CRYPT_MODE_CBC ) || \
( queryInfo->cryptAlgo == CRYPT_ALGO_AES && \
queryInfo->cryptMode == CRYPT_MODE_OFB ) )
return( readOctetString( stream, queryInfo->iv,
&queryInfo->ivLength,
CRYPT_MAX_IVSIZE ) );
readSequence( stream, NULL );
readOctetString( stream, queryInfo->iv, &queryInfo->ivLength,
CRYPT_MAX_IVSIZE );
return( readShortInteger( stream, NULL ) );
case CRYPT_ALGO_CAST:
readSequence( stream, NULL );
readOctetString( stream, queryInfo->iv, &queryInfo->ivLength,
CRYPT_MAX_IVSIZE );
return( readShortInteger( stream, NULL ) );
case CRYPT_ALGO_IDEA:
{
int paramTag;
if( queryInfo->cryptMode == CRYPT_MODE_ECB )
/* The NULL parameter has already been read in
readAlgoIDheader() */
return( CRYPT_OK );
readSequence( stream, NULL );
paramTag = peekTag( stream );
if( queryInfo->cryptMode == CRYPT_MODE_CFB )
{
/* Skip the CFB r, k, and j parameters */
while( paramTag == MAKE_CTAG_PRIMITIVE( 0 ) || \
paramTag == MAKE_CTAG_PRIMITIVE( 1 ) || \
paramTag == MAKE_CTAG_PRIMITIVE( 2 ) )
{
long value;
status = readShortIntegerTag( stream, &value, paramTag );
if( cryptStatusError( status ) )
return( status );
if( value != 64 )
return( CRYPT_ERROR_NOTAVAIL );
paramTag = peekTag( stream );
}
return( readOctetStringTag( stream, queryInfo->iv,
&queryInfo->ivLength,
CRYPT_MAX_IVSIZE, 3 ) );
}
if( queryInfo->cryptMode == CRYPT_MODE_OFB && \
paramTag == BER_INTEGER )
{
long value;
/* Skip the OFB j parameter */
status = readShortInteger( stream, &value );
if( cryptStatusError( status ) )
return( status );
if( value != 64 )
return( CRYPT_ERROR_NOTAVAIL );
}
return( readOctetString( stream, queryInfo->iv,
&queryInfo->ivLength,
CRYPT_MAX_IVSIZE ) );
}
case CRYPT_ALGO_RC2:
/* In theory we should check that the parameter value ==
RC2_KEYSIZE_MAGIC (corresponding to a 128-bit key) but in
practice this doesn't really matter, we just use whatever we
find inside the PKCS #1 padding */
readSequence( stream, NULL );
if( queryInfo->cryptMode != CRYPT_MODE_CBC )
return( readShortInteger( stream, NULL ) );
readShortInteger( stream, NULL );
return( readOctetString( stream, queryInfo->iv,
&queryInfo->ivLength,
CRYPT_MAX_IVSIZE ) );
case CRYPT_ALGO_RC4:
/* The NULL parameter has already been read in
readAlgoIDheader() */
return( CRYPT_OK );
case CRYPT_ALGO_RC5:
{
long val1, val2, val3;
readSequence( stream, NULL );
readShortInteger( stream, &val1 ); /* Version */
readShortInteger( stream, &val2 ); /* Rounds */
status = readShortInteger( stream, &val3 ); /* Block size */
if( cryptStatusError( status ) )
return( status );
if( val1 != 16 || val2 != 12 || val3 != 64 )
/* This algorithm makes enough of a feature of its variable
parameters that we do actually check to make sure that
they're sensible, since it may just be possible that
someone playing with an implementation decides to use
weird values */
return( CRYPT_ERROR_NOTAVAIL );
return( readOctetString( stream, queryInfo->iv,
&queryInfo->ivLength,
CRYPT_MAX_IVSIZE ) );
}
case CRYPT_ALGO_SKIPJACK:
readSequence( stream, NULL );
return( readOctetString( stream, queryInfo->iv,
&queryInfo->ivLength,
CRYPT_MAX_IVSIZE ) );
}
assert( NOTREACHED );
return( CRYPT_ERROR_NOTAVAIL ); /* Get rid of compiler warning */
}
/* Write an EncryptionAlgorithmIdentifier record */
static int writeContextCryptAlgoID( STREAM *stream,
const CRYPT_CONTEXT iCryptContext )
{
const BYTE *oid;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -