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

📄 pkcs15_wr.c

📁 cryptlib是功能强大的安全工具集。允许开发人员快速在自己的软件中集成加密和认证服务。
💻 C
📖 第 1 页 / 共 5 页
字号:
	/* Determine how big the public key attribute collections will be */
	keyUsage &= PUBKEY_USAGE_MASK;
	commonKeyAttributeSize = ( int ) sizeofObject( pkcs15info->iDlength ) + \
							 sizeofBitString( keyUsage ) + \
							 sizeofBitString( KEYATTR_ACCESS_PUBLIC );
	if( pkcs15info->validFrom )
		commonKeyAttributeSize += sizeofGeneralizedTime();
	if( pkcs15info->validTo )
		commonKeyAttributeSize += sizeofGeneralizedTime();

	/* Write the public key attributes */
	sMemOpen( &stream, pubKeyAttributes, KEYATTR_BUFFER_SIZE );
	writeSequence( &stream, commonAttributeSize );
	writeCharacterString( &stream, ( BYTE * ) pkcs15info->label,
						  pkcs15info->labelLength, BER_STRING_UTF8 );
	writeSequence( &stream, commonKeyAttributeSize );
	writeOctetString( &stream, pkcs15info->iD, pkcs15info->iDlength,
					  DEFAULT_TAG );
	writeBitString( &stream, keyUsage, DEFAULT_TAG );
	status = writeBitString( &stream, KEYATTR_ACCESS_PUBLIC, DEFAULT_TAG );
	if( pkcs15info->validFrom )
		status = writeGeneralizedTime( &stream, pkcs15info->validFrom, \
									   DEFAULT_TAG );
	if( pkcs15info->validTo )
		status = writeGeneralizedTime( &stream, pkcs15info->validTo, \
									   CTAG_KA_VALIDTO );
	*pubKeyAttributeSize = stell( &stream );
	assert( sStatusOK( &stream ) );
	sMemDisconnect( &stream );
	pkcs15info->pubKeyUsage = keyUsage;		/* Update stored usage info */

	return( status );
	}

static int writeCertAttributes( void *certAttributes,
								int *certAttributeSize,
							    PKCS15_INFO *pkcs15info,
								const CRYPT_HANDLE cryptHandle )
	{
	STREAM stream;
	BOOLEAN trustedImplicit = FALSE;
	int isCA, trustedUsage, status;
	int commonAttributeSize, commonCertAttributeSize;
	int keyIdentifierDataSize, trustedUsageSize;

	/* Get various pieces of information from the object.  If we're adding a
	   standalone cert then the iD and keyID won't have been set up yet, so
	   we need to set these up as well.  Since the cert could be a data-only
	   cert, we create the iD ourselves from the encoded public key
	   components rather than trying to read an associated context's keyID
	   attribute.  For similar reasons we specifically don't try and read the
	   PGP ID information since for a cert chain it'll come from the context
	   of the leaf cert rather than the current cert (in any case they're not
	   necessary since none of the certs in the chain will be PGP keys */
	status = krnlSendMessage( cryptHandle, IMESSAGE_GETATTRIBUTE, &isCA, 
							  CRYPT_CERTINFO_CA );
	if( status == CRYPT_ERROR_NOTFOUND )
		{
		isCA = FALSE;
		status = CRYPT_OK;
		}
	if( cryptStatusOK( status ) )
		{
		status = krnlSendMessage( cryptHandle, IMESSAGE_GETATTRIBUTE, 
							&trustedUsage, CRYPT_CERTINFO_TRUSTED_USAGE );
		if( status == CRYPT_ERROR_NOTFOUND )
			{
			/* If there's no trusted usage defined, don't store a trust
			   setting */
			trustedUsage = CRYPT_UNUSED;
			status = CRYPT_OK;
			}
		}
	if( cryptStatusOK( status ) )
		{
		status = krnlSendMessage( cryptHandle, IMESSAGE_GETATTRIBUTE, 
							&trustedImplicit, CRYPT_CERTINFO_TRUSTED_IMPLICIT );
		if( status == CRYPT_ERROR_NOTFOUND )
			{
			/* If it's not implicitly trusted, don't store a trust setting */
			trustedImplicit = FALSE;
			status = CRYPT_OK;
			}
		}
	if( cryptStatusOK( status ) )
		status = getValidityInfo( pkcs15info, cryptHandle );
	if( cryptStatusOK( status ) )
		{
		RESOURCE_DATA msgData;

		setMessageData( &msgData, pkcs15info->pgp2KeyID, PGP_KEYID_SIZE );
		status = krnlSendMessage( cryptHandle, IMESSAGE_GETATTRIBUTE_S,
								  &msgData, CRYPT_IATTRIBUTE_KEYID_PGP );
		if( cryptStatusOK( status ) )
			/* Not present for all key types, so an error isn't fatal */
			pkcs15info->pgp2KeyIDlength = msgData.length;
		setMessageData( &msgData, pkcs15info->openPGPKeyID, PGP_KEYID_SIZE );
		status = krnlSendMessage( cryptHandle, IMESSAGE_GETATTRIBUTE_S,
								  &msgData, CRYPT_IATTRIBUTE_KEYID_OPENPGP );
		pkcs15info->openPGPKeyIDlength = msgData.length;
		}
	if( cryptStatusError( status ) )
		return( status );
	if( !pkcs15info->iDlength )
		{
		status = getCertID( cryptHandle, CRYPT_IATTRIBUTE_SPKI,
							pkcs15info->iD );
		if( cryptStatusError( status ) )
			return( status );
		pkcs15info->iDlength = KEYID_SIZE;
		}
	if( !pkcs15info->keyIDlength )
		{
		RESOURCE_DATA msgData;

		setMessageData( &msgData, pkcs15info->keyID, CRYPT_MAX_HASHSIZE );
		status = krnlSendMessage( cryptHandle, IMESSAGE_GETATTRIBUTE_S,
								  &msgData, CRYPT_CERTINFO_SUBJECTKEYIDENTIFIER );
		if( cryptStatusOK( status ) )
			pkcs15info->keyIDlength = msgData.length;
		else
			{
			memcpy( pkcs15info->keyID, pkcs15info->iD, pkcs15info->iDlength );
			pkcs15info->keyIDlength = pkcs15info->iDlength;
			}
		}

	/* At this point we could create a pseudo-label by walking up the cert DN
	   from the CN until we find a component we can use, however label-less
	   items will only occur when adding a standalone (i.e. trusted, 
	   implicitly-handled) cert.  If we were to set labels for these, the 
	   keyset would end up acting as a general-purpose certificate store 
	   which it isn't meant to be, so we always leave implicitly handled 
	   certs label-less */

	/* Calculate the various IDs for the cert */
	status = getCertID( cryptHandle, CRYPT_IATTRIBUTE_ISSUERANDSERIALNUMBER,
						pkcs15info->iAndSID );
	if( cryptStatusOK( status ) )
		status = getCertID( cryptHandle, CRYPT_IATTRIBUTE_SUBJECT,
							pkcs15info->subjectNameID );
	if( cryptStatusOK( status ) )
		status = getCertID( cryptHandle, CRYPT_IATTRIBUTE_ISSUER,
							pkcs15info->issuerNameID );
	if( cryptStatusError( status ) )
		return( status );
	pkcs15info->iAndSIDlength = pkcs15info->subjectNameIDlength = \
		pkcs15info->issuerNameIDlength = KEYID_SIZE;
	trustedUsageSize = ( trustedUsage != CRYPT_UNUSED ) ? \
					   sizeofBitString( trustedUsage ) : 0;
	keyIdentifierDataSize = sizeofObjectIDs( pkcs15info );

	/* Determine how big the attribute collection will be */
	commonAttributeSize = pkcs15info->labelLength ? \
						  ( int) sizeofObject( pkcs15info->labelLength ) : 0;
	commonCertAttributeSize = ( int ) \
						sizeofObject( pkcs15info->iDlength ) + \
						( isCA ? sizeofBoolean() : 0 ) + \
						( ( trustedUsage != CRYPT_UNUSED ) ? \
						  sizeofObject( trustedUsageSize ) : 0 ) + \
						sizeofObject( keyIdentifierDataSize ) + \
						( trustedImplicit ? sizeofBoolean() : 0 ) + \
						sizeofGeneralizedTime() + sizeofGeneralizedTime();

	/* Write the cert attributes */
	sMemOpen( &stream, certAttributes, KEYATTR_BUFFER_SIZE );
	writeSequence( &stream, commonAttributeSize );
	if( commonAttributeSize )
		writeCharacterString( &stream, pkcs15info->label,
							  pkcs15info->labelLength, BER_STRING_UTF8 );
	writeSequence( &stream, commonCertAttributeSize );
	writeOctetString( &stream, pkcs15info->iD, pkcs15info->iDlength,
					  DEFAULT_TAG );
	if( isCA )
		writeBoolean( &stream, TRUE, DEFAULT_TAG );
	if( trustedUsage != CRYPT_UNUSED )
		{
		writeConstructed( &stream, trustedUsageSize, CTAG_CA_TRUSTED_USAGE );
		writeBitString( &stream, trustedUsage, DEFAULT_TAG );
		}
	writeObjectIDs( &stream, pkcs15info, keyIdentifierDataSize, 
					CTAG_CA_IDENTIFIERS );
	if( trustedImplicit )
		writeBoolean( &stream, TRUE, CTAG_CA_TRUSTED_IMPLICIT );
	writeGeneralizedTime( &stream, pkcs15info->validFrom, DEFAULT_TAG );
	status = writeGeneralizedTime( &stream, pkcs15info->validTo, \
								   CTAG_CA_VALIDTO );
	*certAttributeSize = stell( &stream );
	assert( sStatusOK( &stream ) );
	sMemDisconnect( &stream );

	return( status );
	}

/****************************************************************************
*																			*
*									Write a Key								*
*																			*
****************************************************************************/

/* When adding key/cert data to a PKCS #15 collection, we have to be able to 
   cleanly handle the addition of arbitrary collections of objects, which 
   leads to some rather convoluted logic for deciding what needs updating 
   and under which conditions.  The actions taken are:

	key only:	if present
					return( CRYPT_ERROR_DUPLICATE )
				else
					add key;
	cert only:	if present
					return( CRYPT_ERROR_DUPLICATE );
				elif( matching key present )
#ifdef RETAIN_PUBKEY
					add, update key data;
#else
					add, delete key data;
#endif // RETAIN_PUBKEY
				elif( trusted cert )
					add as trusted cert;
				else
					error;
	key+cert:	if key present and cert present
					return( CRYPT_ERROR_DUPLICATE );
#ifdef RETAIN_PUBKEY
				if key present -> don't add key;
#else
				delete key;
#endif // RETAIN_PUBKEY
				if cert present -> don't add cert;

   The following values specify the action to be taken when adding a cert */

typedef enum {
	CERTADD_UPDATE_EXISTING,/* Update existing key info with a cert */
	CERTADD_NORMAL,			/* Add a cert for which no key info present */
	CERTADD_STANDALONE_CERT	/* Add a standalone cert not assoc'd with a key */
	} CERTADD_TYPE;

/* Determine the tag to use when encoding a given key type.  There isn't any
   tag for Elgamal but the keys are the same as X9.42 DH keys and cryptlib
   uses the OID rather than the tag to determine the key type, so the 
   following sleight-of-hand works */

static int getKeyTypeTag( const CRYPT_CONTEXT cryptContext )
	{
	CRYPT_ALGO_TYPE cryptAlgo;
	int status;

	status = krnlSendMessage( cryptContext, IMESSAGE_GETATTRIBUTE,
							  &cryptAlgo, CRYPT_CTXINFO_ALGO );
	if( cryptStatusError( status ) )
		return( status );
	switch( cryptAlgo )
		{
		case CRYPT_ALGO_RSA:
			return( DEFAULT_TAG );

		case CRYPT_ALGO_DH:
		case CRYPT_ALGO_ELGAMAL:
			return( 1 );

		case CRYPT_ALGO_DSA:
			return( 2 );

		case CRYPT_ALGO_KEA:
			return( 3 );
		}

	assert( NOTREACHED );
	return( 0 );	/* Get rid of compiler warning */
	}

/* Generate a session key and write the wrapped key in the form
   SET OF {	[ 0 ] (EncryptedKey) } */

static int writeWrappedSessionKey( STREAM *stream,
								   CRYPT_CONTEXT iSessionKeyContext,
								   const CRYPT_USER cryptOwner,
								   const char *password,
								   const int passwordLength )
	{
	MESSAGE_CREATEOBJECT_INFO createInfo;
	CRYPT_ALGO_TYPE cryptAlgo;
	int iterations, exportedKeySize, status;

	/* In the interests of luser-proofing, we're really paranoid and force
	   the use of non-weak algorithms and modes of operation.  In addition
	   since OIDs are only defined for a limited subset of algorithms, we
	   also default to a guaranteed available algorithm if no OID is defined
	   for the one requested */
	krnlSendMessage( cryptOwner, IMESSAGE_GETATTRIBUTE, &cryptAlgo,
					 CRYPT_OPTION_ENCR_ALGO );
	if( isWeakCryptAlgo( cryptAlgo ) || \
		cryptStatusError( sizeofAlgoIDex( cryptAlgo,
									( CRYPT_ALGO_TYPE ) CRYPT_MODE_CBC, 0 ) ) )
		cryptAlgo = CRYPT_ALGO_3DES;
	krnlSendMessage( cryptOwner, IMESSAGE_GETATTRIBUTE, &iterations,
					 CRYPT_OPTION_KEYING_ITERATIONS );
	if( iterations < MIN_KEYING_ITERATIONS )
		iterations = MIN_KEYING_ITERATIONS;

	/* Create an encryption context and derive the user password into it */
	setMessageCreateObjectInfo( &createInfo, cryptAlgo );
	status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_DEV_CREATEOBJECT,
							  &createInfo, OBJECT_TYPE_CONTEXT );
	if( cryptStatusError( status ) )
		return( status );
	status = krnlSendMessage( createInfo.cryptHandle, IMESSAGE_SETATTRIBUTE, 
							  &iterations, CRYPT_CTXINFO_KEYING_ITERATIONS );
	if( cryptStatusOK( status ) )
		{
		RESOURCE_DATA msgData;

		setMessageData( &msgData, ( void * ) password, passwordLength );
		status = krnlSendMessage( createInfo.cryptHandle,
								  IMESSAGE_SETATTRIBUTE_S, &msgData, 
								  CRYPT_CTXINFO_KEYING_VALUE );
		}
	if( cryptStatusError( status ) )
		{
		krnlSendNotifier( createInfo.cryptHandle, IMESSAGE_DECREFCOUNT );
		return( status );
		}

	/* Determine the size of the exported key and write the encrypted data
	   content field */
	if( cryptStatusOK( status ) )
		status = iCryptExportKeyEx( NULL, &exportedKeySize, 0, 
									CRYPT_FORMAT_CMS, iSessionKeyContext, 
									createInfo.cryptHandle, CRYPT_UNUSED );
	if( cryptStatusOK( status ) )
		{
		writeSet( stream, exportedKeySize );
		status = iCryptExportKeyEx( sMemBufPtr( stream ), &exportedKeySize, 
									sMemDataLeft( stream ), CRYPT_FORMAT_CMS, 
									iSessionKeyContext, createInfo.cryptHandle, 

⌨️ 快捷键说明

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