📄 asn1objs.c
字号:
/****************************************************************************
* *
* ASN.1 Object Management Routines *
* Copyright Peter Gutmann 1992-2001 *
* *
****************************************************************************/
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if defined( INC_ALL ) || defined( INC_CHILD )
#include "asn1.h"
#include "asn1objs.h"
#include "asn1oid.h"
#else
#include "keymgmt/asn1.h"
#include "keymgmt/asn1objs.h"
#include "keymgmt/asn1oid.h"
#endif /* Compiler-specific includes */
/* Context-specific tags for the KEK record */
enum { CTAG_KK_DA };
/* Context-specific tags for the KeyTrans record */
enum { CTAG_KT_SKI };
/* Context-specific tags for the KeyAgree/Fortezza record */
enum { CTAG_KA_ORIG, CTAG_KA_UKM };
/* Context-specific tags for the RecipientInfo record. KeyTrans has no tag
(actually it has an implied 0 tag because of CMS misdesign, so the other
tags start at 1). To allow for addition of new RI types we permit (but
ignore) objects tagged up to CTAG_RI_MAX */
enum { CTAG_RI_KEYAGREE = 1, CTAG_RI_KEK, CTAG_RI_PWRI, CTAG_RI_MAX = 9 };
/* Context-specific tags for the SignerInfo record */
enum { CTAG_SI_SKI };
/* CMS version numbers for various objects */
#define KEYTRANS_VERSION 0
#define PWRI_VERSION 0
#define KEYTRANS_EX_VERSION 2
#define KEK_VERSION 4
#define SIGNATURE_VERSION 1
#define SIGNATURE_EX_VERSION 3
/****************************************************************************
* *
* Message Digest Routines *
* *
****************************************************************************/
/* Determine the encoded size of a message digest value */
int sizeofMessageDigest( const CRYPT_ALGO hashAlgo, const int hashSize )
{
return( ( int ) sizeofObject( sizeofAlgoID( hashAlgo ) + \
( int ) sizeofObject( hashSize ) ) );
}
/* Write a message digest value */
int writeMessageDigest( STREAM *stream, const CRYPT_ALGO hashAlgo,
const void *hash, const int hashSize )
{
writeSequence( stream, sizeofAlgoID( hashAlgo ) + \
( int ) sizeofObject( hashSize ) );
writeAlgoID( stream, hashAlgo );
return( writeOctetString( stream, hash, hashSize, DEFAULT_TAG ) );
}
/* Read a message digest value */
int readMessageDigest( STREAM *stream, CRYPT_ALGO *hashAlgo, void *hash,
int *hashSize )
{
readSequence( stream, NULL );
readAlgoID( stream, hashAlgo );
return( readOctetString( stream, hash, hashSize, CRYPT_MAX_HASHSIZE ) );
}
/****************************************************************************
* *
* Conventionally-Encrypted Key Routines *
* *
****************************************************************************/
/* The OID for the PKCS #5 v2.0 key derivation function and the parameterised
PWRI key wrap algorithm */
#define OID_PBKDF2 MKOID( "\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x05\x0C" )
#define OID_PWRIKEK MKOID( "\x06\x0B\x2A\x86\x48\x86\xF7\x0D\x01\x09\x10\x03\x09" )
/* Write a PBKDF2 key derivation record */
static int writeKeyDerivationInfo( STREAM *stream,
const CRYPT_CONTEXT iCryptContext )
{
RESOURCE_DATA msgData;
BYTE salt[ CRYPT_MAX_HASHSIZE ];
int keySetupIterations, derivationInfoSize, status;
/* Get the key derivation information */
status = krnlSendMessage( iCryptContext, RESOURCE_IMESSAGE_GETATTRIBUTE,
&keySetupIterations,
CRYPT_CTXINFO_KEYING_ITERATIONS );
if( status == CRYPT_ERROR_NOTFOUND )
/* If the key wasn't derived from a password, don't go any further */
return( CRYPT_OK );
if( cryptStatusOK( status ) )
{
setResourceData( &msgData, salt, CRYPT_MAX_HASHSIZE );
status = krnlSendMessage( iCryptContext,
RESOURCE_IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_CTXINFO_KEYING_SALT );
}
if( cryptStatusError( status ) )
return( status );
derivationInfoSize = ( int ) sizeofObject( msgData.length ) + \
sizeofShortInteger( ( long ) keySetupIterations );
/* Write the PBKDF2 information */
writeConstructed( stream, sizeofOID( OID_PBKDF2 ) +
( int ) sizeofObject( derivationInfoSize ), CTAG_KK_DA );
writeOID( stream, OID_PBKDF2 );
writeSequence( stream, derivationInfoSize );
writeOctetString( stream, msgData.data, msgData.length, DEFAULT_TAG );
writeShortInteger( stream, keySetupIterations, DEFAULT_TAG );
zeroise( salt, CRYPT_MAX_HASHSIZE );
return( sGetStatus( stream ) );
}
/* Read a PBKDF2 key derivation record */
static int readKeyDerivationInfo( STREAM *stream, QUERY_INFO *queryInfo )
{
long endPos, value;
int length, status;
/* Read the outer wrapper and key derivation algorithm OID */
readConstructed( stream, NULL, CTAG_KK_DA );
status = readOID( stream, OID_PBKDF2 );
if( cryptStatusError( status ) )
return( status );
/* Read the PBKDF2 parameters, limiting the salt and iteration count to
sane values */
readSequence( stream, &length );
endPos = stell( stream ) + length;
status = readOctetString( stream, queryInfo->salt,
&queryInfo->saltLength, CRYPT_MAX_HASHSIZE );
if( cryptStatusError( status ) )
return( status );
status = readShortInteger( stream, &value );
if( cryptStatusError( status ) )
return( status );
if( value > MAX_KEYSETUP_ITERATIONS )
return( CRYPT_ERROR_BADDATA );
queryInfo->keySetupIterations = ( int ) value;
queryInfo->keySetupAlgo = CRYPT_ALGO_HMAC_SHA;
if( stell( stream ) < endPos )
sseek( stream, endPos );
return( sGetStatus( stream ) );
}
/* Write a KEKRecipientInfo (= PasswordRecipientInfo) record */
int writeKEKInfo( STREAM *stream, const CRYPT_CONTEXT iCryptContext,
const BYTE *encryptedKey, const int encryptedKeyLength )
{
STREAM localStream;
BYTE derivationInfo[ CRYPT_MAX_HASHSIZE + 32 ], kekInfo[ 128 ];
int derivationInfoSize, kekInfoSize, status;
/* Determine the size of the derivation info and KEK info. To save
evaluating it twice in a row and because it's short, we just write
it to local buffers */
sMemOpen( &localStream, derivationInfo, CRYPT_MAX_HASHSIZE + 32 );
status = writeKeyDerivationInfo( &localStream, iCryptContext );
derivationInfoSize = ( int ) stell( &localStream );
sMemDisconnect( &localStream );
if( cryptStatusError( status ) )
return( status );
sMemOpen( &localStream, kekInfo, 128 );
#if 1 /* Post-June 2001 PWRI draft */
writeSequence( &localStream,
sizeofOID( OID_PWRIKEK ) + \
sizeofContextAlgoID( iCryptContext, CRYPT_ALGO_NONE,
ALGOID_FLAG_NONE ) );
writeOID( &localStream, OID_PWRIKEK );
#endif /* Post-June 2001 PWRI draft */
status = writeContextAlgoID( &localStream, iCryptContext, CRYPT_ALGO_NONE,
ALGOID_FLAG_NONE );
kekInfoSize = ( int ) stell( &localStream );
sMemDisconnect( &localStream );
if( cryptStatusError( status ) )
return( status );
/* Write the algorithm identifiers and encrypted key */
writeConstructed( stream, sizeofShortInteger( PWRI_VERSION ) +
derivationInfoSize + kekInfoSize +
( int ) sizeofObject( encryptedKeyLength ),
CTAG_RI_PWRI );
writeShortInteger( stream, PWRI_VERSION, DEFAULT_TAG );
if( derivationInfoSize )
swrite( stream, derivationInfo, derivationInfoSize );
swrite( stream, kekInfo, kekInfoSize );
writeOctetString( stream, encryptedKey, encryptedKeyLength, DEFAULT_TAG );
return( sGetStatus( stream ) );
}
/* Read a KEKRecipientInfo (= PasswordRecipientInfo) record */
int readKEKInfo( STREAM *stream, QUERY_INFO *queryInfo )
{
long value;
int status;
/* Clear return value */
memset( queryInfo, 0, sizeof( QUERY_INFO ) );
/* Read the header */
readConstructed( stream, NULL, CTAG_RI_PWRI );
status = readShortInteger( stream, &value );
if( cryptStatusError( status ) )
return( status );
if( value != PWRI_VERSION )
return( CRYPT_ERROR_BADDATA );
/* Read the optional KEK derivation info and KEK algorithm info */
if( peekTag( stream ) == MAKE_CTAG( CTAG_KK_DA ) )
status = readKeyDerivationInfo( stream, queryInfo );
if( cryptStatusOK( status ) )
{
const long position = stell( stream );
/* Because of the last-minute change in the PWRI format before the
RFC was published, older versions of cryptlib generate a slightly
different KEK algorithm info format. To handle this, we read
part of the AlgorithmIdentifier and, if it's the newer format,
skip the extra level of wrapping */
readSequence( stream, NULL );
status = readOID( stream, OID_PWRIKEK );
if( cryptStatusError( status ) )
{
/* It's the original format, clear the stream error state caused
by the failed PWRI KEK OID read and try again */
sClearError( stream );
sseek( stream, position );
}
status = readContextAlgoID( stream, NULL, queryInfo, DEFAULT_TAG );
}
if( cryptStatusError( status ) )
return( status );
/* Finally, read the start of the encrypted key. We never read the data
itself since it's passed directly to the decrypt function */
status = readOctetStringHole( stream, &queryInfo->dataLength,
DEFAULT_TAG );
if( cryptStatusOK( status ) )
{
queryInfo->dataStart = sMemBufPtr( stream );
if( queryInfo->dataLength < bitsToBytes( MIN_KEYSIZE_BITS ) )
/* We shouldn't be using a key this short, we can't actually
load it anyway but a CRYPT_ERROR_BADDATA at this point
provides more meaningful information to the caller */
status = CRYPT_ERROR_BADDATA;
}
return( status );
}
/****************************************************************************
* *
* Public-key Encrypted Key Routines *
* *
****************************************************************************/
/* Write a KeyTransRecipientInfo record */
int writeKeyTransInfo( STREAM *stream, const CRYPT_CONTEXT iCryptContext,
const BYTE *buffer, const int length,
const void *auxInfo, const int auxInfoLength,
const RECIPIENT_TYPE recipientType )
{
const int dataLength = \
sizeofContextAlgoID( iCryptContext, CRYPT_ALGO_NONE,
ALGOID_FLAG_ALGOID_ONLY ) + \
( int ) sizeofObject( length );
if( recipientType == RECIPIENT_CRYPTLIB )
{
RESOURCE_DATA msgData;
BYTE keyID[ CRYPT_MAX_HASHSIZE ];
setResourceData( &msgData, keyID, CRYPT_MAX_HASHSIZE );
krnlSendMessage( iCryptContext, RESOURCE_IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_IATTRIBUTE_KEYID );
writeSequence( stream, sizeofShortInteger( KEYTRANS_EX_VERSION ) +
( int ) sizeofObject( msgData.length ) + dataLength );
writeShortInteger( stream, KEYTRANS_EX_VERSION, DEFAULT_TAG );
writeOctetString( stream, msgData.data, msgData.length, CTAG_KT_SKI );
}
else
{
writeSequence( stream, sizeofShortInteger( KEYTRANS_VERSION ) +
auxInfoLength + dataLength );
writeShortInteger( stream, KEYTRANS_VERSION, DEFAULT_TAG );
swrite( stream, auxInfo, auxInfoLength );
}
writeContextAlgoID( stream, iCryptContext, CRYPT_ALGO_NONE,
ALGOID_FLAG_ALGOID_ONLY );
writeOctetString( stream, buffer, length, DEFAULT_TAG );
return( sGetStatus( stream ) );
}
/* Read a KeyTransRecipientInfo record */
int readKeyTransInfo( STREAM *stream, QUERY_INFO *queryInfo )
{
long value;
int status;
/* Clear return value */
memset( queryInfo, 0, sizeof( QUERY_INFO ) );
queryInfo->formatType = CRYPT_FORMAT_CRYPTLIB;
/* Read the header and version number */
readSequence( stream, NULL );
status = readShortInteger( stream, &value );
if( cryptStatusError( status ) )
return( status );
if( value < 0 || value > KEYTRANS_EX_VERSION )
return( CRYPT_ERROR_BADDATA );
/* Read the key ID and PKC algorithm information */
if( value != KEYTRANS_EX_VERSION )
{
queryInfo->formatType = CRYPT_FORMAT_CMS;
queryInfo->iAndSStart = sMemBufPtr( stream );
queryInfo->iAndSLength = getObjectLength( queryInfo->iAndSStart,
sMemDataLeft( stream ) );
status = readUniversal( stream );
}
else
status = readOctetStringTag( stream, queryInfo->keyID,
&queryInfo->keyIDlength, CRYPT_MAX_HASHSIZE,
MAKE_CTAG_PRIMITIVE( CTAG_KT_SKI ) );
if( cryptStatusOK( status ) )
status = readAlgoID( stream, &queryInfo->cryptAlgo );
if( cryptStatusError( status ) )
return( status );
/* Finally, read the start of the encrypted key. We never read the data
itself since it's passed directly to the PKC decrypt function */
status = readOctetStringHole( stream, &queryInfo->dataLength,
DEFAULT_TAG );
if( cryptStatusOK( status ) )
queryInfo->dataStart = sMemBufPtr( stream );
return( status );
}
/****************************************************************************
* *
* Key Agreement Routines *
* *
****************************************************************************/
/* Write a KeyAgreeRecipientInfo (=FortezzaRecipientInfo) record */
int writeKeyAgreeInfo( STREAM *stream, const CRYPT_CONTEXT iCryptContext,
const void *wrappedKey, const int wrappedKeyLength,
const void *ukm, const int ukmLength,
const void *auxInfo, const int auxInfoLength )
{
RESOURCE_DATA msgData;
BYTE rKeyID[ 1024 ];
int rKeyIDlength, recipientKeyInfoSize, status;
/* Get the recipients key ID and determine how large the recipient key
info will be */
setResourceData( &msgData, rKeyID, 1024 );
status = krnlSendMessage( iCryptContext,
RESOURCE_MESSAGE_GETATTRIBUTE_S, &msgData,
CRYPT_CERTINFO_SUBJECTKEYIDENTIFIER );
if( cryptStatusError( status ) )
return( status );
rKeyIDlength = msgData.length;
recipientKeyInfoSize = ( int ) ( \
sizeofObject( sizeofObject( rKeyIDlength ) ) + \
sizeofObject( wrappedKeyLength ) );
/* Write the FortezzaRecipientInfo header and version number */
writeConstructed( stream, sizeofShortInteger( 3 ) +
( int ) sizeofObject( sizeofObject( auxInfoLength ) ) +
( int ) sizeofObject( sizeofObject( ukmLength ) ) +
sizeofOID( ALGOID_FORTEZZA_KEYWRAP ) +
( int ) sizeofObject( sizeofObject( recipientKeyInfoSize ) ),
CTAG_RI_KEYAGREE );
writeShortInteger( stream, 3, DEFAULT_TAG );
/* Write the originator's keyIdentifier, UKM, and Fortezza key wrap OID */
writeConstructed( stream, ( int ) sizeofObject( auxInfoLength ),
CTAG_KA_ORIG );
writeOctetString( stream, auxInfo, auxInfoLength, 0 );
writeConstructed( stream, ( int ) sizeofObject( ukmLength ),
CTAG_KA_UKM );
writeOctetString( stream, ukm, ukmLength, DEFAULT_TAG );
swrite( stream, ALGOID_FORTEZZA_KEYWRAP,
sizeofOID( ALGOID_FORTEZZA_KEYWRAP ) );
/* Write the recipient keying info */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -