📄 cryptenv.c
字号:
/****************************************************************************
* *
* cryptlib Enveloping Routines *
* Copyright Peter Gutmann 1996-2005 *
* *
****************************************************************************/
#include <stdlib.h>
#include <string.h>
#include "crypt.h"
#ifdef INC_ALL
#include "envelope.h"
#else
#include "envelope/envelope.h"
#endif /* Compiler-specific includes */
#ifdef USE_ENVELOPES
/* The default size for the envelope buffer. On 16-bit systems they're
smaller because of memory and int size limitations */
#if defined( CONFIG_CONSERVE_MEMORY )
#define DEFAULT_BUFFER_SIZE 8192
#elif INT_MAX <= 32767
#define DEFAULT_BUFFER_SIZE 16384
#else
#define DEFAULT_BUFFER_SIZE 32768
#endif /* OS-specific envelope size defines */
/* When pushing and popping data, overflow and underflow errors can be
recovered from by adding or removing data, so we don't retain the error
state for these error types */
#define isRecoverableError( status ) \
( ( status ) == CRYPT_ERROR_OVERFLOW || \
( status ) == CRYPT_ERROR_UNDERFLOW )
/****************************************************************************
* *
* Utility Functions *
* *
****************************************************************************/
/* Reset the internal virtual cursor in a content-list item after we've
moved the attribute cursor */
static void resetVirtualCursor( CONTENT_LIST *contentListPtr )
{
if( contentListPtr == NULL || \
!( contentListPtr->flags & CONTENTLIST_ISSIGOBJ ) )
return;
contentListPtr->clSigInfo.attributeCursorEntry = \
CRYPT_ENVINFO_SIGNATURE_RESULT;
}
/* Move the internal virtual cursor within a content-list item */
static BOOLEAN moveVirtualCursor( CONTENT_LIST *contentListPtr,
const ATTR_TYPE attrGetType )
{
static const CRYPT_ATTRIBUTE_TYPE attributeOrderList[] = {
CRYPT_ENVINFO_SIGNATURE_RESULT, CRYPT_ENVINFO_SIGNATURE,
CRYPT_ENVINFO_SIGNATURE_EXTRADATA, CRYPT_ENVINFO_TIMESTAMP,
CRYPT_ATTRIBUTE_NONE, CRYPT_ATTRIBUTE_NONE };
CONTENT_SIG_INFO *sigInfo = &contentListPtr->clSigInfo;
CRYPT_ATTRIBUTE_TYPE attributeType = sigInfo->attributeCursorEntry;
BOOLEAN doContinue;
assert( attrGetType == ATTR_NEXT || attrGetType == ATTR_PREV );
assert( sigInfo->attributeCursorEntry != CRYPT_ATTRIBUTE_NONE );
do
{
int i;
/* Find the position of the current sub-attribute in the attribute
order list and use that to get its successor/predecessor sub-
attribute */
for( i = 0; \
attributeOrderList[ i ] != attributeType && \
attributeOrderList[ i ] != CRYPT_ATTRIBUTE_NONE; i++ );
if( attributeOrderList[ i ] == CRYPT_ATTRIBUTE_NONE )
attributeType = CRYPT_ATTRIBUTE_NONE;
else
if( attrGetType == ATTR_PREV )
attributeType = ( i < 1 ) ? CRYPT_ATTRIBUTE_NONE : \
attributeOrderList[ i - 1 ];
else
attributeType = attributeOrderList[ i + 1 ];
if( attributeType == CRYPT_ATTRIBUTE_NONE )
/* We've reached the first/last sub-attribute within the current
item/group, tell the caller that there are no more sub-
attributes present and they have to move on to the next
group */
return( FALSE );
/* Check whether the required sub-attribute is present. If not, we
continue and try the next one */
doContinue = FALSE;
switch( attributeType )
{
case CRYPT_ENVINFO_SIGNATURE_RESULT:
break; /* Always present */
case CRYPT_ENVINFO_SIGNATURE:
if( sigInfo->iSigCheckKey == CRYPT_ERROR )
doContinue = TRUE;
break;
case CRYPT_ENVINFO_SIGNATURE_EXTRADATA:
if( sigInfo->iExtraData == CRYPT_ERROR )
doContinue = TRUE;
break;
case CRYPT_ENVINFO_TIMESTAMP:
if( sigInfo->iTimestamp == CRYPT_ERROR )
doContinue = TRUE;
break;
default:
assert( NOTREACHED );
return( FALSE );
}
}
while( doContinue );
sigInfo->attributeCursorEntry = attributeType;
return( TRUE );
}
/* Callback function used to provide external access to content list-
internal fields */
static const void *getAttrFunction( const void *attributePtr,
CRYPT_ATTRIBUTE_TYPE *groupID,
CRYPT_ATTRIBUTE_TYPE *attributeID,
CRYPT_ATTRIBUTE_TYPE *instanceID,
const ATTR_TYPE attrGetType )
{
CONTENT_LIST *contentListPtr = ( CONTENT_LIST * ) attributePtr;
BOOLEAN subGroupMove;
assert( contentListPtr == NULL || \
isReadPtr( contentListPtr, sizeof( CONTENT_LIST ) ) );
/* Clear return values */
if( groupID != NULL )
*groupID = CRYPT_ATTRIBUTE_NONE;
if( attributeID != NULL )
*attributeID = CRYPT_ATTRIBUTE_NONE;
if( instanceID != NULL )
*instanceID = CRYPT_ATTRIBUTE_NONE;
/* Move to the next or previous attribute if required. This isn't just a
case of following the prev/next links because some content-list items
contain an entire attribute group, so positioning by attribute merely
changes the current selection within the group (== content-list item)
rather than moving to the previous/next entry. Because of this we
have to special-case the code for composite items (currently only
signature objects meet this definition) and allow virtual positioning
within the item */
if( contentListPtr == NULL )
return( NULL );
subGroupMove = ( attrGetType == ATTR_PREV || \
attrGetType == ATTR_NEXT ) && \
( contentListPtr->flags & CONTENTLIST_ISSIGOBJ );
if( subGroupMove )
subGroupMove = moveVirtualCursor( contentListPtr, attrGetType );
/* If we're moving by group, move to the next/previous content list
item and reset the internal virtual cursor. Note that we always
advance the cursor to the next/prev attribute, it's up to the calling
code to manage attribute by attribute vs.group by group moves */
if( !subGroupMove && attrGetType != ATTR_CURRENT )
{
contentListPtr = ( attrGetType == ATTR_PREV ) ? \
contentListPtr->prev : contentListPtr->next;
resetVirtualCursor( contentListPtr );
}
if( contentListPtr == NULL )
return( NULL );
/* Return ID information to the caller. We only return the group ID if
we've moved within the attribute group, if we've moved from one group
to another we leave it cleared because envelopes can contain multiple
groups with the same ID, and returning an ID identical to the one from
the group that we've moved out of would make it look as if we're still
within the same group. Note that this relies on the behaviour of the
attribute-move functions, which first get the current group using
ATTR_CURRENT and then move to the next or previous using ATTR_NEXT/
PREV */
if( groupID != NULL && ( attrGetType == ATTR_CURRENT || subGroupMove ) )
*groupID = contentListPtr->envInfo;
if( attributeID != NULL && \
( contentListPtr->flags & CONTENTLIST_ISSIGOBJ ) )
*attributeID = contentListPtr->clSigInfo.attributeCursorEntry;
return( contentListPtr );
}
/* 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;
assert( contentListItem->flags & CONTENTLIST_ISSIGOBJ );
/* 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,
CRYPT_ICERTTYPE_CMS_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,
IMESSAGE_DEV_CREATEOBJECT_INDIRECT,
&createInfo, OBJECT_TYPE_CERTIFICATE );
if( cryptStatusOK( status ) )
contentListItem->clSigInfo.iSigCheckKey = createInfo.cryptHandle;
return( status );
}
/****************************************************************************
* *
* Envelope Attribute Handling Functions *
* *
****************************************************************************/
/* Exit after setting extended error information */
static int exitError( ENVELOPE_INFO *envelopeInfoPtr,
const CRYPT_ATTRIBUTE_TYPE errorLocus,
const CRYPT_ERRTYPE_TYPE errorType, const int status )
{
setErrorInfo( envelopeInfoPtr, errorLocus, errorType );
return( status );
}
static int exitErrorInited( ENVELOPE_INFO *envelopeInfoPtr,
const CRYPT_ATTRIBUTE_TYPE errorLocus )
{
return( exitError( envelopeInfoPtr, errorLocus, CRYPT_ERRTYPE_ATTR_PRESENT,
CRYPT_ERROR_INITED ) );
}
static int exitErrorNotInited( ENVELOPE_INFO *envelopeInfoPtr,
const CRYPT_ATTRIBUTE_TYPE errorLocus )
{
return( exitError( envelopeInfoPtr, errorLocus, CRYPT_ERRTYPE_ATTR_ABSENT,
CRYPT_ERROR_NOTINITED ) );
}
static int exitErrorNotFound( ENVELOPE_INFO *envelopeInfoPtr,
const CRYPT_ATTRIBUTE_TYPE errorLocus )
{
return( exitError( envelopeInfoPtr, errorLocus, CRYPT_ERRTYPE_ATTR_ABSENT,
CRYPT_ERROR_NOTFOUND ) );
}
/* Handle data sent to or read from an envelope object */
static int processGetAttribute( ENVELOPE_INFO *envelopeInfoPtr,
void *messageDataPtr, const int messageValue )
{
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 that 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 that don't work for PGP */
if( envelopeInfoPtr->type == CRYPT_FORMAT_PGP && \
messageValue == CRYPT_ENVINFO_SIGNATURE_EXTRADATA )
return( CRYPT_ARGERROR_VALUE );
/* Make sure that the attribute is valid for this envelope type and state */
switch( messageValue )
{
case CRYPT_OPTION_ENCR_ALGO:
case CRYPT_OPTION_ENCR_HASH:
case CRYPT_OPTION_ENCR_MAC:
/* Algorithm types are valid only for enveloping */
if( envelopeInfoPtr->flags & ENVELOPE_ISDEENVELOPE )
return( CRYPT_ARGERROR_OBJECT );
break;
case CRYPT_ATTRIBUTE_CURRENT_GROUP:
case CRYPT_ATTRIBUTE_CURRENT:
case CRYPT_ENVINFO_SIGNATURE_RESULT:
case CRYPT_ENVINFO_SIGNATURE:
case CRYPT_ENVINFO_SIGNATURE_EXTRADATA:
case CRYPT_ENVINFO_TIMESTAMP:
/* The signature key and extra data is read-only for de-
enveloping, write-only for enveloping, which can't be checked
by the more general kernel checks (the current-component and
sig-result attributes are de-enveloping only, so they are
checked) */
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 );
/* We're querying something that resides in the content list,
make sure that there's a content list present. If it's
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -