📄 asn1_algid.c
字号:
/****************************************************************************
* *
* ASN.1 Algorithm Identifier 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 */
/****************************************************************************
* *
* Object/Algorithm Identifier Routines *
* *
****************************************************************************/
/* Pull in the AlgorithmIdentifier OID table */
#if defined( INC_ALL )
#include "asn1_oids.h"
#else
#include "misc/asn1_oids.h"
#endif /* Compiler-specific includes */
/* Map an OID to an algorithm type. The parameter value can be NULL if no
sub-algorithm is expected, but we return an error code if the OID has a
sub-algorithm type present */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3 ) ) \
static int oidToAlgorithm( IN_BUFFER( oidLength ) const BYTE *oid,
IN_RANGE( 1, MAX_OID_SIZE ) const int oidLength,
OUT_ALGO_Z CRYPT_ALGO_TYPE *cryptAlgo,
OUT_OPT_INT_Z int *parameter )
{
BYTE oidByte;
int i;
assert( isReadPtr( oid, oidLength ) );
assert( isWritePtr( cryptAlgo, sizeof( CRYPT_ALGO_TYPE ) ) );
assert( parameter == NULL || isWritePtr( parameter, sizeof( int ) ) );
REQUIRES( oidLength >= MIN_OID_SIZE && oidLength <= MAX_OID_SIZE );
/* Clear return values */
*cryptAlgo = CRYPT_ALGO_NONE;
if( parameter != NULL )
*parameter = 0;
/* If the OID is shorter than the minimum possible algorithm OID value,
don't try and process it */
if( oidLength < 7 )
return( CRYPT_ERROR_BADDATA );
oidByte = oid[ 6 ];
/* Look for a matching OID. For quick-reject matching we check the byte
furthest inside the OID that's likely to not match (large groups of
OIDs have common prefixes due to being in the same arc), this rejects
the majority of mismatches without requiring a full comparison */
for( i = 0; algoIDinfoTbl[ i ].algorithm != CRYPT_ALGO_NONE && \
i < FAILSAFE_ARRAYSIZE( algoIDinfoTbl, ALGOID_INFO ); i++ )
{
const ALGOID_INFO *algoIDinfoPtr = &algoIDinfoTbl[ i ];
if( sizeofOID( algoIDinfoPtr->oid ) == oidLength && \
algoIDinfoPtr->oid[ 6 ] == oidByte && \
!memcmp( algoIDinfoPtr->oid, oid, oidLength ) )
{
/* If we're expecting a sub-algorithm, return the sub-algorithm
type alongside the main algorithm type */
if( parameter != NULL )
{
*cryptAlgo = algoIDinfoPtr->algorithm;
*parameter = algoIDinfoPtr->parameter;
return( CRYPT_OK );
}
/* If we're not expecting a sub-algorithm but there's one
present, mark it as an error */
if( algoIDinfoPtr->parameter != CRYPT_ALGO_NONE )
return( CRYPT_ERROR_BADDATA );
*cryptAlgo = algoIDinfoPtr->algorithm;
return( CRYPT_OK );
}
}
ENSURES( i < FAILSAFE_ARRAYSIZE( algoIDinfoTbl, ALGOID_INFO ) );
/* No algorithm for this OID found */
return( CRYPT_ERROR_NOTAVAIL );
}
/* Map an algorithm and optional sub-algorithm/mode 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 */
CHECK_RETVAL_PTR \
static const BYTE *algorithmToOID( IN_ALGO const CRYPT_ALGO_TYPE cryptAlgo,
IN_RANGE( 0, 999 ) const int parameter )
{
int i;
REQUIRES_N( cryptAlgo > CRYPT_ALGO_NONE && cryptAlgo < CRYPT_ALGO_LAST );
REQUIRES_N( parameter >= 0 && parameter <= 999 );
for( i = 0; algoIDinfoTbl[ i ].algorithm != CRYPT_ALGO_NONE && \
i < FAILSAFE_ARRAYSIZE( algoIDinfoTbl, ALGOID_INFO ); i++ )
{
if( algoIDinfoTbl[ i ].algorithm == cryptAlgo )
break;
}
ENSURES_N( i < FAILSAFE_ARRAYSIZE( algoIDinfoTbl, ALGOID_INFO ) );
while( algoIDinfoTbl[ i ].algorithm == cryptAlgo && \
i < FAILSAFE_ARRAYSIZE( algoIDinfoTbl, ALGOID_INFO ) )
{
if( algoIDinfoTbl[ i ].parameter == parameter )
return( algoIDinfoTbl[ i ].oid );
i++;
}
ENSURES_N( i < FAILSAFE_ARRAYSIZE( algoIDinfoTbl, ALGOID_INFO ) );
retIntError_Null();
}
CHECK_RETVAL_PTR \
static const BYTE *algorithmToOIDcheck( IN_ALGO const CRYPT_ALGO_TYPE cryptAlgo,
IN_RANGE( 0, 999 ) const int parameter )
{
int i;
REQUIRES_N( cryptAlgo > CRYPT_ALGO_NONE && cryptAlgo < CRYPT_ALGO_LAST );
REQUIRES_N( parameter >= 0 && parameter <= 999 );
for( i = 0; algoIDinfoTbl[ i ].algorithm != CRYPT_ALGO_NONE && \
i < FAILSAFE_ARRAYSIZE( algoIDinfoTbl, ALGOID_INFO ); i++ )
{
if( algoIDinfoTbl[ i ].algorithm == cryptAlgo )
break;
}
ENSURES_N( i < FAILSAFE_ARRAYSIZE( algoIDinfoTbl, ALGOID_INFO ) );
while( algoIDinfoTbl[ i ].algorithm == cryptAlgo && \
i < FAILSAFE_ARRAYSIZE( algoIDinfoTbl, ALGOID_INFO ) )
{
if( algoIDinfoTbl[ i ].parameter == parameter )
return( algoIDinfoTbl[ i ].oid );
i++;
}
ENSURES_N( i < FAILSAFE_ARRAYSIZE( algoIDinfoTbl, ALGOID_INFO ) );
return( NULL );
}
/* Read the start of an AlgorithmIdentifier record, used by a number of
routines. 'parameter' can be either a CRYPT_ALGO_TYPE or a
CRYPT_MODE_TYPE, which is why it's given as a generic integer rather than
a more specific type */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
static int readAlgoIDheader( INOUT STREAM *stream,
OUT_ALGO_Z CRYPT_ALGO_TYPE *cryptAlgo,
OUT_OPT_RANGE( 0, 999 ) int *parameter,
OUT_OPT_LENGTH_SHORT_Z int *extraLength,
IN_TAG const int tag )
{
CRYPT_ALGO_TYPE localCryptAlgo;
BYTE oidBuffer[ MAX_OID_SIZE + 8 ];
int oidLength, algoParam, length, status;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( isWritePtr( cryptAlgo, sizeof( CRYPT_ALGO_TYPE ) ) );
assert( parameter == NULL || \
isWritePtr( parameter, sizeof( int ) ) );
assert( extraLength == NULL || \
isWritePtr( extraLength, sizeof( int ) ) );
REQUIRES_S( tag == DEFAULT_TAG || ( tag >= 0 && tag < MAX_TAG_VALUE ) );
/* Clear the return values */
*cryptAlgo = CRYPT_ALGO_NONE;
if( parameter != NULL )
*parameter = 0;
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 = readEncodedOID( stream, oidBuffer, MAX_OID_SIZE, &oidLength,
BER_OBJECT_IDENTIFIER );
if( cryptStatusError( status ) )
return( status );
length -= oidLength;
if( oidLength != sizeofOID( oidBuffer ) || \
length < 0 || length >= MAX_INTLENGTH_SHORT )
{
/* It's a stream-related error, make it persistent */
return( sSetError( stream, CRYPT_ERROR_BADDATA ) );
}
status = oidToAlgorithm( oidBuffer, oidLength, &localCryptAlgo,
&algoParam );
if( cryptStatusError( status ) )
return( status );
*cryptAlgo = localCryptAlgo;
if( parameter != NULL )
*parameter = algoParam;
/* If the caller has specified that there should be no parameters
present, make sure that there's either no data or an ASN.1 NULL
present and nothing else */
if( extraLength == NULL )
return( ( length > 0 ) ? readNull( stream ) : CRYPT_OK );
/* If the parameters are null parameters, check them and exit */
if( length == sizeofNull() )
return( readNull( stream ) );
/* Handle any remaining parameters */
*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 */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
static int readAlgoIDInfo( INOUT STREAM *stream,
INOUT QUERY_INFO *queryInfo,
IN_TAG const int tag )
{
int mode, length, status; /* 'mode' must be type integer */
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( isWritePtr( queryInfo, sizeof( QUERY_INFO ) ) );
REQUIRES_S( tag == DEFAULT_TAG || ( tag >= 0 && tag < MAX_TAG_VALUE ) );
/* Read the AlgorithmIdentifier header and OID */
status = readAlgoIDheader( stream, &queryInfo->cryptAlgo, &mode,
&length, tag );
if( cryptStatusError( status ) )
return( status );
queryInfo->cryptMode = mode; /* CRYPT_MODE_TYPE vs. integer */
/* 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_MODE_NONE;
}
/* Hash algorithms will either have NULL parameters or none at all
depending on which interpretation of which standard the sender used
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -