📄 cryptenv.c
字号:
/****************************************************************************
* *
* cryptlib Enveloping Routines *
* Copyright Peter Gutmann 1996-2002 *
* *
****************************************************************************/
#include <stdlib.h>
#include <string.h>
#include "crypt.h"
#ifdef INC_ALL
#include "envelope.h"
#else
#include "envelope/envelope.h"
#endif /* Compiler-specific includes */
/* The default size for the envelope buffer and auxiliary buffer used as a
staging area for assembling information. Under DOS and Win16 they're
smaller because of memory and int size limitations */
#if defined( __MSDOS16__ )
#define DEFAULT_BUFFER_SIZE 8192
#elif defined( __WIN16__ )
#define DEFAULT_BUFFER_SIZE 16384
#else
#define DEFAULT_BUFFER_SIZE 32768
#endif /* OS-specific envelope size defines */
#define DEFAULT_AUXBUFFER_SIZE 8192
/****************************************************************************
* *
* Utility Functions *
* *
****************************************************************************/
/* Instantiate a cert chain from a collection of certs */
static int instantiateCertChain( const ENVELOPE_INFO *envelopeInfoPtr,
CONTENT_LIST *contentListItem )
{
MESSAGE_CREATEOBJECT_INFO createInfo;
int status;
/* Instantiate the cert chain. Since this isn't a true cert chain (in
the sense of being degenerate PKCS #7 SignedData) but only a
context-tagged SET OF Certificate, we notify the cert management code
of this when it performs the import */
setMessageCreateObjectIndirectInfo( &createInfo,
envelopeInfoPtr->auxBuffer, envelopeInfoPtr->auxBufSize );
createInfo.arg1 = CERTFORMAT_CERTSET;
if( contentListItem->issuerAndSerialNumber == NULL )
{
createInfo.arg2 = CRYPT_IKEYID_KEYID;
createInfo.strArg2 = contentListItem->keyID;
createInfo.strArgLen2 = contentListItem->keyIDsize;
}
else
{
createInfo.arg2 = CRYPT_IKEYID_ISSUERANDSERIALNUMBER;
createInfo.strArg2 = contentListItem->issuerAndSerialNumber;
createInfo.strArgLen2 = contentListItem->issuerAndSerialNumberSize;
}
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
RESOURCE_IMESSAGE_DEV_CREATEOBJECT_INDIRECT,
&createInfo, OBJECT_TYPE_CERTIFICATE );
if( cryptStatusError( status ) )
return( status );
contentListItem->iSigCheckKey = createInfo.cryptHandle;
return( CRYPT_OK );
}
/* Move the envelope component cursor */
static int moveCursor( ENVELOPE_INFO *envelopeInfoPtr, const int value )
{
if( envelopeInfoPtr->contentList == NULL )
return( CRYPT_ERROR_NOTFOUND ); /* Nothing to move the cursor to */
switch( value )
{
case CRYPT_CURSOR_FIRST:
envelopeInfoPtr->contentListCurrent = envelopeInfoPtr->contentList;
break;
case CRYPT_CURSOR_PREVIOUS:
if( envelopeInfoPtr->contentListCurrent == NULL || \
envelopeInfoPtr->contentListCurrent == envelopeInfoPtr->contentList )
return( CRYPT_ERROR_NOTFOUND );
else
{
CONTENT_LIST *contentListPtr = envelopeInfoPtr->contentList;
/* Find the previous element in the list */
while( contentListPtr->next != envelopeInfoPtr->contentListCurrent )
contentListPtr = contentListPtr->next;
envelopeInfoPtr->contentListCurrent = contentListPtr;
}
break;
case CRYPT_CURSOR_NEXT:
if( envelopeInfoPtr->contentListCurrent == NULL || \
envelopeInfoPtr->contentListCurrent->next == NULL )
return( CRYPT_ERROR_NOTFOUND );
envelopeInfoPtr->contentListCurrent = envelopeInfoPtr->contentListCurrent->next;
break;
case CRYPT_CURSOR_LAST:
envelopeInfoPtr->contentListCurrent = envelopeInfoPtr->contentList;
while( envelopeInfoPtr->contentListCurrent->next != NULL )
envelopeInfoPtr->contentListCurrent = envelopeInfoPtr->contentListCurrent->next;
break;
default:
return( CRYPT_ARGERROR_NUM1 );
}
return( CRYPT_OK );
}
/****************************************************************************
* *
* Envelope Attribute Handling Functions *
* *
****************************************************************************/
/* Handle data sent to or read from an envelope object */
static int processGetAttribute( ENVELOPE_INFO *envelopeInfoPtr,
void *messageDataPtr, const int messageValue )
{
CRYPT_HANDLE iCryptHandle;
MESSAGE_KEYMGMT_INFO getkeyInfo;
CONTENT_LIST *contentListItem;
int *valuePtr = ( int * ) messageDataPtr, status;
/* Generic attributes are valid for all envelope types */
if( messageValue == CRYPT_ATTRIBUTE_BUFFERSIZE )
{
*valuePtr = envelopeInfoPtr->bufSize;
return( CRYPT_OK );
}
if( messageValue == CRYPT_ATTRIBUTE_ERRORTYPE )
{
*valuePtr = envelopeInfoPtr->errorType;
return( CRYPT_OK );
}
if( messageValue == CRYPT_ATTRIBUTE_ERRORLOCUS )
{
*valuePtr = envelopeInfoPtr->errorLocus;
return( CRYPT_OK );
}
/* If we're de-enveloping PGP data, make sure the attribute is valid for
PGP envelopes. We can't perform this check via the ACLs because the
data type isn't known at envelope creation time, so there's a single
generic de-envelope type for which the ACLs allow the union of all
de-enveloping attribute types. The following check weeds out the ones
which don't work for PGP */
if( envelopeInfoPtr->type == CRYPT_FORMAT_PGP && \
messageValue == CRYPT_ENVINFO_SIGNATURE_EXTRADATA )
return( CRYPT_ARGERROR_VALUE );
/* Make sure the attribute is valid for this envelope type and state */
if( messageValue == CRYPT_ENVINFO_CURRENT_COMPONENT || \
messageValue == CRYPT_ENVINFO_SIGNATURE_RESULT || \
messageValue == CRYPT_ENVINFO_SIGNATURE || \
messageValue == CRYPT_ENVINFO_SIGNATURE_EXTRADATA )
{
if( !( envelopeInfoPtr->flags & ENVELOPE_ISDEENVELOPE ) )
return( CRYPT_ARGERROR_OBJECT );
/* The following check isn't strictly necessary since we can get some
information as soon as it's available, but it leads to less
confusion (for example without this check we can get signer info
long before we can get the signature results, which could be
misinterpreted to mean the signature is bad) and forces the caller
to do things cleanly */
if( envelopeInfoPtr->usage == ACTION_SIGN && \
envelopeInfoPtr->state != STATE_FINISHED )
return( CRYPT_ERROR_INCOMPLETE );
}
else
if( messageValue != CRYPT_ENVINFO_CONTENTTYPE && \
messageValue != CRYPT_ENVINFO_DETACHEDSIGNATURE )
return( CRYPT_ARGERROR_VALUE );
/* If we're querying something which resides in the content list, make
sure there's a content list present. If it's present but nothing is
selected, select the first entry */
if( ( messageValue == CRYPT_ENVINFO_CURRENT_COMPONENT || \
messageValue == CRYPT_ENVINFO_SIGNATURE || \
messageValue == CRYPT_ENVINFO_SIGNATURE_RESULT || \
messageValue == CRYPT_ENVINFO_SIGNATURE_EXTRADATA ) && \
envelopeInfoPtr->contentListCurrent == NULL )
{
if( envelopeInfoPtr->contentList == NULL )
return( CRYPT_ERROR_NOTFOUND );
envelopeInfoPtr->contentListCurrent = envelopeInfoPtr->contentList;
}
/* Handle the various information types */
switch( messageValue )
{
case CRYPT_ENVINFO_CURRENT_COMPONENT:
contentListItem = envelopeInfoPtr->contentListCurrent;
/* If we need something other than a private key or we need a
private key but there's no keyset present to fetch it from,
just report what we need and exit */
if( contentListItem->envInfo != CRYPT_ENVINFO_PRIVATEKEY || \
envelopeInfoPtr->iDecryptionKeyset == CRYPT_ERROR )
{
*valuePtr = contentListItem->envInfo;
return( CRYPT_OK );
}
/* There's a decryption keyset available, try and get the
required key from it. Since we're accessing the key by
(unique) key ID, there's no real need to specify a preference
for encryption keys.
Unlike sig.check keyset access, we retry the access every
time we're called because we may be talking to a device which
has a trusted authentication path which is outside our
control, so that the first read fails if the user hasn't
entered their PIN but a second read once they've entered it
will succeed */
if( contentListItem->issuerAndSerialNumber == NULL )
{
setMessageKeymgmtInfo( &getkeyInfo,
( contentListItem->formatType == CRYPT_FORMAT_PGP ) ? \
CRYPT_IKEYID_PGPKEYID : CRYPT_IKEYID_KEYID,
contentListItem->keyID,
contentListItem->keyIDsize, NULL, 0,
KEYMGMT_FLAG_NONE );
}
else
{
setMessageKeymgmtInfo( &getkeyInfo,
CRYPT_IKEYID_ISSUERANDSERIALNUMBER,
contentListItem->issuerAndSerialNumber,
contentListItem->issuerAndSerialNumberSize,
NULL, 0, KEYMGMT_FLAG_NONE );
}
status = krnlSendMessage( envelopeInfoPtr->iDecryptionKeyset,
RESOURCE_IMESSAGE_KEY_GETKEY, &getkeyInfo,
KEYMGMT_ITEM_PRIVATEKEY );
/* If we managed to get the private key (either bcause it wasn't
protected by a password if it's in a keyset or because it came
from a device), push it into the envelope. If the call
succeeds, this will import the session key and delete the
required-information list */
if( cryptStatusOK( status ) )
{
status = envelopeInfoPtr->addInfo( envelopeInfoPtr,
CRYPT_ENVINFO_PRIVATEKEY,
&getkeyInfo.cryptHandle, 0 );
krnlSendNotifier( getkeyInfo.cryptHandle,
RESOURCE_IMESSAGE_DECREFCOUNT );
}
/* If we got the key, there's nothing else needed. If we didn't,
we still return an OK status since the caller is asking us for
the resource which is required and not the status of any
background operation which was performed while trying to obtain
it */
*valuePtr = cryptStatusError( status ) ? \
envelopeInfoPtr->contentListCurrent->envInfo : \
CRYPT_ATTRIBUTE_NONE;
return( CRYPT_OK );
case CRYPT_ENVINFO_CONTENTTYPE:
if( envelopeInfoPtr->contentType == CRYPT_CONTENT_NONE )
return( CRYPT_ERROR_NOTFOUND );
*valuePtr = envelopeInfoPtr->contentType;
return( CRYPT_OK );
case CRYPT_ENVINFO_DETACHEDSIGNATURE:
/* If this isn't signed data or we haven't sorted out the content
details yet, we don't know whether it's a detached sig or
not */
if( envelopeInfoPtr->usage != ACTION_SIGN || \
envelopeInfoPtr->contentType == CRYPT_CONTENT_NONE )
return( CRYPT_ERROR_NOTFOUND );
*valuePtr = ( envelopeInfoPtr->flags & ENVELOPE_DETACHED_SIG ) ? \
TRUE : FALSE;
return( CRYPT_OK );
case CRYPT_ENVINFO_SIGNATURE_RESULT:
/* Make sure the content list item is of the appropriate type,
and if we've already done this one don't process it a second
time. This check is also performed by the addInfo() code, but
we duplicate it here to avoid having to do an unnecessary key
fetch for non-CMS signatures */
contentListItem = envelopeInfoPtr->contentListCurrent;
if( contentListItem->envInfo != CRYPT_ENVINFO_SIGNATURE )
return( CRYPT_ERROR_NOTFOUND );
if( contentListItem->processed )
{
*valuePtr = contentListItem->processingResult;
return( CRYPT_OK );
}
/* If there's an encoded cert chain present and it hasn't been
instantiated as a cert object yet, instantiate it now. We
don't check the return value since a failure isn't fatal, we
can still perform the sig.check with a user-supplied key */
if( contentListItem->iSigCheckKey == CRYPT_ERROR && \
envelopeInfoPtr->auxBuffer != NULL )
instantiateCertChain( envelopeInfoPtr, contentListItem );
/* If we don't have a sig.check key available (for example from a
CMS cert chain), make sure there's a keyset available to pull
the key from and get the owner ID */
if( contentListItem->iSigCheckKey == CRYPT_ERROR )
{
if( envelopeInfoPtr->iSigCheckKeyset == CRYPT_ERROR )
{
setErrorInfo( envelopeInfoPtr, CRYPT_ENVINFO_KEYSET_SIGCHECK,
CRYPT_ERRTYPE_ATTR_ABSENT );
return( CRYPT_ERROR_NOTINITED );
}
/* Try and get the key information. Since we're accessing
the key by (unique) key ID, there's no real need to
specify a preference for encryption keys */
if( contentListItem->issuerAndSerialNumber == NULL )
{
setMessageKeymgmtInfo( &getkeyInfo,
( contentListItem->formatType == CRYPT_FORMAT_PGP ) ? \
CRYPT_IKEYID_PGPKEYID : CRYPT_IKEYID_KEYID,
contentListItem->keyID,
contentListItem->keyIDsize, NULL, 0,
KEYMGMT_FLAG_NONE );
}
else
{
setMessageKeymgmtInfo( &getkeyInfo,
CRYPT_IKEYID_ISSUERANDSERIALNUMBER,
contentListItem->issuerAndSerialNumber,
contentListItem->issuerAndSerialNumberSize,
NULL, 0, KEYMGMT_FLAG_NONE );
}
status = krnlSendMessage( envelopeInfoPtr->iSigCheckKeyset,
RESOURCE_IMESSAGE_KEY_GETKEY, &getkeyInfo,
KEYMGMT_ITEM_PUBLICKEY );
if( cryptStatusError( status ) )
return( status );
iCryptHandle = getkeyInfo.cryptHandle;
}
/* Push the public key into the envelope, which performs the
signature check */
*valuePtr = envelopeInfoPtr->addInfo( envelopeInfoPtr,
CRYPT_ENVINFO_SIGNATURE,
&iCryptHandle, 0 );
if( contentListItem->iSigCheckKey == CRYPT_ERROR )
/* If it's a newly-created key and it wasn't used, discard
it */
krnlSendNotifier( iCryptHandle, RESOURCE_IMESSAGE_DECREFCOUNT );
return( CRYPT_OK );
case CRYPT_ENVINFO_SIGNATURE:
/* Return the key which was used to check the signature */
if( envelopeInfoPtr->contentListCurrent == NULL )
return( CRYPT_ERROR_NOTFOUND );
if( envelopeInfoPtr->contentListCurrent->iSigCheckKey == CRYPT_ERROR )
{
/* There's no signing key present, try and instantiate it
from an attached cert chain if there is one */
if( envelopeInfoPtr->auxBuffer == NULL )
return( CRYPT_ERROR_NOTFOUND );
status = instantiateCertChain( envelopeInfoPtr,
envelopeInfoPtr->contentListCurrent );
if( cryptStatusError( status ) )
return( status );
}
iCryptHandle = envelopeInfoPtr->contentListCurrent->iSigCheckKey;
/* Make the information externally visible */
krnlSendNotifier( iCryptHandle, RESOURCE_IMESSAGE_INCREFCOUNT );
krnlSendMessage( iCryptHandle, RESOURCE_IMESSAGE_SETATTRIBUTE,
MESSAGE_VALUE_FALSE, CRYPT_IATTRIBUTE_INTERNAL );
*valuePtr = iCryptHandle;
return( CRYPT_OK );
case CRYPT_ENVINFO_SIGNATURE_EXTRADATA:
/* Make sure there's extra data present */
iCryptHandle = envelopeInfoPtr->contentListCurrent->iExtraData;
if( iCryptHandle == CRYPT_ERROR )
return( CRYPT_ERROR_NOTFOUND );
/* Make the information externally visible */
krnlSendNotifier( iCryptHandle, RESOURCE_IMESSAGE_INCREFCOUNT );
krnlSendMessage( iCryptHandle, RESOURCE_IMESSAGE_SETATTRIBUTE,
MESSAGE_VALUE_FALSE, CRYPT_IATTRIBUTE_INTERNAL );
*valuePtr = iCryptHandle;
return( CRYPT_OK );
}
assert( NOTREACHED );
return( CRYPT_ERROR ); /* Get rid of compiler warning */
}
static int processGetAttributeS( ENVELOPE_INFO *envelopeInfoPtr,
void *messageDataPtr, const int messageValue )
{
CONTENT_LIST *contentListItem;
int status;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -