⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 env_attr.c

📁 cryptlib安全工具包
💻 C
📖 第 1 页 / 共 4 页
字号:
	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 + -