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

📄 pkcs15_set.c

📁 cryptlib安全工具包
💻 C
📖 第 1 页 / 共 2 页
字号:
/****************************************************************************
*																			*
*					   cryptlib PKCS #15 Set-item Routines					*
*						Copyright Peter Gutmann 1996-2007					*
*																			*
****************************************************************************/

#if defined( INC_ALL )
  #include "crypt.h"
  #include "keyset.h"
  #include "pkcs15.h"
#else
  #include "crypt.h"
  #include "keyset/keyset.h"
  #include "keyset/pkcs15.h"
#endif /* Compiler-specific includes */

#ifdef USE_PKCS15

/****************************************************************************
*																			*
*								Utility Functions							*
*																			*
****************************************************************************/

/* Check whether we can add anything to a PKCS #15 personality */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 8, 9 ) ) \
static int checkAddInfo( const PKCS15_INFO *pkcs15infoPtr,
						 IN_HANDLE const CRYPT_HANDLE iCryptHandle,
						 const BOOLEAN isCertChain, 
						 const BOOLEAN privkeyPresent,
						 const BOOLEAN certPresent,
						 const BOOLEAN pkcs15keyPresent,
						 const BOOLEAN pkcs15certPresent,
						 OUT BOOLEAN *isCertUpdate, 
						 INOUT ERROR_INFO *errorInfo )
	{
	MESSAGE_DATA msgData;
	BOOLEAN unneededCert, unneededKey;
	int status;

	assert( isReadPtr( pkcs15infoPtr, sizeof( PKCS15_INFO ) ) );
	assert( isWritePtr( isCertUpdate, sizeof( BOOLEAN ) ) );
	
	REQUIRES( isHandleRangeValid( iCryptHandle ) );
	REQUIRES( errorInfo != NULL );

	/* Clear return value */
	*isCertUpdate = FALSE;

	/* Check what we can update (if anything) */
	unneededKey = privkeyPresent & pkcs15keyPresent;
	unneededCert = certPresent & pkcs15certPresent;
	if( ( ( unneededCert && !privkeyPresent ) || \
		  ( unneededKey && unneededCert ) ) && \
		pkcs15infoPtr->validTo > MIN_TIME_VALUE )
		{
		time_t validTo;

		/* The certificate would be a duplicate, see if it's more recent 
		   than the existing one.  We only perform this check if there's a 
		   validTo time stored for the certificate since without this 
		   restriction any certificate without a stored time could be 
		   overwritten */
		setMessageData( &msgData, &validTo, sizeof( time_t ) );
		status = krnlSendMessage( iCryptHandle, IMESSAGE_GETATTRIBUTE_S,
								  &msgData, CRYPT_CERTINFO_VALIDTO );
		if( cryptStatusOK( status ) && validTo > pkcs15infoPtr->validTo )
			{
			time_t validFrom;

			/* It's a newer certificate, don't treat it as a duplicate.  
			   This check is effectively impossible to perform automatically 
			   since there are an infinite number of variations that have to 
			   be taken into account, for example a certificate for the same 
			   key issued by a different CA, same CA but it's changed the 
			   bits it sets in the keyUsage (digitalSignature vs.
			   nonRepudiation), slightly different issuer DN (Thawte 
			   certificates with a date encoded in the DN), and so on and so 
			   on.  Because this really requires manual processing by a 
			   human we don't even try and sort it all out but just allow a 
			   certificate for a given key (checked by the ID match) to be 
			   replaced by a newer certificate for the same key.  This is 
			   restrictive enough to prevent most obviously-wrong 
			   replacements while being permissive enough to allow most 
			   probably-OK replacements */
			unneededCert = FALSE;
			*isCertUpdate = TRUE;

			/* There's one special-case situation in which odd things can 
			   happen when updating certificates and that's when adding a 
			   future-dated certificate, which would result in the 
			   certificate being replaced with one that can't be used yet.  
			   There's no clean way to handle this because in order to know 
			   what to do we'd have to be able to guess the intent of the 
			   user, however for anything but signature certificates it's 
			   likely that the hit-and-miss certificate checking performed 
			   by most software won't even notice a future-dated 
			   certificate, and for signature certificates the semantics of 
			   signing data now using a certificate that isn't valid yet are 
			   somewhat uncertain.  Since in most cases no-one will even 
			   notice the problem, we throw an exception in the debug build 
			   but don't do anything in release builds.  This is probably 
			   less annoying to users than having the code reject an 
			   otherwise-valid future-dated certificate.  If anyone ever
			   complains about this then we can ask the users at that time
			   what sort of behaviour they're prefer */
			setMessageData( &msgData, &validFrom, sizeof( time_t ) );
			status = krnlSendMessage( iCryptHandle, IMESSAGE_GETATTRIBUTE_S,
									  &msgData, CRYPT_CERTINFO_VALIDFROM );
			if( cryptStatusOK( status ) && \
				validFrom > getApproxTime() + 86400L )
				{
				assert( !"Attempt to replace certificate with future-dated certificate" );
				}
			}
		}

	/* Make sure that we can update at least one of the objects in the PKCS 
	   #15 personality */
	if( ( unneededKey && !certPresent ) ||		/* Key only, duplicate */
		( unneededCert && !privkeyPresent ) ||	/* Certificate only, duplicate */
		( unneededKey && unneededCert ) )		/* Key+certificate, duplicate */
		{
		/* If it's anything other than a certificate chain, we can't add 
		   anything */
		if( !isCertChain )
			{
			retExt( CRYPT_ERROR_DUPLICATE, 
					( CRYPT_ERROR_DUPLICATE, errorInfo, 
					  "No new data to add" ) );
			}

		/* Tell the caller that it's an opportunistic certificate-chain 
		   update */
		return( OK_SPECIAL );
		}

	return( CRYPT_OK );
	}

/****************************************************************************
*																			*
*									Add a Key								*
*																			*
****************************************************************************/

/* Add an item to the PKCS #15 keyset */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
static int setItemFunction( INOUT KEYSET_INFO *keysetInfoPtr,
							IN_HANDLE const CRYPT_HANDLE cryptHandle,
							IN_ENUM( KEYMGMT_ITEM ) \
								const KEYMGMT_ITEM_TYPE itemType,
							IN_BUFFER_OPT( passwordLength ) const char *password, 
							IN_LENGTH_NAME_Z const int passwordLength,
							IN_FLAGS( KEYMGMT ) const int flags )
	{
	CRYPT_CERTIFICATE iCryptCert = DUMMY_INIT;
	PKCS15_INFO *pkcs15info = keysetInfoPtr->keyData, *pkcs15infoPtr;
	MESSAGE_DATA msgData;
	BYTE iD[ CRYPT_MAX_HASHSIZE + 8 ];
	BOOLEAN certPresent = FALSE, privkeyPresent;
	BOOLEAN pkcs15certPresent = FALSE, pkcs15keyPresent = FALSE;
	BOOLEAN isCertChain = FALSE, isCertUpdate = FALSE;
	const int noPkcs15objects = keysetInfoPtr->keyDataNoObjects;
	int pkcs15index = CRYPT_ERROR, iDsize, value, status;

	assert( isWritePtr( keysetInfoPtr, sizeof( KEYSET_INFO ) ) );
	assert( isWritePtr( pkcs15info, \
						sizeof( PKCS15_INFO ) * noPkcs15objects ) );

	REQUIRES( keysetInfoPtr->type == KEYSET_FILE && \
			  keysetInfoPtr->subType == KEYSET_SUBTYPE_PKCS15 );
	REQUIRES( isHandleRangeValid( cryptHandle ) );
	REQUIRES( itemType == KEYMGMT_ITEM_PUBLICKEY || \
			  itemType == KEYMGMT_ITEM_PRIVATEKEY || \
			  itemType == KEYMGMT_ITEM_SECRETKEY );
	REQUIRES( ( password == NULL && passwordLength == 0 ) || \
			  ( password != NULL && \
				passwordLength >= MIN_NAME_LENGTH && \
				passwordLength < MAX_ATTRIBUTE_SIZE ) );
	REQUIRES( ( itemType == KEYMGMT_ITEM_PUBLICKEY && \
				password == NULL && passwordLength == 0 ) || \
			  ( ( itemType == KEYMGMT_ITEM_PRIVATEKEY || \
				  itemType == KEYMGMT_ITEM_SECRETKEY ) && \
				password != NULL && passwordLength != 0 ) );
	REQUIRES( flags == KEYMGMT_FLAG_NONE );

	/* If we're being sent a secret key, add it to the PKCS #15 keyset and 
	   exit */
	if( itemType == KEYMGMT_ITEM_SECRETKEY )
		return( addSecretKey( pkcs15info, noPkcs15objects, cryptHandle ) );

	/* Check the object, extract ID information from it, and determine
	   whether it's a standalone certificate (which produces a PKCS #15 
	   certificate object) or a private-key context (which produces a PKCS 
	   #15 private key object and either a PKCS #15 public-key object (if 
	   there's no certificate present) or a certificate object (if there's 
	   a certificate present)).

	   Note that we don't allow the addition of standalone public keys
	   (without corresponding private keys) since file keysets are private-
	   key keysets and not general-purpose public key exchange mechanisms.
	   Without this safeguard some users would use them as a general public-
	   key store in place of database keysets or (more rarely) as a type of 
	   unsigned certificate for exchanging public keys.
	   
	   In addition allowing the storage of standalone public keys is rather 
	   problematic since they need to have a label attached in order to be 
	   identified so performing a public-key add with a private-key context 
	   would work but performing one with a public-key context would fail.  
	   A certificate update on this public-key-only item would result in the 
	   presence a private-key-labelled certificate, which is even more 
	   strange for users to comprehend.  To keep things sensible we 
	   therefore disallow the addition of standalone public keys */
	status = krnlSendMessage( cryptHandle, IMESSAGE_CHECK, NULL,
							  MESSAGE_CHECK_PKC );
	if( cryptStatusError( status ) )
		return( cryptArgError( status ) ? CRYPT_ARGERROR_NUM1 : status );
	setMessageData( &msgData, iD, CRYPT_MAX_HASHSIZE );
	status = krnlSendMessage( cryptHandle, IMESSAGE_GETATTRIBUTE_S,
							  &msgData, CRYPT_IATTRIBUTE_KEYID );
	if( cryptStatusError( status ) )
		return( status );
	iDsize = msgData.length;
	privkeyPresent = cryptStatusOK( \
			krnlSendMessage( cryptHandle, IMESSAGE_CHECK, NULL,
							 MESSAGE_CHECK_PKC_PRIVATE ) ) ? TRUE : FALSE;

	/* If we're adding a private key make sure that there's a context and a
	   password present.  Conversely if we're adding a public key make sure 
	   that there's no password present.  The password-check has already 
	   been performed by the kernel but we perform a second check here just 
	   to be safe.  The private-key check can't be performed by the kernel 
	   since it doesn't know the difference between public- and private-key 
	   contexts */
	switch( itemType )
		{
		case KEYMGMT_ITEM_PUBLICKEY:
			if( password != NULL )
				return( CRYPT_ARGERROR_STR1 );
			break;

		case KEYMGMT_ITEM_PRIVATEKEY:
			if( !privkeyPresent )
				{
				retExtArg( CRYPT_ARGERROR_NUM1, 
						   ( CRYPT_ARGERROR_NUM1, KEYSET_ERRINFO, 
							 "Item being added doesn't contain a private "
							 "key" ) );
				}
			if( password == NULL )
				return( CRYPT_ARGERROR_STR1 );
			break;
		
		default:
			retIntError();
		}

	/* If there's a certificate present make sure that it's something that 
	   can be stored.  We don't treat the wrong type as an error since we 
	   can still store the public/private key components even if we don't 
	   store the certificate */
	if( cryptStatusOK( \
		krnlSendMessage( cryptHandle, IMESSAGE_GETATTRIBUTE, &value,
						 CRYPT_CERTINFO_CERTTYPE ) ) && \
		( value == CRYPT_CERTTYPE_CERTIFICATE || \
		  value == CRYPT_CERTTYPE_CERTCHAIN ) )
		{
		/* If it's a certificate chain, remember this for later since we may
		   need to store multiple certificates */
		if( value == CRYPT_CERTTYPE_CERTCHAIN )
			isCertChain = TRUE;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -