📄 cryptenv.c
字号:
if( cryptStatusOK( status ) )
return( attributeCopy( messageDataPtr, getkeyInfo.auxInfo,
getkeyInfo.auxInfoLength ) );
return( status );
}
assert( NOTREACHED );
return( CRYPT_ERROR ); /* Get rid of compiler warning */
}
static int processSetAttribute( ENVELOPE_INFO *envelopeInfoPtr,
void *messageDataPtr, const int messageValue )
{
MESSAGE_CHECK_TYPE checkType = MESSAGE_CHECK_NONE;
ACTION_TYPE usage = ACTION_NONE;
static const struct {
const CRYPT_ATTRIBUTE_TYPE type; /* Attribute type */
const ACTION_TYPE usage; /* Corresponding usage type */
const MESSAGE_CHECK_TYPE checkType; /* and check type */
} checkTable[] = {
#ifdef USE_COMPRESSION
{ CRYPT_ENVINFO_COMPRESSION, ACTION_COMPRESS, MESSAGE_CHECK_NONE },
#endif /* USE_COMPRESSION */
{ CRYPT_ENVINFO_MAC, ACTION_MAC, MESSAGE_CHECK_MAC },
{ CRYPT_ENVINFO_KEY, ACTION_CRYPT, MESSAGE_CHECK_CRYPT },
{ CRYPT_ENVINFO_PUBLICKEY, ACTION_CRYPT, MESSAGE_CHECK_PKC_ENCRYPT },
{ CRYPT_ENVINFO_PRIVATEKEY, ACTION_CRYPT, MESSAGE_CHECK_PKC_DECRYPT },
{ CRYPT_ENVINFO_HASH, ACTION_SIGN, MESSAGE_CHECK_HASH },
{ CRYPT_ENVINFO_TIMESTAMP_AUTHORITY, ACTION_SIGN, MESSAGE_CHECK_NONE },
{ CRYPT_ENVINFO_DETACHEDSIGNATURE, ACTION_SIGN, MESSAGE_CHECK_NONE },
{ CRYPT_IATTRIBUTE_INCLUDESIGCERT, ACTION_SIGN, MESSAGE_CHECK_NONE },
{ CRYPT_IATTRIBUTE_ATTRONLY, ACTION_SIGN, MESSAGE_CHECK_NONE },
{ CRYPT_ATTRIBUTE_NONE, ACTION_NONE }
};
const int value = *( int * ) messageDataPtr;
int i, status;
/* If it's an initialisation message, there's nothing to do */
if( messageValue == CRYPT_IATTRIBUTE_INITIALISED )
return( CRYPT_OK );
/* Generic attributes are valid for all envelope types */
if( messageValue == CRYPT_ATTRIBUTE_BUFFERSIZE )
{
envelopeInfoPtr->bufSize = value;
return( CRYPT_OK );
}
/* If it's meta-information, process it now */
if( messageValue == CRYPT_ENVINFO_CURRENT_COMPONENT )
return( moveCursor( envelopeInfoPtr, value ) );
/* In general we can't add new enveloping information once we've started
processing data */
if( messageValue != CRYPT_ENVINFO_CURRENT_COMPONENT && \
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( messageValue != 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( messageValue == CRYPT_OPTION_ENCR_MAC || \
messageValue == CRYPT_ENVINFO_MAC || \
messageValue == CRYPT_ENVINFO_KEY || \
messageValue == CRYPT_ENVINFO_SESSIONKEY )
return( CRYPT_ARGERROR_VALUE );
if( messageValue == 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++ )
if( checkTable[ i ].type == messageValue )
{
if( envelopeInfoPtr->usage != ACTION_NONE && \
envelopeInfoPtr->usage != checkTable[ i ].usage )
return( exitErrorInited( envelopeInfoPtr, messageValue ) );
usage = checkTable[ i ].usage;
checkType = checkTable[ i ].checkType;
break;
}
if( usage == ACTION_NONE )
switch( messageValue )
{
case CRYPT_OPTION_ENCR_ALGO:
if( cryptStatusError( \
envelopeInfoPtr->checkCryptAlgo( value,
isStreamCipher( value ) ? CRYPT_MODE_OFB : \
( envelopeInfoPtr->type == CRYPT_FORMAT_PGP ) ? \
CRYPT_MODE_CFB : CRYPT_MODE_CBC ) ) )
return( CRYPT_ARGERROR_VALUE );
envelopeInfoPtr->defaultAlgo = value;
return( CRYPT_OK );
case CRYPT_OPTION_ENCR_HASH:
if( cryptStatusError( \
envelopeInfoPtr->checkHashAlgo( value ) ) )
return( CRYPT_ARGERROR_VALUE );
envelopeInfoPtr->defaultHash = value;
return( CRYPT_OK );
case CRYPT_OPTION_ENCR_MAC:
if( cryptStatusError( \
envelopeInfoPtr->checkHashAlgo( value ) ) )
return( CRYPT_ARGERROR_VALUE );
envelopeInfoPtr->defaultMAC = value;
return( CRYPT_OK );
case CRYPT_ENVINFO_DATASIZE:
if( envelopeInfoPtr->payloadSize != CRYPT_UNUSED )
return( exitErrorInited( envelopeInfoPtr,
CRYPT_ENVINFO_DATASIZE ) );
break;
case CRYPT_ENVINFO_CONTENTTYPE:
/* Exactly what is supposed to happen when PGP is asked to
sign non-plain-data is ill-defined. No command-line PGP
option will generate this type of message, and the RFCs
don't specify the behaviour (in fact RFC 1991's
description of PGP signing is completely wrong). In
practice PGP hashes and signs the payload contents of a
PGP literal data packet, however if there are extra layers
of processing between the signing and literal packets (eg
compression or encryption), what gets hashed isn't
specified. If it's always the payload of the final
(literal) data packet, we'd have to be able to burrow down
through arbitrary amounts of further data and processing
in order to get to the payload data to hash (this also
makes things like mail gateways that only allow signed
messages through infeasible unless the gateway holds
everyone's private key in order to get at the plaintext to
hash). Because of this problem, we disallow any attempts
to set a content-type other than plain data if we're
signing a PGP-format message */
if( envelopeInfoPtr->type == CRYPT_FORMAT_PGP && \
envelopeInfoPtr->usage == ACTION_SIGN && \
value != CRYPT_CONTENT_DATA )
return( CRYPT_ARGERROR_VALUE );
/* For user-friendliness we allow overwriting a given content
type with the same type, which is useful for cases when
cryptlib automatically presets the type based on other
information */
if( envelopeInfoPtr->contentType && \
envelopeInfoPtr->contentType != value )
return( exitErrorInited( envelopeInfoPtr,
CRYPT_ENVINFO_CONTENTTYPE ) );
break;
case CRYPT_ENVINFO_SESSIONKEY:
checkType = MESSAGE_CHECK_CRYPT;
if( envelopeInfoPtr->usage != ACTION_NONE && \
!( ( envelopeInfoPtr->flags & ENVELOPE_ISDEENVELOPE ) && \
envelopeInfoPtr->usage == ACTION_CRYPT ) )
/* On de-enveloping the usage is set by the enveloped data
format, so setting a session key when the usage is
already set to encryption isn't an error */
return( exitErrorInited( envelopeInfoPtr,
CRYPT_ENVINFO_SESSIONKEY ) );
usage = ACTION_CRYPT;
break;
case CRYPT_ENVINFO_SIGNATURE:
checkType = \
( envelopeInfoPtr->flags & ENVELOPE_ISDEENVELOPE ) ? \
MESSAGE_CHECK_PKC_SIGCHECK : MESSAGE_CHECK_PKC_SIGN;
if( envelopeInfoPtr->usage != ACTION_NONE && \
envelopeInfoPtr->usage != ACTION_SIGN )
return( exitErrorInited( envelopeInfoPtr,
CRYPT_ENVINFO_SIGNATURE ) );
if( envelopeInfoPtr->type == CRYPT_FORMAT_PGP && \
envelopeInfoPtr->contentType == CRYPT_CONTENT_DATA )
/* See the long comment for CRYPT_ENVINFO_CONTENTTYPE */
return( CRYPT_ARGERROR_VALUE );
usage = ACTION_SIGN;
break;
case CRYPT_ENVINFO_SIGNATURE_EXTRADATA:
if( envelopeInfoPtr->type != CRYPT_FORMAT_CMS && \
envelopeInfoPtr->type != CRYPT_FORMAT_SMIME )
return( CRYPT_ARGERROR_VALUE );
if( envelopeInfoPtr->usage != ACTION_NONE && \
envelopeInfoPtr->usage != ACTION_SIGN )
return( exitErrorInited( envelopeInfoPtr,
CRYPT_ENVINFO_SIGNATURE_EXTRADATA ) );
break;
case CRYPT_ENVINFO_ORIGINATOR:
checkType = MESSAGE_CHECK_PKC_KA_EXPORT;
if( envelopeInfoPtr->usage != ACTION_NONE && \
envelopeInfoPtr->usage != ACTION_CRYPT )
return( exitErrorInited( envelopeInfoPtr,
CRYPT_ENVINFO_ORIGINATOR ) );
usage = ACTION_CRYPT;
if( envelopeInfoPtr->iExtraCertChain != CRYPT_ERROR )
return( exitErrorInited( envelopeInfoPtr,
CRYPT_ENVINFO_ORIGINATOR ) );
break;
case CRYPT_ENVINFO_KEYSET_ENCRYPT:
checkType = MESSAGE_CHECK_PKC_ENCRYPT;
if( envelopeInfoPtr->iEncryptionKeyset != CRYPT_ERROR )
return( exitErrorInited( envelopeInfoPtr,
CRYPT_ENVINFO_KEYSET_ENCRYPT ) );
break;
case CRYPT_ENVINFO_KEYSET_DECRYPT:
checkType = MESSAGE_CHECK_PKC_DECRYPT;
if( envelopeInfoPtr->iDecryptionKeyset != CRYPT_ERROR )
return( exitErrorInited( envelopeInfoPtr,
CRYPT_ENVINFO_KEYSET_DECRYPT ) );
break;
case CRYPT_ENVINFO_KEYSET_SIGCHECK:
checkType = MESSAGE_CHECK_PKC_SIGCHECK;
if( envelopeInfoPtr->iSigCheckKeyset != CRYPT_ERROR )
return( exitErrorInited( envelopeInfoPtr,
CRYPT_ENVINFO_KEYSET_SIGCHECK ) );
break;
default:
assert( NOTREACHED );
}
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 && \
messageValue == 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 the hash context
before they push the signed data (to signifiy the use of a
detached signature) so that it's checked using the default
(CMS) algorithm values rather then PGP ones */
if( checkType == MESSAGE_CHECK_CRYPT || \
checkType == MESSAGE_CHECK_HASH || \
checkType == MESSAGE_CHECK_MAC )
{
CRYPT_ALGO_TYPE algorithm;
krnlSendMessage( value, IMESSAGE_GETATTRIBUTE, &algorithm,
CRYPT_CTXINFO_ALGO );
if( checkType == MESSAGE_CHECK_CRYPT )
{
CRYPT_MODE_TYPE mode;
krnlSendMessage( value, IMESSAGE_GETATTRIBUTE, &mode,
CRYPT_CTXINFO_MODE );
status = envelopeInfoPtr->checkCryptAlgo( algorithm, mode );
}
else
status = envelopeInfoPtr->checkHashAlgo( algorithm );
if( cryptStatusError( status ) )
return( CRYPT_ERROR_NOTAVAIL );
}
/* If we're using CMS enveloping, the object must have an initialised
cert of the correct type associated with it. Most of this will be
caught by the kernel, but there are a couple of special cases (eg
attribute cert where the main object is a PKC context) which are
missed by the general kernel checks */
if( ( messageValue == CRYPT_ENVINFO_SIGNATURE || \
messageValue == CRYPT_ENVINFO_PUBLICKEY || \
messageValue == CRYPT_ENVINFO_PRIVATEKEY || \
messageValue == 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, messageValue,
&value, 0 );
if( cryptStatusError( status ) )
{
if( status == CRYPT_ERROR_INITED )
return( exitErrorInited( envelopeInfoPtr, messageValue ) );
return( status );
}
if( usage != ACTION_NONE )
/* The action was successfully added, update the usage if
necessary */
envelopeInfoPtr->usage = usage;
return( CRYPT_OK );
}
static int processSetAttributeS( ENVELOPE_INFO *envelopeInfoPtr,
void *messageDataPtr, const int messageValue )
{
RESOURCE_DATA *msgData = ( RESOURCE_DATA * ) messageDataPtr;
ACTION_TYPE usage = ACTION_NONE;
int status;
/* Handle the various information types */
switch( messageValue )
{
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 )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -