📄 asn1objs.c
字号:
writeSequence( stream, ( int ) sizeofObject( recipientKeyInfoSize ) );
writeSequence( stream, recipientKeyInfoSize );
writeConstructed( stream, ( int ) sizeofObject( rKeyIDlength ), 0 );
writeOctetString( stream, rKeyID, rKeyIDlength, DEFAULT_TAG );
writeOctetString( stream, wrappedKey, wrappedKeyLength, DEFAULT_TAG );
return( sGetStatus( stream ) );
}
/* Read a key agreement record */
int readKeyAgreeInfo( STREAM *stream, QUERY_INFO *queryInfo,
CRYPT_CONTEXT *iKeyAgreeContext )
{
CRYPT_CONTEXT iLocalKeyAgreeContext;
long value;
int status;
/* Clear return values */
memset( queryInfo, 0, sizeof( QUERY_INFO ) );
if( iKeyAgreeContext != NULL )
*iKeyAgreeContext = CRYPT_ERROR;
/* Read the header and version number */
readConstructed( stream, NULL, CTAG_RI_KEYAGREE );
status = readShortInteger( stream, &value );
if( cryptStatusError( status ) )
return( status );
if( value != 3 )
return( CRYPT_ERROR_BADDATA );
/* Read the public key information and encryption algorithm information */
status = readPublicKey( stream, &iLocalKeyAgreeContext,
READKEY_OPTION_NONE, DEFAULT_TAG );
if( cryptStatusError( status ) )
return( status );
/* If we're doing a query we're not interested in the key agreement
context so we just copy out the information we need and destroy it */
if( iKeyAgreeContext == NULL )
{
RESOURCE_DATA msgData;
setResourceData( &msgData, queryInfo->keyID,
queryInfo->keyIDlength );
status = krnlSendMessage( iLocalKeyAgreeContext,
RESOURCE_IMESSAGE_GETATTRIBUTE_S, &msgData,
CRYPT_IATTRIBUTE_KEYID );
if( cryptStatusOK( status ) )
status = krnlSendMessage( iLocalKeyAgreeContext,
RESOURCE_IMESSAGE_GETATTRIBUTE,
&queryInfo->cryptAlgo,
CRYPT_CTXINFO_ALGO );
krnlSendNotifier( iLocalKeyAgreeContext, RESOURCE_IMESSAGE_DECREFCOUNT );
if( cryptStatusError( status ) )
return( status );
}
else
/* Make the key agreement context externally visible */
*iKeyAgreeContext = iLocalKeyAgreeContext;
return( CRYPT_OK );
}
/****************************************************************************
* *
* Signature Routines *
* *
****************************************************************************/
/* Write a signature. The handling of CMS signatures is non-orthogonal to
readSignature() because creating a CMS signature involves adding assorted
additional data like iAndS and signed attributes which present too much
information to pass into a basic writeSignature() call */
int writeSignature( STREAM *stream, const CRYPT_CONTEXT iSignContext,
const CRYPT_ALGO hashAlgo, const CRYPT_ALGO signAlgo,
const BYTE *signature, const int signatureLength,
const SIGNATURE_TYPE signatureType )
{
/* If it's an X.509 signature, write the algorithm identifier and
signature data wrapped in a BIT STRING. If it's a raw signature,
just write the BIT STRING */
if( signatureType == SIGNATURE_RAW || signatureType == SIGNATURE_X509 )
{
/* Write the hash+signature algorithm identifier if necessary
followed by the BIT STRING wrapper */
if( signatureType == SIGNATURE_X509 )
writeContextAlgoID( stream, iSignContext, hashAlgo,
ALGOID_FLAG_ALGOID_ONLY );
writeTag( stream, BER_BITSTRING );
writeLength( stream, signatureLength + 1 );
sputc( stream, 0 ); /* Write bit remainder octet */
return( writeRawObject( stream, signature, signatureLength ) );
}
/* If it's a PGP signature, write the signature in the form expected by
PGP */
if( signatureType == SIGNATURE_PGP )
{
int pgpWriteMPI( STREAM *stream, const BYTE *data, const int length );
if( isDlpAlgo( signAlgo ) )
/* We've already specified the DLP output format as PGP so
there's no need for further processing */
return( swrite( stream, signature, signatureLength ) );
return( pgpWriteMPI( stream, signature, signatureLength ) );
}
/* Write the signature identification information and signature data
wrapped as an OCTET STRING */
if( signatureType == SIGNATURE_CRYPTLIB )
{
RESOURCE_DATA msgData;
BYTE keyID[ CRYPT_MAX_HASHSIZE ];
/* Get the key ID */
setResourceData( &msgData, keyID, CRYPT_MAX_HASHSIZE );
krnlSendMessage( iSignContext, RESOURCE_IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_IATTRIBUTE_KEYID );
/* Write the header */
writeSequence( stream, sizeofShortInteger( SIGNATURE_EX_VERSION ) +
( int ) sizeofObject( msgData.length ) +
sizeofContextAlgoID( iSignContext, CRYPT_ALGO_NONE, \
ALGOID_FLAG_ALGOID_ONLY ) +
sizeofAlgoID( hashAlgo ) +
( int ) sizeofObject( signatureLength ) );
/* Write the version, key ID and algorithm identifier */
writeShortInteger( stream, SIGNATURE_EX_VERSION, DEFAULT_TAG );
writeOctetString( stream, msgData.data, msgData.length, CTAG_SI_SKI );
writeAlgoID( stream, hashAlgo );
writeContextAlgoID( stream, iSignContext, CRYPT_ALGO_NONE,
ALGOID_FLAG_ALGOID_ONLY );
}
else
{
assert( signatureType == SIGNATURE_CMS );
/* Write the signature algorithm identifier. Since full CMS sigs
include signed attributes */
writeContextAlgoID( stream, iSignContext, CRYPT_ALGO_NONE,
ALGOID_FLAG_ALGOID_ONLY );
}
return( writeOctetString( stream, signature, signatureLength, DEFAULT_TAG ) );
}
/* Read a signature */
int readSignature( STREAM *stream, QUERY_INFO *queryInfo,
const SIGNATURE_TYPE signatureType,
const CRYPT_ALGO signAlgo )
{
int length, status;
/* Clear return value */
memset( queryInfo, 0, sizeof( QUERY_INFO ) );
/* If it's an X.509 signature, it's just a signature+hash algorithm ID.
If it's a raw signature it's the same without the algorithm ID */
if( signatureType == SIGNATURE_RAW || signatureType == SIGNATURE_X509 )
{
/* Read the signature/hash algorithm information if necessary
followed by the start of the signature */
if( signatureType == SIGNATURE_X509 )
{
status = readAlgoIDex( stream, &queryInfo->cryptAlgo,
&queryInfo->hashAlgo, NULL );
if( cryptStatusError( status ) )
return( status );
}
status = readBitStringHole( stream, &queryInfo->dataLength,
DEFAULT_TAG );
if( cryptStatusOK( status ) )
queryInfo->dataStart = sMemBufPtr( stream );
return( status );
}
/* If it's a PGP signature, it's either handled directly or it's an RSA
MPI which only needs to have its length stripped */
if( signatureType == SIGNATURE_PGP )
{
if( isDlpAlgo( signAlgo ) )
{
queryInfo->dataStart = sMemBufPtr( stream );
queryInfo->dataLength = sMemDataLeft( stream );
}
else
{
assert( signAlgo == CRYPT_ALGO_RSA );
queryInfo->dataStart = sMemBufPtr( stream ) + 2;
queryInfo->dataLength = sMemDataLeft( stream ) - 2;
}
return( CRYPT_OK );
}
/* If it's a CMS signature, read the issuer ID and hash algorithm
identifier and skip the authenticated attributes if there are any
present after remembering where they start */
if( signatureType == SIGNATURE_CMS )
{
long value;
/* Read the header */
readSequence( stream, NULL );
status = readShortInteger( stream, &value );
if( cryptStatusOK( status ) && value != SIGNATURE_VERSION )
status = CRYPT_ERROR_BADDATA;
if( cryptStatusError( status ) )
return( status );
/* Read the issuer and serial number and hash algorithm ID */
queryInfo->iAndSStart = sMemBufPtr( stream );
queryInfo->iAndSLength = getObjectLength( queryInfo->iAndSStart,
sMemDataLeft( stream ) );
readUniversal( stream );
status = readAlgoID( stream, &queryInfo->hashAlgo );
if( cryptStatusError( status ) )
return( status );
/* Read the authenticated attributes if there are any present */
if( peekTag( stream ) == MAKE_CTAG( 0 ) )
{
queryInfo->attributeStart = sMemBufPtr( stream );
status = readConstructed( stream, &length, 0 );
if( cryptStatusError( status ) )
return( status );
queryInfo->attributeLength = ( int ) sizeofObject( length );
sSkip( stream, length );
}
}
else
/* If it's a cryptlib signature, read the key ID */
if( signatureType == SIGNATURE_CRYPTLIB )
{
long value;
/* Read the header */
readSequence( stream, NULL );
status = readShortInteger( stream, &value );
if( cryptStatusOK( status ) && value != SIGNATURE_EX_VERSION )
status = CRYPT_ERROR_BADDATA;
if( cryptStatusError( status ) )
return( status );
/* Read the key ID and hash algorithm identifier */
readOctetStringTag( stream, queryInfo->keyID,
&queryInfo->keyIDlength, CRYPT_MAX_HASHSIZE,
MAKE_CTAG_PRIMITIVE( CTAG_SI_SKI ) );
status = readAlgoID( stream, &queryInfo->hashAlgo );
if( cryptStatusError( status ) )
return( status );
}
else
assert( signatureType == SIGNATURE_CMS );
/* Read the CMS/cryptlib signature algorithm and start of the signature */
readAlgoID( stream, &queryInfo->cryptAlgo );
status = readOctetStringHole( stream, &queryInfo->dataLength,
DEFAULT_TAG );
if( cryptStatusOK( status ) )
queryInfo->dataStart = sMemBufPtr( stream );
return( status );
}
/****************************************************************************
* *
* Object Query Routines *
* *
****************************************************************************/
/* Read the type and start of a cryptlib object */
static int readObjectType( STREAM *stream, CRYPT_OBJECT_TYPE *objectType,
int *length, CRYPT_FORMAT_TYPE *formatType )
{
const long startPos = stell( stream );
int tag, status;
/* Get the type and length information. We can't use getObjectLength()
because the stream will typically have an unknown size (the higher-
level routines which call this function don't know the size of the
object they have until the queryObject() call has told them */
*formatType = CRYPT_FORMAT_CRYPTLIB;
*objectType = CRYPT_OBJECT_NONE;
*length = getObjectLength( sMemBufPtr( stream ),
sMemDataLeft( stream ) );
tag = readTag( stream );
if( tag == BER_SEQUENCE )
{
long value;
/* This could be a signature or a PKC-encrypted key. Read the
length and see what follows */
readShortLength( stream ); /* Skip previous length */
status = readShortInteger( stream, &value );
if( cryptStatusError( status ) )
return( status );
if( value == KEYTRANS_VERSION || value == KEYTRANS_EX_VERSION )
*objectType = CRYPT_OBJECT_PKCENCRYPTED_KEY;
else
if( value == SIGNATURE_VERSION || value == SIGNATURE_EX_VERSION )
*objectType = CRYPT_OBJECT_SIGNATURE;
else
{
*objectType = CRYPT_OBJECT_NONE;
return( CRYPT_ERROR_BADDATA );
}
if( value == KEYTRANS_VERSION || value == SIGNATURE_VERSION )
*formatType = CRYPT_FORMAT_CMS;
}
else
{
switch( tag )
{
case MAKE_CTAG( CTAG_RI_KEYAGREE ):
*objectType = CRYPT_OBJECT_KEYAGREEMENT;
break;
case MAKE_CTAG( CTAG_RI_PWRI ):
*objectType = CRYPT_OBJECT_ENCRYPTED_KEY;
break;
default:
*objectType = CRYPT_OBJECT_NONE;
if( tag > MAKE_CTAG( CTAG_RI_PWRI ) && \
tag <= MAKE_CTAG( CTAG_RI_MAX ) )
/* This is probably a new RecipientInfo type, skip it */
break;
return( CRYPT_ERROR_BADDATA );
}
}
return( sseek( stream, startPos ) );
}
/* Low-level object query function. This is used by a number of library
routines to get information on objects at a lower level than that provided
by cryptQueryObject() (for example the enveloping functions use it to
determine whether there is enough data available to allow a full
cryptQueryObject()). At this level the stream error code (which is
independant of the crypt error code returned by the ASN.1 routines) is
available to provide more information via sGetError().
Note that this function doens't perform a full check of all the fields in
an object, all it does is extract enough information from the start to
satisfy the query, and confirm that there's enough data in the stream to
contain the rest of the non-payload portion of the object. The
appropriate import function checks the validity of the entire object, but
has side-effects such as creating encryption contexts and/or performing
signature checks as part of the import function. It's not really possible
to check the validity of the octet or bit string which makes up an
encrypted session key or signature without actually performing the import,
so once we've read the rest of the header we just make sure the final
octet or bit string is complete without checking its validity */
int queryObject( STREAM *stream, QUERY_INFO *queryInfo )
{
CRYPT_FORMAT_TYPE formatType;
CRYPT_OBJECT_TYPE objectType;
int startPos = ( int ) stell( stream ), length, status;
/* Clear the return value and determine the object type */
memset( queryInfo, 0, sizeof( QUERY_INFO ) );
status = readObjectType( stream, &objectType, &length, &formatType );
if( cryptStatusError( status ) )
return( status );
/* Call the appropriate routine to find out more about the object */
switch( objectType )
{
case CRYPT_OBJECT_ENCRYPTED_KEY:
status = readKEKInfo( stream, queryInfo );
break;
case CRYPT_OBJECT_PKCENCRYPTED_KEY:
status = readKeyTransInfo( stream, queryInfo );
break;
case CRYPT_OBJECT_KEYAGREEMENT:
status = readKeyAgreeInfo( stream, queryInfo, NULL );
break;
case CRYPT_OBJECT_SIGNATURE:
status = readSignature( stream, queryInfo,
( formatType == CRYPT_FORMAT_CRYPTLIB ) ? \
SIGNATURE_CRYPTLIB : SIGNATURE_CMS,
CRYPT_ALGO_NONE );
break;
case CRYPT_OBJECT_NONE:
/* New, unrecognised RecipientInfo type */
status = readUniversal( stream );
break;
default:
assert( NOTREACHED );
}
if( cryptStatusOK( status ) )
{
queryInfo->formatType = formatType;
queryInfo->type = objectType;
queryInfo->size = length;
}
/* Sometimes there's extra information (such as an encrypted key or
signature) which we don't read since it's passed directly to the
decrypt function, so if there's any unread data left in the header we
seek over it to make sure everything we need is in the buffer. Since
a length-limited stream is used by the enveloping routines, we return
an underflow error if the object isn't entirely present */
if( cryptStatusOK( status ) && \
length > stell( stream ) - startPos && \
sSkip( stream, length - ( stell( stream ) - startPos ) ) != CRYPT_OK )
status = CRYPT_ERROR_UNDERFLOW;
/* Return to the start of the object in case the caller wants to read it
from the stream following the query */
sseek( stream, startPos );
return( status );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -