📄 env_attr.c
字号:
if( cryptArgError( status ) )
{
/* Make sure that any argument errors arising from this internal key
fetch don't get propagated back up to the caller */
status = CRYPT_ERROR_NOTFOUND;
}
/* 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 );
krnlSendNotifier( getkeyInfo.cryptHandle, 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 that
was performed while trying to obtain it */
*valuePtr = cryptStatusError( status ) ? \
envelopeInfoPtr->contentListCurrent->envInfo : \
CRYPT_ATTRIBUTE_NONE;
return( CRYPT_OK );
}
/* Get the result of the signature-check process and the key used for
signing. Since the signature check is performed on-demand this can
require a considerable amount of additional work */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
static int getSignatureResult( INOUT ENVELOPE_INFO *envelopeInfoPtr,
OUT_INT_Z int *valuePtr )
{
CRYPT_HANDLE iCryptHandle;
const CONTENT_SIG_INFO *sigInfo;
CONTENT_LIST *contentListItem = envelopeInfoPtr->contentListCurrent;
MESSAGE_KEYMGMT_INFO getkeyInfo;
int status;
assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
assert( isWritePtr( valuePtr, sizeof( int ) ) );
REQUIRES( envelopeInfoPtr->usage == ACTION_MAC || \
contentListItem != NULL );
/* Clear return value */
*valuePtr = 0;
/* If it's a MACd envelope then the signature result isn't held in a
content list as for the other signatures since the "signature" is
just a MAC tag appended to the data. The appropriate value to return
here is a bit tricky since an attacker could corrupt the MAC tag and
force a less severe error like CRYPT_ERROR_UNDERFLOW (by truncating
the data). However we can only get here once we've reached the
finished state, which means that all of the data (including the MAC
tag) has been successfully processed. This means that any persistent
error state is regarded as the equivalent of a signature error */
if( envelopeInfoPtr->usage == ACTION_MAC )
{
*valuePtr = ( envelopeInfoPtr->errorState != CRYPT_OK ) ? \
CRYPT_ERROR_SIGNATURE : CRYPT_OK;
return( CRYPT_OK );
}
REQUIRES( contentListItem != NULL );
/* Make sure that 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 (just for the signature-result attribute) to avoid having to do
an unnecessary key fetch for non-CMS signatures */
sigInfo = &contentListItem->clSigInfo;
if( contentListItem->envInfo != CRYPT_ENVINFO_SIGNATURE )
return( exitErrorNotFound( envelopeInfoPtr,
CRYPT_ENVINFO_SIGNATURE_RESULT ) );
if( contentListItem->flags & CONTENTLIST_PROCESSED )
{
*valuePtr = sigInfo->processingResult;
return( CRYPT_OK );
}
/* If there's an encoded certificate chain present and it hasn't been
instantiated as a certificate object yet, instantiate it now. We
don't check the return value since a failure isn't fatal, we can
still perform the signature check with a key pulled from a keyset */
if( sigInfo->iSigCheckKey == CRYPT_ERROR && \
envelopeInfoPtr->auxBuffer != NULL )
{
( void ) instantiateCertChain( contentListItem,
envelopeInfoPtr->auxBuffer,
envelopeInfoPtr->auxBufSize );
}
/* If we have a key instantiated from a certificate chain, use that to
check the signature. In theory we could also be re-using the key
from an earlier, not-completed check, however this is only retained
if the check succeeds (to allow a different key to be tried if the
check fails) so in practice this never occurs */
if( sigInfo->iSigCheckKey != CRYPT_ERROR )
{
/* Add the signature-check key with the special type
CRYPT_ENVINFO_SIGNATURE_RESULT to indicate that it's been
provided internally rather than being supplied by the user */
*valuePtr = envelopeInfoPtr->addInfo( envelopeInfoPtr,
CRYPT_ENVINFO_SIGNATURE_RESULT,
sigInfo->iSigCheckKey );
return( CRYPT_OK );
}
/* We don't have a signature check key available (for example from a CMS
certificate chain), make sure that there's a keyset available to pull
the key from and get the key from it */
if( envelopeInfoPtr->iSigCheckKeyset == CRYPT_ERROR )
return( exitErrorNotInited( envelopeInfoPtr,
CRYPT_ENVINFO_KEYSET_SIGCHECK ) );
/* Try and get the required key. Even though we're accessing the key by
(unique) key ID we still specify the key type preference in case
there's some problem with the ID info. This means that we return a
more meaningful error message now rather than a usage-related one
when we try to use the key */
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_USAGE_SIGN );
}
else
{
setMessageKeymgmtInfo( &getkeyInfo,
CRYPT_IKEYID_ISSUERANDSERIALNUMBER,
contentListItem->issuerAndSerialNumber,
contentListItem->issuerAndSerialNumberSize,
NULL, 0, KEYMGMT_FLAG_USAGE_SIGN );
}
status = krnlSendMessage( envelopeInfoPtr->iSigCheckKeyset,
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. Adding the key increments its reference count since the key
is usually user-supplied and we need to keep a reference for use by
the envelope, however since the key that we're using here is an
internal-use-only key we don't want to do this so we decrement it
again after it's been added. In addition we add the signature-check
key with the special type CRYPT_ENVINFO_SIGNATURE_RESULT to indicate
that it's been provided internally rather than being user-supplied */
*valuePtr = envelopeInfoPtr->addInfo( envelopeInfoPtr,
CRYPT_ENVINFO_SIGNATURE_RESULT,
iCryptHandle );
krnlSendNotifier( iCryptHandle, IMESSAGE_DECREFCOUNT );
/* If the key wasn't used for the signature check (i.e. it wasn't stored
in the content list for later use, which means it isn't needed any
more), discard it */
if( sigInfo->iSigCheckKey == CRYPT_ERROR )
krnlSendNotifier( iCryptHandle, IMESSAGE_DECREFCOUNT );
return( CRYPT_OK );
}
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
static int getSignatureKey( INOUT ENVELOPE_INFO *envelopeInfoPtr,
OUT_INT_Z int *valuePtr )
{
CRYPT_CERTIFICATE sigCheckCert;
CONTENT_LIST *contentListItem = envelopeInfoPtr->contentListCurrent;
CONTENT_SIG_INFO *sigInfo = &contentListItem->clSigInfo;
int status;
assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
assert( isWritePtr( valuePtr, sizeof( int ) ) );
REQUIRES( contentListItem != NULL );
/* Clear return value */
*valuePtr = 0;
/* If there's no signing key present try and instantiate it from an
attached certificate chain */
if( sigInfo->iSigCheckKey == CRYPT_ERROR )
{
if( envelopeInfoPtr->auxBuffer == NULL )
{
/* There's no attached certificate chain to recover the signing
key from, we can't go any further */
return( exitErrorNotFound( envelopeInfoPtr,
CRYPT_ENVINFO_SIGNATURE ) );
}
status = instantiateCertChain( contentListItem,
envelopeInfoPtr->auxBuffer,
envelopeInfoPtr->auxBufSize );
if( cryptStatusError( status ) )
return( exitError( envelopeInfoPtr, CRYPT_ENVINFO_SIGNATURE,
CRYPT_ERRTYPE_ATTR_VALUE, status ) );
}
/* If we instantiated the signature-check key ourselves (either from a
keyset or from envelope data) rather than having it supplied
externally, we're done */
if( !( contentListItem->flags & CONTENTLIST_EXTERNALKEY ) )
{
krnlSendNotifier( sigInfo->iSigCheckKey, IMESSAGE_INCREFCOUNT );
*valuePtr = sigInfo->iSigCheckKey;
return( CRYPT_OK );
}
/* The signature check key was externally supplied by the caller. If
they added a private key+certificate combination as the signature
check key then this will return a supposed signature-check
certificate that actually has private-key capabilities. Even adding
a simple certificate (+ public key context for the signature check)
can be dangerous since it can act as a subliminal channel if it's
passed on to a different user (although exactly how this would be
exploitable is another question entirely). To avoid this problem we
completely isolate the added signature check key by returning a copy
of the associated certificate object */
status = krnlSendMessage( sigInfo->iSigCheckKey, IMESSAGE_GETATTRIBUTE,
&sigCheckCert, CRYPT_IATTRIBUTE_CERTCOPY );
if( cryptStatusError( status ) )
return( exitError( envelopeInfoPtr, CRYPT_ENVINFO_SIGNATURE,
CRYPT_ERRTYPE_ATTR_VALUE, status ) );
/* We've created a new instantiation of the signature check key which is
distinct from the externally-supplied original, replace the existing
one with the new one and return it to the caller */
krnlSendNotifier( sigInfo->iSigCheckKey, IMESSAGE_DECREFCOUNT );
*valuePtr = sigInfo->iSigCheckKey = sigCheckCert;
return( CRYPT_OK );
}
/* Check an attribute add that isn't handled by the table-driven
general-purpose checks in setContextAttribute() */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 4, 5 ) ) \
static int checkOtherAttribute( INOUT ENVELOPE_INFO *envelopeInfoPtr,
IN_INT_Z const int value,
IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE attribute,
OUT_ENUM_OPT( ACTION ) ACTION_TYPE *usage,
OUT_ENUM_OPT( MESSAGE_CHECK ) \
MESSAGE_CHECK_TYPE *checkType )
{
assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
assert( isWritePtr( usage, sizeof( ACTION_TYPE ) ) );
REQUIRES( value >= 0 && value < MAX_INTLENGTH );
REQUIRES( isAttribute( attribute ) || \
isInternalAttribute( attribute ) );
/* Clear return values */
*usage = ACTION_NONE;
*checkType = MESSAGE_CHECK_NONE;
switch( attribute )
{
case CRYPT_OPTION_ENCR_ALGO:
if( !envelopeInfoPtr->checkAlgo( 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( OK_SPECIAL );
case CRYPT_OPTION_ENCR_HASH:
if( !envelopeInfoPtr->checkAlgo( value, CRYPT_MODE_NONE ) )
return( CRYPT_ARGERROR_VALUE );
envelopeInfoPtr->defaultHash = value;
return( OK_SPECIAL );
case CRYPT_OPTION_ENCR_MAC:
if( !envelopeInfoPtr->checkAlgo( value, CRYPT_MODE_NONE ) )
return( CRYPT_ARGERROR_VALUE );
envelopeInfoPtr->defaultMAC = value;
return( OK_SPECIAL );
case CRYPT_ENVINFO_DATASIZE:
if( envelopeInfoPtr->payloadSize != CRYPT_UNUSED )
return( exitErrorInited( envelopeInfoPtr,
CRYPT_ENVINFO_DATASIZE ) );
return( CRYPT_OK );
case CRYPT_ENVINFO_CONTENTTYPE:
/* Exactly what's 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 (e.g. compression or encryption)
then 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 ) );
return( CRYPT_OK );
case CRYPT_ENVINFO_INTEGRITY:
/* The integrity-protection flag can't be reset to a value of
CRYPT_INTEGRITY_NONE once it's been set to a higher level.
If it could be reset then the caller could set non-MAC-
compatible options by clearing the flag and then setting it
again afterwards */
if( envelopeInfoPtr->usage != ACTION_NONE )
return( CRYPT_ERROR_INITED );
return( CRYPT_OK );
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;
return( CRYPT_OK );
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 ) );
return( CRYPT_OK );
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 ) );
return( CRYPT_OK );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -