📄 env_attr.c
字号:
attribute == CRYPT_ATTRIBUTE_CURRENT ) ||
/* Compression = CRYPT_UNUSED, CURRENT = cursor positioning
code */
( value >= 0 && value < MAX_INTLENGTH ) );
REQUIRES( isAttribute( attribute ) || \
isInternalAttribute( attribute ) );
/* Generic attributes are valid for all envelope types */
if( attribute == CRYPT_ATTRIBUTE_BUFFERSIZE )
{
envelopeInfoPtr->bufSize = value;
return( CRYPT_OK );
}
/* If it's meta-information, process it now */
if( attribute == CRYPT_ATTRIBUTE_CURRENT_GROUP || \
attribute == CRYPT_ATTRIBUTE_CURRENT )
{
const CONTENT_LIST *contentListCursor;
/* If it's an absolute positioning code, pre-set the attribute
cursor if required */
if( value == CRYPT_CURSOR_FIRST || value == CRYPT_CURSOR_LAST )
{
if( envelopeInfoPtr->contentList == NULL )
return( CRYPT_ERROR_NOTFOUND );
ENSURES( envelopeInfoPtr->contentList != NULL );
/* If it's an absolute attribute positioning code, reset the
attribute cursor to the start of the list before we try to
move it and if it's an attribute positioning code initialise
the attribute cursor if necessary */
if( attribute == CRYPT_ATTRIBUTE_CURRENT_GROUP || \
envelopeInfoPtr->contentListCurrent == NULL )
{
envelopeInfoPtr->contentListCurrent = \
envelopeInfoPtr->contentList;
if( envelopeInfoPtr->contentListCurrent != NULL )
resetVirtualCursor( envelopeInfoPtr->contentListCurrent );
}
/* If there are no attributes present, return the appropriate
error code */
if( envelopeInfoPtr->contentListCurrent == NULL )
{
return( ( value == CRYPT_CURSOR_FIRST || \
value == CRYPT_CURSOR_LAST ) ? \
CRYPT_ERROR_NOTFOUND : \
CRYPT_ERROR_NOTINITED );
}
}
else
{
/* It's a relative positioning code, return a not-inited error
rather than a not-found error if the cursor isn't set since
there may be attributes present but the cursor hasn't been
initialised yet by selecting the first or last absolute
attribute */
if( envelopeInfoPtr->contentListCurrent == NULL )
return( CRYPT_ERROR_NOTINITED );
}
ENSURES( envelopeInfoPtr->contentListCurrent != NULL );
/* Move the cursor */
contentListCursor = \
attributeMoveCursor( envelopeInfoPtr->contentListCurrent,
getAttrFunction, attribute, value );
if( contentListCursor == NULL )
return( CRYPT_ERROR_NOTFOUND );
envelopeInfoPtr->contentListCurrent = \
( CONTENT_LIST * ) contentListCursor;
return( CRYPT_OK );
}
/* In general we can't add new enveloping information once we've started
processing data */
if( envelopeInfoPtr->state != STATE_PREDATA )
{
/* We can't add new information once we've started enveloping */
if( !( envelopeInfoPtr->flags & ENVELOPE_ISDEENVELOPE ) )
return( CRYPT_ERROR_INITED );
/* We can only add signature check information once we've started
de-enveloping */
if( attribute != CRYPT_ENVINFO_SIGNATURE )
return( CRYPT_ERROR_INITED );
}
/* 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 )
{
if( attribute == CRYPT_OPTION_ENCR_MAC || \
attribute == CRYPT_ENVINFO_INTEGRITY || \
attribute == CRYPT_ENVINFO_KEY || \
attribute == CRYPT_ENVINFO_SESSIONKEY )
return( CRYPT_ARGERROR_VALUE );
if( attribute == CRYPT_ENVINFO_HASH && \
!( envelopeInfoPtr->flags & ENVELOPE_DETACHED_SIG ) )
{
/* We can add a hash if we're creating a detached signature */
return( CRYPT_ARGERROR_VALUE );
}
}
/* Since the information may not be used for quite some time after it's
added we do some preliminary checking here to allow us to return an
error code immediately rather than from some deeply-buried function an
indeterminate time in the future. Since much of the checking is
similar, we use a table-driven check for most types and fall back to
custom checking for special cases */
for( i = 0; checkTable[ i ].type != ACTION_NONE && \
i < FAILSAFE_ARRAYSIZE( checkTable, CHECK_INFO ); i++ )
{
if( checkTable[ i ].type == attribute )
{
if( envelopeInfoPtr->usage != ACTION_NONE && \
envelopeInfoPtr->usage != checkTable[ i ].usage )
return( exitErrorInited( envelopeInfoPtr, attribute ) );
usage = checkTable[ i ].usage;
checkType = checkTable[ i ].checkType;
break;
}
}
ENSURES( i < FAILSAFE_ARRAYSIZE( checkTable, CHECK_INFO ) );
if( usage != ACTION_NONE )
{
/* Make sure that the usage requirements for the item that we're
about to add are consistent */
if( envelopeInfoPtr->usage != ACTION_NONE && \
envelopeInfoPtr->usage != usage )
return( exitErrorInited( envelopeInfoPtr,
attribute ) );
}
else
{
/* It's not a general class of action, perform special-case usage
checking */
status = checkOtherAttribute( envelopeInfoPtr, value, attribute,
&usage, &checkType );
if( cryptStatusError( status ) )
{
/* An attribute that's handled internally will return OK_SPECIAL
to indicate that there's nothing further to do */
if( status == OK_SPECIAL )
return( CRYPT_OK );
return( status );
}
}
if( checkType != MESSAGE_CHECK_NONE )
{
/* Check the object as appropriate. A key agreement key can also act
as a public key because of the way KEA works so if a check for a
straight public key fails we try again to see if it's a key
agreement key with import capabilities */
status = krnlSendMessage( value, IMESSAGE_CHECK, NULL, checkType );
if( status == CRYPT_ARGERROR_OBJECT && \
attribute == CRYPT_ENVINFO_PUBLICKEY )
status = krnlSendMessage( value, IMESSAGE_CHECK, NULL,
MESSAGE_CHECK_PKC_KA_IMPORT );
if( cryptStatusError( status ) )
return( CRYPT_ARGERROR_NUM1 );
/* Make sure that the object corresponds to a representable algorithm
type. Note that this check isn't totally foolproof on de-
enveloping PGP data since the user can push in the hash context
before they push in the signed data (to signifiy the use of a
detached signature) so it'd be checked using the default (CMS)
algorithm values rather than the PGP ones */
if( checkType == MESSAGE_CHECK_PKC_ENCRYPT || \
checkType == MESSAGE_CHECK_PKC_DECRYPT || \
checkType == MESSAGE_CHECK_PKC_SIGN || \
checkType == MESSAGE_CHECK_PKC_SIGCHECK || \
checkType == MESSAGE_CHECK_CRYPT || \
checkType == MESSAGE_CHECK_HASH || \
checkType == MESSAGE_CHECK_MAC )
{
CRYPT_ALGO_TYPE algorithm;
CRYPT_MODE_TYPE mode = CRYPT_MODE_NONE;
status = krnlSendMessage( value, IMESSAGE_GETATTRIBUTE,
&algorithm, CRYPT_CTXINFO_ALGO );
if( cryptStatusOK( status ) && checkType == MESSAGE_CHECK_CRYPT )
{
/* It's a conventional-encryption context, get the mode as
well */
status = krnlSendMessage( value, IMESSAGE_GETATTRIBUTE,
&mode, CRYPT_CTXINFO_MODE );
}
if( cryptStatusError( status ) )
return( CRYPT_ARGERROR_NUM1 );
if( !envelopeInfoPtr->checkAlgo( algorithm, mode ) )
return( CRYPT_ERROR_NOTAVAIL );
}
/* If we're using CMS enveloping then the object must have an
initialised certificate of the correct type associated with it.
Most of this will be caught by the kernel but there are a couple
of special cases (e.g. an attribute certificate where the main
object is a PKC context) which are missed by the general kernel
checks */
if( ( attribute == CRYPT_ENVINFO_SIGNATURE || \
attribute == CRYPT_ENVINFO_PUBLICKEY || \
attribute == CRYPT_ENVINFO_PRIVATEKEY || \
attribute == CRYPT_ENVINFO_ORIGINATOR ) &&
( envelopeInfoPtr->type == CRYPT_FORMAT_CMS || \
envelopeInfoPtr->type == CRYPT_FORMAT_SMIME ) )
{
int inited, certType;
status = krnlSendMessage( value, IMESSAGE_GETATTRIBUTE, &inited,
CRYPT_CERTINFO_IMMUTABLE );
if( cryptStatusError( status ) || !inited )
return( CRYPT_ARGERROR_NUM1 );
status = krnlSendMessage( value, IMESSAGE_GETATTRIBUTE,
&certType, CRYPT_CERTINFO_CERTTYPE );
if( cryptStatusError( status ) ||
( certType != CRYPT_CERTTYPE_CERTIFICATE && \
certType != CRYPT_CERTTYPE_CERTCHAIN ) )
return( CRYPT_ARGERROR_NUM1 );
}
}
/* Add it to the envelope */
status = envelopeInfoPtr->addInfo( envelopeInfoPtr, attribute,
value );
if( cryptStatusError( status ) )
{
if( status == CRYPT_ERROR_INITED )
return( exitErrorInited( envelopeInfoPtr, attribute ) );
return( status );
}
if( usage != ACTION_NONE )
{
/* The action was successfully added, update the usage if
necessary */
envelopeInfoPtr->usage = usage;
}
return( CRYPT_OK );
}
/* Set a string attribute */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
int setEnvelopeAttributeS( INOUT ENVELOPE_INFO *envelopeInfoPtr,
IN_BUFFER( dataLength ) const void *data,
IN_LENGTH const int dataLength,
IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE attribute )
{
ACTION_TYPE usage = ACTION_NONE;
int status;
assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
assert( isReadPtr( data, dataLength ) );
REQUIRES( dataLength > 0 && dataLength < MAX_INTLENGTH );
REQUIRES( isAttribute( attribute ) || \
isInternalAttribute( attribute ) );
/* Handle the various information types */
switch( attribute )
{
case CRYPT_ENVINFO_PASSWORD:
/* Set the envelope usage type based on the fact that we've been
fed a password */
if( envelopeInfoPtr->usage == ACTION_NONE )
usage = ACTION_CRYPT;
else
{
if( envelopeInfoPtr->usage != ACTION_CRYPT && \
envelopeInfoPtr->usage != ACTION_MAC )
return( exitErrorInited( envelopeInfoPtr,
CRYPT_ENVINFO_PASSWORD ) );
}
/* In general we can't add new enveloping information once we've
started processing data */
if( envelopeInfoPtr->state != STATE_PREDATA && \
!( envelopeInfoPtr->flags & ENVELOPE_ISDEENVELOPE ) )
{
/* We can't add new information once we've started enveloping */
return( exitErrorInited( envelopeInfoPtr,
CRYPT_ENVINFO_PASSWORD ) );
}
/* Add it to the envelope */
status = envelopeInfoPtr->addInfoString( envelopeInfoPtr,
CRYPT_ENVINFO_PASSWORD, data, dataLength );
break;
case CRYPT_ENVINFO_RECIPIENT:
{
MESSAGE_KEYMGMT_INFO getkeyInfo;
/* Set the envelope usage type based on the fact that we've been
fed a recipient email address */
if( envelopeInfoPtr->usage != ACTION_NONE && \
envelopeInfoPtr->usage != ACTION_CRYPT )
return( CRYPT_ARGERROR_VALUE );
usage = ACTION_CRYPT;
/* Make sure that there's a keyset available to pull the
recipient's key from */
if( envelopeInfoPtr->iEncryptionKeyset == CRYPT_ERROR )
return( exitErrorNotInited( envelopeInfoPtr,
CRYPT_ENVINFO_KEYSET_ENCRYPT ) );
/* Try and read the recipient's key from the keyset. Some
keysets (particularly PKCS #11 devices, for which apps set
the usage flags more or less at random) may not be able to
differentiate between encryption and signature keys based on
the information that they have. This isn't a problem when
matching a key based on a unique ID but with the use of the
recipient name as the ID there could be multiple possible
matches. Before we try and use the key we therefore perform
an extra check here to make sure that it really is an
encryption-capable key */
setMessageKeymgmtInfo( &getkeyInfo, CRYPT_KEYID_URI, data,
dataLength, NULL, 0,
KEYMGMT_FLAG_USAGE_CRYPT );
status = krnlSendMessage( envelopeInfoPtr->iEncryptionKeyset,
IMESSAGE_KEY_GETKEY, &getkeyInfo,
KEYMGMT_ITEM_PUBLICKEY );
if( cryptStatusOK( status ) && \
cryptStatusError( \
krnlSendMessage( getkeyInfo.cryptHandle, IMESSAGE_CHECK,
NULL, MESSAGE_CHECK_PKC_ENCRYPT ) ) )
{
krnlSendNotifier( getkeyInfo.cryptHandle,
IMESSAGE_DECREFCOUNT );
status = CRYPT_ERROR_NOTFOUND;
}
if( cryptStatusOK( status ) )
{
/* We got the key, add it to the envelope */
status = envelopeInfoPtr->addInfo( envelopeInfoPtr,
CRYPT_ENVINFO_PUBLICKEY,
getkeyInfo.cryptHandle );
krnlSendNotifier( getkeyInfo.cryptHandle,
IMESSAGE_DECREFCOUNT );
}
break;
}
default:
retIntError();
}
if( cryptStatusError( status ) )
{
if( status == CRYPT_ERROR_INITED )
return( exitErrorInited( envelopeInfoPtr, attribute ) );
return( status );
}
if( usage != ACTION_NONE )
{
/* The action was successfully added, update the usage if
necessary */
envelopeInfoPtr->usage = usage;
}
return( CRYPT_OK );
}
#endif /* USE_ENVELOPES */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -