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

📄 pkcs12.c

📁 cryptlib安全工具包
💻 C
📖 第 1 页 / 共 3 页
字号:
	int dataSize, i, j;

	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( isReadPtr( pkcs12info, sizeof( PKCS12_INFO ) ) );

	/* Write the item wrapper and item data */
	sMemOpen( &memStream, buffer, 256 );
	if( isPrivateKey )
		{
		writeNonCMSheader( &memStream, OID_PKCS12_SHROUDEDKEYBAG,
						   pkcs12info->privKeyDataSize,
						   attrDataSize );
		dataPtr = pkcs12info->privKeyData;
		dataSize = pkcs12info->privKeyDataSize;
		}
	else
		{
		writeNonCMSheader( &memStream, OID_PKCS12_CERTBAG, ( int ) \
						   ( sizeofOID( OID_PKCS9_X509CERTIFICATE ) + \
							 sizeofObject( \
								sizeofObject( pkcs12info->certDataSize ) ) ),
							 attrDataSize );
		writeOID( &memStream, OID_PKCS9_X509CERTIFICATE );
		writeConstructed( &memStream, ( int ) \
						  sizeofObject( pkcs12info->certDataSize ), 0 );
		writeOctetStringHole( &memStream, pkcs12info->certDataSize, 
							  DEFAULT_TAG );
		dataPtr = pkcs12info->certData;
		dataSize = pkcs12info->certDataSize;
		}
	assert( stell( &memStream ) < 256 );
	swrite( stream, buffer, stell( &memStream ) );
	status = swrite( stream, dataPtr, dataSize );
	if( cryptStatusError( status ) )
		{
		sMemClose( &memStream );
		return( status );
		}

	/* Mac the payload data if necessary */
	if( macData )
		{
		status = krnlSendMessage( pkcs12info->iMacContext, IMESSAGE_CTX_HASH,
								  buffer, stell( &memStream ) );
		if( cryptStatusOK( status ) )
			status = krnlSendMessage( pkcs12info->iMacContext, 
									  IMESSAGE_CTX_HASH, dataPtr, dataSize );
		if( cryptStatusError( status ) )
			{
			sMemClose( &memStream );
			return( status );
			}
		}
	sMemClose( &memStream );

	/* Write the item's ID and label.  These are supposedly optional, but
	   some apps will break if they're not present.  We have to keep the ID
	   short (rather than using, say, a keyID) because some apps assume that 
	   it's a 32-bit int or a similar type of value */
	sMemOpen( &memStream, buffer, 256 );
	writeSet( &memStream, attrDataSize );
	writeSequence( &memStream, idDataSize );
	writeOID( &memStream, OID_PKCS9_LOCALKEYID );
	writeSet( &memStream, sizeofObject( 1 ) );
	writeOctetStringHole( &memStream, 1, DEFAULT_TAG );
	sputc( &memStream, pkcs12info->index );
	writeSequence( &memStream, labelDataSize );
	writeOID( &memStream, OID_PKCS9_FRIENDLYNAME );
	writeSet( &memStream, ( int ) sizeofObject( pkcs12info->labelLength * 2 ) );
	writeGenericHole( &memStream, pkcs12info->labelLength * 2,
					  BER_STRING_BMP );
	for( i = 0, j = 0; i < pkcs12info->labelLength && \
					   i < CRYPT_MAX_TEXTSIZE; i++ )
		{
		/* Convert the ASCII string into a BMP string */
		sputc( &memStream, 0 );
		sputc( &memStream, pkcs12info->label[ i ] );
		}
	if( i >= CRYPT_MAX_TEXTSIZE )
		retIntError();
	assert( stell( &memStream ) < 256 );
	status = swrite( stream, buffer, stell( &memStream ) );
	if( cryptStatusError( status ) )
		{
		sMemClose( &memStream );
		return( status );
		}

	/* Mac the attribute data if necessary */
	if( macData )
		{
		status = krnlSendMessage( pkcs12info->iMacContext, 
								  IMESSAGE_CTX_HASH, buffer, 
								  stell( &memStream ) );
		if( cryptStatusError( status ) )
			{
			sMemClose( &memStream );
			return( status );
			}
		}
	sMemClose( &memStream );

	return( CRYPT_OK );
	}

/* Flush a PKCS #12 collection to a stream */

static int pkcs12Flush( STREAM *stream, const PKCS12_INFO *pkcs12info )
	{
	STREAM memStream;
	MESSAGE_DATA msgData;
	BYTE buffer[ 32 + 8 ];
	BOOLEAN privateKeyPresent = FALSE;
	int safeDataSize, authSafeDataSize, macDataSize, i, status = CRYPT_OK;

	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( isReadPtr( pkcs12info, sizeof( PKCS12_INFO ) ) );

	/* Determine the overall size of the objects */
	sMemNullOpen( &memStream );
	for( i = 0; cryptStatusOK( status ) && i < MAX_PKCS12_OBJECTS; i++ )
		{
		if( pkcs12info[ i ].privKeyDataSize > 0 )
			{
			privateKeyPresent = TRUE;
			status = writeItem( &memStream, pkcs12info, TRUE, FALSE );
			}
		if( pkcs12info[ i ].certDataSize > 0 )
			status = writeItem( &memStream, pkcs12info, FALSE, FALSE );
		}
	safeDataSize = stell( &memStream );
	sMemClose( &memStream );
	if( cryptStatusError( status ) )
		return( status );
	if( !privateKeyPresent )
		{
		/* If there's no data present, let the caller know that the keyset
		   is empty */
		return( OK_SPECIAL );
		}
	authSafeDataSize = ( int ) \
					sizeofObject( \
						sizeofObject( \
							sizeofOID( OID_CMS_DATA ) + \
							sizeofObject( \
								sizeofObject( sizeofObject( safeDataSize ) ) ) ) );
	macDataSize = ( int ) \
				sizeofObject( \
					sizeofAlgoID( CRYPT_ALGO_SHA ) + \
					sizeofObject( 20 ) ) + \
				sizeofObject( pkcs12info->macSaltSize ) + \
				sizeofShortInteger( pkcs12info->macIterations );

	/* Write the outermost (authSafe) layer of cruft */
	writeSequence( stream, ( int ) \
				   sizeofShortInteger( 3 ) + \
				   sizeofObject( \
						sizeofOID( OID_CMS_DATA ) + \
						sizeofObject( \
							sizeofObject( authSafeDataSize ) ) ) + \
				   sizeofObject( macDataSize ) );
	writeShortInteger( stream, 3, DEFAULT_TAG );
	writeCMSheader( stream, OID_CMS_DATA, authSafeDataSize,
					TRUE );

	/* Create an intermediate memory stream so we can MAC the data before we
	   write it to disk */
	sMemOpen( &memStream, buffer, 32 );

	/* Write and MAC the next layer (safe) of cruft */
	writeSequence( &memStream, ( int ) \
				   sizeofObject( \
						sizeofOID( OID_CMS_DATA ) + \
						sizeofObject( \
							sizeofObject( sizeofObject( safeDataSize ) ) ) ) );
	writeCMSheader( &memStream, OID_CMS_DATA, sizeofObject( safeDataSize ),
					TRUE );
	writeSequence( &memStream, safeDataSize );
	assert( stell( &memStream ) < 32 );
	swrite( stream, buffer, stell( &memStream ) );
	status = krnlSendMessage( pkcs12info->iMacContext, IMESSAGE_CTX_HASH, 
							  buffer, stell( &memStream ) );
	sMemClose( &memStream );
	if( cryptStatusError( status ) )
		return( status );

	/* Write the individual objects */
	for( i = 0; cryptStatusOK( status ) && i < MAX_PKCS12_OBJECTS; i++ )
		{
		if( pkcs12info[ i ].privKeyDataSize > 0 )
			writeItem( stream, pkcs12info, TRUE, TRUE );
		if( pkcs12info[ i ].certDataSize > 0 )
			writeItem( stream, pkcs12info, FALSE, TRUE );
		}
	if( cryptStatusError( status ) )
		return( status );

	/* Wrap up the MACing and write the MAC data.  Despite the fact that the
	   algorithm being used is HMAC, the OID we have to write is the one for 
	   plain SHA-1 */
	status = krnlSendMessage( pkcs12info->iMacContext, IMESSAGE_CTX_HASH, 
							  "", 0 );
	if( cryptStatusOK( status ) )
		{
		setResourceData( &msgData, buffer, CRYPT_MAX_HASHSIZE );
		status = krnlSendMessage( pkcs12info->iMacContext, 
								  IMESSAGE_GETATTRIBUTE_S, &msgData, 
								  CRYPT_CTXINFO_HASHVALUE );
		}
	if( cryptStatusError( status ) )
		return( status );
	writeSequence( stream, macDataSize );
	writeSequence( stream, sizeofAlgoID( CRYPT_ALGO_SHA ) + \
						   sizeofObject( 20 ) );
	writeAlgoID( stream, CRYPT_ALGO_SHA );
	writeOctetString( stream, buffer, msgData.length, DEFAULT_TAG );
	writeOctetString( stream, pkcs12info->macSalt, pkcs12info->macSaltSize,
					  DEFAULT_TAG );
	status = writeShortInteger( stream, pkcs12info->macIterations, DEFAULT_TAG );
	if( cryptStatusError( status ) )
		return( status );

	return( sflush( stream ) );
	}

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

static int setItemFunction( KEYSET_INFO *keysetInfoPtr,
							const CRYPT_HANDLE cryptHandle,
							const KEYMGMT_ITEM_TYPE itemType,
							const char *password, const int passwordLength,
							const int flags )
	{
	CRYPT_CONTEXT iKeyWrapContext;
	CRYPT_ALGO_TYPE cryptAlgo;
	MECHANISM_WRAP_INFO mechanismInfo;
	PKCS12_INFO *pkcs12infoPtr = keysetInfoPtr->keyData;
	STREAM stream;
	BOOLEAN certPresent = FALSE, contextPresent;
	BOOLEAN pkcs12keyPresent = pkcs12infoPtr->privKeyDataSize ? TRUE : FALSE;
	int privKeyInfoSize, pbeInfoDataSize;
	int value, status;

	assert( isWritePtr( keysetInfoPtr, sizeof( KEYSET_INFO ) ) && \
			keysetInfoPtr->type == KEYSET_FILE && \
			keysetInfoPtr->subType == KEYSET_SUBTYPE_PKCS12 );
	assert( isHandleRangeValid( cryptHandle ) );
	assert( itemType == KEYMGMT_ITEM_PUBLICKEY || \
			itemType == KEYMGMT_ITEM_PRIVATEKEY );

	/* If there's already a key and certificate present, we can't add 
	   anything else.  This check also catches the (invalid) case of a 
	   certificate being present without a corresponding private key */
	if( pkcs12infoPtr->certDataSize > 0 )
		{
		retExt( CRYPT_ERROR_OVERFLOW, 
				( CRYPT_ERROR_OVERFLOW, KEYSET_ERRINFO, 
				  "No more room in keyset to add this item" ) );
		}

	/* Check the object and extract ID information from it */
	status = krnlSendMessage( cryptHandle, IMESSAGE_CHECK, NULL,
							  MESSAGE_CHECK_PKC );
	if( cryptStatusOK( status ) )
		{
		status = krnlSendMessage( cryptHandle, IMESSAGE_GETATTRIBUTE,
								  &cryptAlgo, CRYPT_CTXINFO_ALGO );
		if( cryptStatusOK( status ) && cryptAlgo != CRYPT_ALGO_RSA )
			{
			retExtArg( CRYPT_ARGERROR_NUM1, 
					   ( CRYPT_ARGERROR_NUM1, KEYSET_ERRINFO, 
						 "Standard PKCS #12 can only store RSA keys" ) );
			}
		}
	if( cryptStatusError( status ) )
		return( ( status == CRYPT_ARGERROR_OBJECT ) ? \
				CRYPT_ARGERROR_NUM1 : status );
	contextPresent = cryptStatusOK( krnlSendMessage( cryptHandle,
								IMESSAGE_CHECK, NULL,
								MESSAGE_CHECK_PKC_PRIVATE ) ) ? TRUE : FALSE;

	/* 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 */
	status = krnlSendMessage( cryptHandle, IMESSAGE_GETATTRIBUTE,
							  &value, CRYPT_CERTINFO_CERTTYPE );
	if( cryptStatusOK( status ) && \
		( value == CRYPT_CERTTYPE_CERTIFICATE || \
		  value == CRYPT_CERTTYPE_CERTCHAIN ) )
		{
		/* If the certificate isn't signed, we can't store it in this 
		   state */
		status = krnlSendMessage( cryptHandle, IMESSAGE_GETATTRIBUTE,
								  &value, CRYPT_CERTINFO_IMMUTABLE );
		if( cryptStatusError( status ) || !value )
			{
			retExt( CRYPT_ERROR_NOTINITED, 
					( CRYPT_ERROR_NOTINITED, KEYSET_ERRINFO, 
					  "Certificate being added is incomplete (unsigned)" ) );
			}
		certPresent = TRUE;
		if( !pkcs12keyPresent )
			{
			/* We can't add a certificate unless there's already a key 
			   present.  Since PKCS #12 doesn't store any index information, 
			   we have no idea whether the two actually belong together, so 
			   we just have to hope for the best */
			retExt( CRYPT_ERROR_NOTINITED, 
					( CRYPT_ERROR_NOTINITED, KEYSET_ERRINFO, 
					  "No key present that corresponds to certificate being "
					  "added" ) );
			}
		}
	else
		{
		/* If we're trying to add a standalone key and there's already one
		   present, we can't add another one */
		if( pkcs12keyPresent )
			{
			retExt( CRYPT_ERROR_INITED, 
					( CRYPT_ERROR_INITED, KEYSET_ERRINFO, 
					  "No more room in keyset to add this item" ) );
			}
		}

	/* If we're adding a private key, make sure that there's a password 
	   present.  Conversely, if there's a password present make sure that 
	   we're adding a private key */
	if( pkcs12keyPresent )
		{
		/* We're adding a certificate, there can't be a password present */
		if( password != NULL )
			return( CRYPT_ARGERROR_NUM1 );
		}
	else
		{
		/* We're adding a private key, there must be a password present */
		if( password == NULL )
			return( CRYPT_ARGERROR_STR1 );
		}

	/* Get what little index information PKCS #12 stores with a key */
	if( !pkcs12keyPresent )
		{
		MESSAGE_DATA msgData;

		setResourceData( &msgData, pkcs12infoPtr->label, CRYPT_MAX_TEXTSIZE );
		status = krnlSendMessage( cryptHandle, IMESSAGE_GETATTRIBUTE_S,
								  &msgData, CRYPT_CTXINFO_LABEL );
		if( cryptStatusError( status ) )
			return( status );
		pkcs12infoPtr->labelLength = msgData.length;
		pkcs12infoPtr->index = 1;
		}

	/* We're ready to go, lock the object for our exclusive use */
	status = krnlSendNotifier( cryptHandle, IMESSAGE_LOCK );
	if( cryptStatusError( status ) )
		return( status );

	/* Write the certificate if necessary.  We do this one first because 
	   it's the easiest to back out of */
	if( certPresent )
		{
		MESSAGE_DATA msgData;

⌨️ 快捷键说明

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