📄 envelope.c
字号:
/****************************************************************************
* *
* cryptlib Enveloping Routines *
* Copyright Peter Gutmann 1996-2001 *
* *
****************************************************************************/
#include <stdlib.h>
#include <string.h>
#if defined( INC_ALL )
#include "asn1.h"
#include "asn1objs.h"
#include "asn1oid.h"
#include "envelope.h"
#elif defined( INC_CHILD )
#include "../keymgmt/asn1.h"
#include "../keymgmt/asn1objs.h"
#include "../keymgmt/asn1oid.h"
#include "../envelope/envelope.h"
#else
#include "keymgmt/asn1.h"
#include "keymgmt/asn1objs.h"
#include "keymgmt/asn1oid.h"
#include "envelope/envelope.h"
#endif /* Compiler-specific includes */
/****************************************************************************
* *
* Utility Functions *
* *
****************************************************************************/
/* Check that a requested algorithm type is valid with enveloped data */
static int checkCryptAlgo( const CRYPT_ALGO cryptAlgo,
const CRYPT_ALGO cryptMode )
{
return( checkAlgoID( cryptAlgo, cryptMode ) ? \
CRYPT_OK : CRYPT_ERROR_NOTAVAIL );
}
static int checkHashAlgo( const CRYPT_ALGO hashAlgo )
{
return( checkAlgoID( hashAlgo, CRYPT_MODE_NONE ) ? \
CRYPT_OK : CRYPT_ERROR_NOTAVAIL );
}
/* Get the OID for a CMS content type. If no type is explicitly given, we
assume raw data */
static const struct {
const CRYPT_CONTENT_TYPE contentType;
const BYTE *oid;
} contentOIDs[] = {
{ CRYPT_CONTENT_DATA, OID_CMS_DATA },
{ CRYPT_CONTENT_SIGNEDDATA, OID_CMS_SIGNEDDATA },
{ CRYPT_CONTENT_ENVELOPEDDATA, OID_CMS_ENVELOPEDDATA },
{ CRYPT_CONTENT_SIGNEDANDENVELOPEDDATA, MKOID( "\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x07\x04" ) },
{ CRYPT_CONTENT_DIGESTEDDATA, OID_CMS_DIGESTEDDATA },
{ CRYPT_CONTENT_ENCRYPTEDDATA, OID_CMS_ENCRYPTEDDATA },
{ CRYPT_CONTENT_COMPRESSEDDATA, OID_CMS_COMPRESSEDDATA },
{ CRYPT_CONTENT_TSTINFO, MKOID( "\x06\x0B\x2A\x86\x48\x86\xF7\x0D\x01\x09\x10\x01\x04" ) },
{ CRYPT_CONTENT_SPCINDIRECTDATACONTEXT, OID_MS_SPCINDIRECTDATACONTEXT },
{ 0, NULL }
};
static const BYTE *getContentOID( const CRYPT_CONTENT_TYPE contentType )
{
int i;
for( i = 0; contentOIDs[ i ].oid != NULL; i++ )
if( contentOIDs[ i ].contentType == contentType )
return( contentOIDs[ i ].oid );
assert( NOTREACHED );
return( NULL ); /* Get rid of compiler warning */
}
/* Copy as much information from the auxiliary buffer to the main buffer as
possible. There are two variants of this function, one which copies
straight from the auxiliary buffer, the second which synchronizes the
auxStream status with the auxiliary buffer and then copies the data
across */
int copyFromAuxBuffer( ENVELOPE_INFO *envelopeInfoPtr )
{
int bytesCopied, dataLeft;
/* Copy as much as we can across */
bytesCopied = min( envelopeInfoPtr->bufSize - envelopeInfoPtr->bufPos,
envelopeInfoPtr->auxBufPos );
memcpy( envelopeInfoPtr->buffer + envelopeInfoPtr->bufPos,
envelopeInfoPtr->auxBuffer, bytesCopied );
envelopeInfoPtr->bufPos += bytesCopied;
/* If there's anything left, move it down in the buffer */
dataLeft = envelopeInfoPtr->auxBufPos - bytesCopied;
if( dataLeft )
memmove( envelopeInfoPtr->auxBuffer, envelopeInfoPtr->auxBuffer + bytesCopied,
dataLeft );
envelopeInfoPtr->auxBufPos = dataLeft;
/* Rewind the memory stream to the new end of the data */
sseek( &envelopeInfoPtr->auxStream, dataLeft );
return( dataLeft );
}
int copyFromAuxStream( ENVELOPE_INFO *envelopeInfoPtr )
{
int auxStreamSize = ( int ) stell( &envelopeInfoPtr->auxStream );
if( sGetStatus( &envelopeInfoPtr->auxStream ) != CRYPT_OK )
return( sGetStatus( &envelopeInfoPtr->auxStream ) );
envelopeInfoPtr->auxBufPos = auxStreamSize;
return( copyFromAuxBuffer( envelopeInfoPtr ) );
}
/****************************************************************************
* *
* Envelope Pre/Post-processing Functions *
* *
****************************************************************************/
/* The following functions take care of pre/post-processing of envelope data
during the enveloping process */
static int processKeyexchangeActions( ENVELOPE_INFO *envelopeInfoPtr )
{
CRYPT_DEVICE iCryptDevice = CRYPT_ERROR;
ACTION_LIST *actionListPtr;
BYTE originatorDomainParams[ CRYPT_MAX_HASHSIZE ];
int totalSize, originatorDomainParamSize = 0, status;
/* If there's an originator chain present, get the originator's domain
parameters and if the key is tied to a device, get the device's handle
so we can create the session key object in it */
if( envelopeInfoPtr->iOriginatorChain != CRYPT_ERROR )
{
RESOURCE_DATA msgData;
setResourceData( &msgData, originatorDomainParams,
CRYPT_MAX_HASHSIZE );
status = krnlSendMessage( envelopeInfoPtr->iOriginatorChain,
RESOURCE_IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_IATTRIBUTE_DOMAINPARAMS );
if( cryptStatusError( status ) )
return( status );
originatorDomainParamSize = msgData.length;
status = krnlSendMessage( envelopeInfoPtr->iOriginatorChain,
RESOURCE_IMESSAGE_GETDEPENDENT, &iCryptDevice,
OBJECT_TYPE_DEVICE );
if( cryptStatusError( status ) )
iCryptDevice = CRYPT_ERROR;
}
/* Create the session/MAC key if necessary */
if( envelopeInfoPtr->actionList == NULL )
{
MESSAGE_CREATEOBJECT_INFO createInfo;
int status;
/* Create a default encryption action and add it to the action
list */
setMessageCreateObjectInfo( &createInfo,
( envelopeInfoPtr->usage == ACTION_CRYPT ) ? \
envelopeInfoPtr->defaultAlgo : \
envelopeInfoPtr->defaultMAC );
status = krnlSendMessage( ( iCryptDevice != CRYPT_ERROR ) ? \
iCryptDevice : SYSTEM_OBJECT_HANDLE,
RESOURCE_IMESSAGE_DEV_CREATEOBJECT,
&createInfo, OBJECT_TYPE_CONTEXT );
if( cryptStatusOK( status ) )
{
status = krnlSendMessage( createInfo.cryptHandle,
RESOURCE_IMESSAGE_CTX_GENKEY,
NULL, FALSE );
if( cryptStatusOK( status ) && \
addAction( &envelopeInfoPtr->actionList,
envelopeInfoPtr->usage,
createInfo.cryptHandle ) == NULL )
status = CRYPT_ERROR_MEMORY;
if( cryptStatusError( status ) )
krnlSendNotifier( createInfo.cryptHandle,
RESOURCE_IMESSAGE_DECREFCOUNT );
}
if( cryptStatusError( status ) )
return( status );
}
else
{
/* If the session key/MAC context is tied to a device, get its handle
so we can check that all key exchange objects are also in the same
device */
status = krnlSendMessage( envelopeInfoPtr->actionList->iCryptHandle,
RESOURCE_MESSAGE_GETDEPENDENT,
&iCryptDevice, OBJECT_TYPE_DEVICE );
if( cryptStatusError( status ) )
iCryptDevice = CRYPT_ERROR;
}
/* Notify the kernel that the session key/MAC context is attached to the
envelope. This is an internal object used only by the envelope so we
tell the kernel not to increment its reference count when it attaches
it */
krnlSendMessage( envelopeInfoPtr->objectHandle,
RESOURCE_IMESSAGE_SETDEPENDENT,
&envelopeInfoPtr->actionList->iCryptHandle,
SETDEP_OPTION_NOINCREF );
/* Now walk down the list of key exchange actions connecting each one to
the session key action and evaluating their size */
totalSize = 0;
for( actionListPtr = envelopeInfoPtr->preActionList;
actionListPtr != NULL; actionListPtr = actionListPtr->next )
{
int cryptAlgo;
/* If the session key/MAC context is tied to a device, make sure the
key exchange object is in the same device */
if( iCryptDevice != CRYPT_ERROR )
{
CRYPT_DEVICE iKeyexDevice;
status = krnlSendMessage( actionListPtr->iCryptHandle,
RESOURCE_MESSAGE_GETDEPENDENT,
&iKeyexDevice, OBJECT_TYPE_DEVICE );
if( cryptStatusError( status ) || iCryptDevice != iKeyexDevice )
return( CRYPT_ERROR_INVALID );
}
/* If it's a key agreement action, make sure there's originator info
present and that the domain parameters match */
if( actionListPtr->action == ACTION_KEYEXCHANGE_PKC && \
cryptStatusOK( krnlSendMessage( actionListPtr->iCryptHandle,
RESOURCE_IMESSAGE_CHECK, NULL,
RESOURCE_MESSAGE_CHECK_PKC_KA_EXPORT ) ) )
{
RESOURCE_DATA msgData;
BYTE domainParams[ CRYPT_MAX_HASHSIZE ];
if( !originatorDomainParamSize )
{
setErrorInfo( envelopeInfoPtr, CRYPT_ENVINFO_ORIGINATOR,
CRYPT_ERRTYPE_ATTR_ABSENT );
return( CRYPT_ERROR_NOTINITED );
}
setResourceData( &msgData, domainParams, CRYPT_MAX_HASHSIZE );
status = krnlSendMessage( actionListPtr->iCryptHandle,
RESOURCE_IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_IATTRIBUTE_DOMAINPARAMS );
if( cryptStatusError( status ) )
return( status );
if( ( originatorDomainParamSize != msgData.length ) || \
memcmp( originatorDomainParams, domainParams,
originatorDomainParamSize ) )
{
setErrorInfo( envelopeInfoPtr, CRYPT_ENVINFO_ORIGINATOR,
CRYPT_ERRTYPE_CONSTRAINT );
return( CRYPT_ERROR_INVALID );
}
}
/* Remember that we now have a controlling action and connect the
controller to the subject */
envelopeInfoPtr->actionList->needsController = FALSE;
actionListPtr->associatedAction = envelopeInfoPtr->actionList;
/* Evaluate the size of the exported action. If it's a conventional
key exchange, we force the use of the CMS format since there's no
reason to use the cryptlib format. Even though it's not required
for encoding the length for DLP-based PKC's, we still evaluate it
anyway to check that everything will be OK later on */
status = iCryptExportKeyEx( NULL, &actionListPtr->encodedSize,
( actionListPtr->action == ACTION_KEYEXCHANGE ) ? \
CRYPT_FORMAT_CMS : envelopeInfoPtr->type,
envelopeInfoPtr->actionList->iCryptHandle,
actionListPtr->iCryptHandle,
( envelopeInfoPtr->iOriginatorChain != CRYPT_ERROR ) ? \
envelopeInfoPtr->iOriginatorChain : CRYPT_UNUSED );
if( cryptStatusOK( status ) )
status = krnlSendMessage( actionListPtr->iCryptHandle,
RESOURCE_IMESSAGE_GETATTRIBUTE,
&cryptAlgo, CRYPT_CTXINFO_ALGO );
if( cryptStatusError( status ) )
return( status );
if( cryptAlgo == CRYPT_ALGO_ELGAMAL )
/* If there are any key exchange actions which will result in
indefinite-length encodings present, we can't use a definite-
length encoding for the key exchange actions */
totalSize = CRYPT_UNUSED;
else
if( totalSize != CRYPT_UNUSED )
totalSize += actionListPtr->encodedSize;
}
envelopeInfoPtr->cryptActionSize = totalSize;
return( CRYPT_OK );
}
static int preEnvelopeEncrypt( ENVELOPE_INFO *envelopeInfoPtr )
{
/* If there's originator info present, find out what it'll take to encode
it into the envelope header */
if( envelopeInfoPtr->iOriginatorChain != CRYPT_ERROR )
{
RESOURCE_DATA msgData;
int status;
/* Determine how big the originator cert chain will be */
setResourceData( &msgData, NULL, 0 );
status = krnlSendMessage( envelopeInfoPtr->iOriginatorChain,
RESOURCE_IMESSAGE_GETATTRIBUTE_S, &msgData,
CRYPT_IATTRIBUTE_CERTSET );
if( cryptStatusError( status ) )
return( status );
envelopeInfoPtr->extraDataSize = msgData.length;
/* If we have very long originator cert chains the auxBuffer may not
be large enough to contain the resulting chain, so we have to
expand it to handle the chain */
if( envelopeInfoPtr->auxBufSize < envelopeInfoPtr->extraDataSize + 64 )
{
free( envelopeInfoPtr->auxBuffer );
if( ( envelopeInfoPtr->auxBuffer = \
malloc( envelopeInfoPtr->extraDataSize + 64 ) ) == NULL )
return( CRYPT_ERROR_MEMORY );
envelopeInfoPtr->auxBufSize = envelopeInfoPtr->extraDataSize + 64;
}
}
/* If there are key exchange actions, connect them to the session key/MAC
action */
if( envelopeInfoPtr->preActionList != NULL )
{
int status;
status = processKeyexchangeActions( envelopeInfoPtr );
if( cryptStatusError( status ) )
return( status );
}
return( CRYPT_OK );
}
static int preEnvelopeSign( ENVELOPE_INFO *envelopeInfoPtr )
{
ACTION_LIST *actionListPtr;
int largestSignatureSize = 0, status;
/* If we're generating a detached signature, the content is supplied
externally and has zero size */
if( envelopeInfoPtr->flags & ENVELOPE_DETACHED_SIG )
envelopeInfoPtr->payloadSize = 0;
/* Evaluate the size of each signature action */
for( actionListPtr = envelopeInfoPtr->postActionList; actionListPtr != NULL;
actionListPtr = actionListPtr->next )
{
int cryptAlgo, signatureSize, signingAttributes;
/* If it's a CMS envelope we have to write the signing cert chain
alongside the signatures as extra data unless it's explicitly
excluded, so we record how large the info will be for later. In
addition we have to match the content-type in the authenticated
attributes with the signed content type if it's anything other
than 'data' (the data content-type is added automatically) */
if( envelopeInfoPtr->type == CRYPT_FORMAT_CMS || \
envelopeInfoPtr->type == CRYPT_FORMAT_SMIME )
{
RESOURCE_DATA msgData;
/* Determine how big the cert chain will be unless we're
explicitly not including signing certs */
if( !( envelopeInfoPtr->flags & ENVELOPE_NOSIGNINGCERTS ) )
{
setResourceData( &msgData, NULL, 0 );
status = krnlSendMessage( actionListPtr->iCryptHandle,
RESOURCE_IMESSAGE_GETATTRIBUTE_S, &msgData,
CRYPT_IATTRIBUTE_CERTSET );
if( cryptStatusError( status ) )
return( status );
envelopeInfoPtr->extraDataSize += msgData.length;
if( msgData.length > largestSignatureSize )
largestSignatureSize = msgData.length;
}
/* If there's no content-type present and the signed content
type isn't 'data' or it's an S/MIME envelope, create signing
attributes to hold the content-type and smimeCapabilities.
Then, make sure that the content-type in the attributes
matches the actual content type */
if( actionListPtr->iExtraData == CRYPT_ERROR && \
( envelopeInfoPtr->contentType != CRYPT_CONTENT_DATA || \
envelopeInfoPtr->type == CRYPT_FORMAT_SMIME ) )
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -