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

📄 pkcs12.c

📁 cryptlib安全工具包
💻 C
📖 第 1 页 / 共 3 页
字号:
		/* Select the leaf certificate in case it's a certificate chain */
		krnlSendMessage( cryptHandle, IMESSAGE_SETATTRIBUTE,
						 MESSAGE_VALUE_CURSORFIRST,
						 CRYPT_CERTINFO_CURRENT_CERTIFICATE );

		/* Get the encoded certificate */
		setResourceData( &msgData, NULL, 0 );
		status = krnlSendMessage( cryptHandle, IMESSAGE_GETATTRIBUTE_S,
								  &msgData, CRYPT_IATTRIBUTE_ENC_CERT );
		if( cryptStatusOK( status ) && \
			( pkcs12infoPtr->certData = clAlloc( "setItemFunction", \
												 msgData.length ) ) == NULL )
			status = CRYPT_ERROR_MEMORY;
		if( cryptStatusOK( status ) )
			{
			msgData.data = pkcs12infoPtr->certData;
			status = krnlSendMessage( cryptHandle, IMESSAGE_GETATTRIBUTE_S,
									  &msgData, CRYPT_IATTRIBUTE_ENC_CERT );
			if( cryptStatusOK( status ) )
				pkcs12infoPtr->certDataSize = msgData.length;
			else
				{
				clFree( "setItemFunction", pkcs12infoPtr->certData );
				pkcs12infoPtr->certData = NULL;
				}
			}

		/* If there's no context to add, return now */
		if( cryptStatusError( status ) || pkcs12keyPresent )
			{
			krnlSendNotifier( cryptHandle, IMESSAGE_UNLOCK );
			retExt( status, 
					( status, KEYSET_ERRINFO, 
					  "Couldn't extract certificate data from "
					  "certificate" ) );
			}
		}

	/* Create the key wrap context and the MAC context (if necessary) from 
	   the password.  See the comment at the start of the file for the 
	   ambiguity involved with the MAC context */
	status = createKeyWrapContext( &iKeyWrapContext, 
								   keysetInfoPtr->ownerHandle, 
								   password, passwordLength, pkcs12infoPtr );
	if( cryptStatusOK( status ) && pkcs12infoPtr->iMacContext == CRYPT_ERROR )
		status = createMacContext( pkcs12infoPtr, keysetInfoPtr->ownerHandle, 
								   password, passwordLength );
	if( cryptStatusError( status ) )
		{
		pkcs12freeEntry( pkcs12infoPtr );
		krnlSendNotifier( cryptHandle, IMESSAGE_UNLOCK );
		retExt( status, 
				( status, KEYSET_ERRINFO, 
				  "Couldn't create session/MAC key to secure private "
				  "key" ) );
		}

	/* Calculate the eventual encrypted key size and allocate storage for it */
	setMechanismWrapInfo( &mechanismInfo, NULL, 0, NULL, 0, cryptHandle,
						  iKeyWrapContext, CRYPT_UNUSED );
	status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_DEV_EXPORT, 
							  &mechanismInfo, MECHANISM_PRIVATEKEYWRAP_PKCS8 );
	privKeyInfoSize = mechanismInfo.wrappedDataLength;
	clearMechanismInfo( &mechanismInfo );
	if( cryptStatusOK( status ) && \
		( pkcs12infoPtr->privKeyData = \
				clAlloc( "setItemFunction", privKeyInfoSize + 64 ) ) == NULL )
			status = CRYPT_ERROR_MEMORY;
	if( cryptStatusError( status ) )
		{
		pkcs12freeEntry( pkcs12infoPtr );
		krnlSendNotifier( iKeyWrapContext, IMESSAGE_DECREFCOUNT );
		krnlSendNotifier( cryptHandle, IMESSAGE_UNLOCK );
		return( status );
		}
	pkcs12infoPtr->privKeyDataSize = privKeyInfoSize + 64;

	/* Write the key-derivation information and wrapped key */
	pbeInfoDataSize = ( int ) sizeofObject( pkcs12infoPtr->wrapSaltSize ) + \
					  sizeofShortInteger( pkcs12infoPtr->wrapIterations );
	sMemOpen( &stream, pkcs12infoPtr->privKeyData,
			  pkcs12infoPtr->privKeyDataSize );
	writeSequence( &stream,
				   sizeofOID( OID_PKCS12_PBEWITHSHAAND2KEYTRIPLEDESCBC ) + \
				   ( int ) sizeofObject( pbeInfoDataSize ) );
	writeOID( &stream, OID_PKCS12_PBEWITHSHAAND2KEYTRIPLEDESCBC );
	writeSequence( &stream, pbeInfoDataSize );
	writeOctetString( &stream, pkcs12infoPtr->wrapSalt, 
					  pkcs12infoPtr->wrapSaltSize, DEFAULT_TAG );
	writeShortInteger( &stream, pkcs12infoPtr->wrapIterations, DEFAULT_TAG );
	status = writeOctetStringHole( &stream, privKeyInfoSize, DEFAULT_TAG );
	assert( stell( &stream ) < 64 );
	if( cryptStatusError( status ) )
		{
		sMemClose( &stream );
		pkcs12freeEntry( pkcs12infoPtr );
		krnlSendNotifier( iKeyWrapContext, IMESSAGE_DECREFCOUNT );
		krnlSendNotifier( cryptHandle, IMESSAGE_UNLOCK );
		retExt( status, 
				( status, KEYSET_ERRINFO, 
				  "Couldn't write wrapped private key header" ) );
		}
	setMechanismWrapInfo( &mechanismInfo,
						  ( BYTE * ) pkcs12infoPtr->privKeyData + \
									 ( int ) stell( &stream ),
						  privKeyInfoSize, NULL, 0, cryptHandle,
						  iKeyWrapContext, CRYPT_UNUSED );
	status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_DEV_EXPORT, 
							  &mechanismInfo, MECHANISM_PRIVATEKEYWRAP_PKCS8 );
	if( cryptStatusOK( status ) )
		pkcs12infoPtr->privKeyDataSize = ( int ) stell( &stream ) + \
										 privKeyInfoSize;
	else
		pkcs12freeEntry( pkcs12infoPtr );
	sMemDisconnect( &stream );
	krnlSendNotifier( cryptHandle, IMESSAGE_UNLOCK );
	if( cryptStatusError( status ) )
		{
		retExt( status, 
				( status, KEYSET_ERRINFO, 
				  "Couldn't wrap/MAC private key data" ) );
		}

	return( CRYPT_OK );
	}

/****************************************************************************
*																			*
*								Init/Shutdown Functions						*
*																			*
****************************************************************************/

/* At one point Netscape produced PKCS #12 files with each primitive portion
   of encapsulated content (T, L, and V) wrapped up in its own constructed
   OCTET STRING segment.  The following function unpacks this mess */

static int unwrapOctetString( STREAM *stream, BYTE *buffer,
							  const int totalLength )
	{
	int bufPos = 0, iterationCount = 0, status;

	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( buffer != NULL );
	assert( totalLength > 0 );

	status = checkEOC( stream );
	while( !cryptStatusError( status ) && status != TRUE && \
		   iterationCount++ < FAILSAFE_ITERATIONS_LARGE )
		{
		int length;

		/* Read the current OCTET STRING segment into the buffer */
		status = readOctetStringHole( stream, &length, DEFAULT_TAG );
		if( cryptStatusError( status ) )
			return( status );

		/* Make sure that we don't overshoot the buffer if the length 
		   encodings are wrong */
		if( bufPos + length > totalLength )
			return( CRYPT_ERROR_BADDATA );

		/* Copy in the current segment */
		status = sread( stream, buffer + bufPos, length );
		if( cryptStatusError( status ) )
			return( status );
		bufPos += length;

		status = checkEOC( stream );
		}
	if( iterationCount >= FAILSAFE_ITERATIONS_LARGE )
		retIntError();
	if( cryptStatusError( status ) )
		return( status );

	return( bufPos );
	}

/* A PKCS #12 file can contain steaming mounds of keys and whatnot, so when we
   open it we scan it and record various pieces of information about it which
   we can use later when we need to access it */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
static int initFunction( INOUT KEYSET_INFO *keysetInfoPtr, 
						 STDC_UNUSED const char *name,
						 STDC_UNUSED const int nameLength,
						 IN_ENUM( CRYPT_KEYOPT ) const CRYPT_KEYOPT_TYPE options )
	{
	PKCS12_INFO *pkcs12info;
	STREAM *stream = &keysetInfoPtr->keysetFile->stream, memStream;
	BYTE *buffer;
	BOOLEAN isIndefinite = FALSE;
	long length;
	int totalLength, status;

	assert( isWritePtr( keysetInfoPtr, sizeof( KEYSET_INFO ) ) && \

	REQUIRES( keysetInfoPtr->type == KEYSET_FILE && \
			  keysetInfoPtr->subType == KEYSET_SUBTYPE_PKCS12 );
	REQUIRES( name == NULL && nameLength == 0 );
	REQUIRES( options >= CRYPT_KEYOPT_NONE && options < CRYPT_KEYOPT_LAST );

	/* Read the outer wrapper, version number field, and CMS data wrapper.  
	   We do this before we perform any setup operations to weed out
	   potential problem files */
	if( options != CRYPT_KEYOPT_CREATE )
		{
		long version;

		readSequence( stream, NULL );
		readShortInteger( stream, &version );
		status = readCMSheader( stream, dataOIDselection, &length, FALSE );
		if( cryptStatusError( status ) )
			{
			retExt( status, 
					( status, KEYSET_ERRINFO, 
					  "Invalid PKCS #12 keyset header" ) );
			}
		if( version != 3 )
			return( CRYPT_ERROR_BADDATA );
		}

	/* Allocate the PKCS #12 object information */
	if( ( pkcs12info = clAlloc( "initFunction", \
								sizeof( PKCS12_INFO ) * \
								MAX_PKCS12_OBJECTS ) ) == NULL )
		return( CRYPT_ERROR_MEMORY );
	memset( pkcs12info, 0, sizeof( PKCS12_INFO ) * MAX_PKCS12_OBJECTS );
	keysetInfoPtr->keyData = pkcs12info;
	keysetInfoPtr->keyDataSize = sizeof( PKCS12_INFO ) * MAX_PKCS12_OBJECTS;
	pkcs12info->iMacContext = CRYPT_ERROR;

	/* If this is a newly-created keyset, there's nothing left to do */
	if( options == CRYPT_KEYOPT_CREATE )
		return( CRYPT_OK );

	/* Extract the OCTET STRING data into an in-memory buffer.  If the file
	   is of a known length we allocate a buffer of that size, otherwise we
	   just try for a reasonable value (indefinite-length encodings are only
	   used by broken older Netscape code which breaks each component up into
	   its own OCTET STRING) */
	if( length == CRYPT_UNUSED )
		{
		totalLength = 8192;
		isIndefinite = TRUE;
		}
	else
		totalLength = ( int ) length;
	if( ( buffer = clAlloc( "initFunction", totalLength ) ) == NULL )
		return( CRYPT_ERROR_MEMORY );
	if( isIndefinite )
		status = totalLength = unwrapOctetString( stream, buffer,
												  totalLength );
	else
		status = sread( stream, buffer, totalLength );
	if( cryptStatusError( status ) )
		{
		clFree( "initFunction", buffer );
		retExt( status, 
				( status, KEYSET_ERRINFO, 
				  "Invalid PKCS #12 keyset content" ) );
		}

	/* Extract the next level of unnecessarily nested data from the mess */
	sMemConnect( &memStream, buffer, totalLength );
	readSequence( &memStream, NULL );
	status = readCMSheader( &memStream, keyDataOIDselection, &length, TRUE );
	if( cryptStatusOK( status ) )
		{
		BYTE *innerBuffer;

		/* If it's straight Data, it'll be a PKCS #8 encrypted nested mess
		   rather than a straight encrypted mess */
		isIndefinite = ( length == CRYPT_UNUSED ) ? TRUE : FALSE;
		if( !isIndefinite )
			totalLength = ( int ) length;
		if( ( innerBuffer = clAlloc( "initFunction", totalLength ) ) != NULL )
			{
			if( isIndefinite )
				{
				status = totalLength = unwrapOctetString( &memStream,
												innerBuffer, totalLength );
				if( !cryptStatusError( status ) )
					status = CRYPT_OK;
				}
			else
				status = sread( stream, innerBuffer, totalLength );

			/* At this point you're on your own - this is too ghastly to
			   continue */

			clFree( "initFunction", innerBuffer );
			if( cryptStatusError( status ) )
				{
				sMemDisconnect( &memStream );
				clFree( "initFunction", buffer );
				retExt( status, 
						( status, KEYSET_ERRINFO, 
						  "Invalid PKCS #12 inner content" ) );
				}
			}
		}
	sMemDisconnect( &memStream );
	clFree( "initFunction", buffer );

	return( CRYPT_OK );
	}

/* Shut down the PKCS #12 state, flushing information to disk if necessary */

STDC_NONNULL_ARG( ( 1 ) ) \
static int shutdownFunction( INOUT KEYSET_INFO *keysetInfoPtr )
	{
	assert( isWritePtr( keysetInfoPtr, sizeof( KEYSET_INFO ) ) );

	REQUIRES( keysetInfoPtr->type == KEYSET_FILE && \
			  keysetInfoPtr->subType == KEYSET_SUBTYPE_PKCS12 );

	/* If the contents have been changed, commit the changes to disk */
	if( keysetInfoPtr->flags & KEYSET_DIRTY )
		{
		int status;

		sseek( &keysetInfoPtr->keysetFile->stream, 0 );
		status = pkcs12Flush( &keysetInfoPtr->keysetFile->stream,
							  keysetInfoPtr->keyData );
		if( status == OK_SPECIAL )
			{
			keysetInfoPtr->flags |= KEYSET_EMPTY;
			status = CRYPT_OK;
			}
		}

	/* Free the PKCS #12 object information */
	if( keysetInfoPtr->keyData != NULL )
		{
		pkcs12Free( keysetInfoPtr->keyData );
		zeroise( keysetInfoPtr->keyData, keysetInfoPtr->keyDataSize );
		clFree( "shutdownFunction", keysetInfoPtr->keyData );
		}

	return( status );
	}

/****************************************************************************
*																			*
*							Keyset Access Routines							*
*																			*
****************************************************************************/

CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
int setAccessMethodPKCS12( INOUT KEYSET_INFO *keysetInfoPtr )
	{
	assert( isWritePtr( keysetInfoPtr, sizeof( KEYSET_INFO ) ) );

	REQUIRES( keysetInfoPtr->type == KEYSET_FILE && \
			  keysetInfoPtr->subType == KEYSET_SUBTYPE_PKCS12 );

	/* Set the access method pointers */
	keysetInfoPtr->initFunction = initFunction;
	keysetInfoPtr->shutdownFunction = shutdownFunction;
	keysetInfoPtr->getItemFunction = getItemFunction;
	keysetInfoPtr->setItemFunction = setItemFunction;

	return( CRYPT_OK );
	}
#endif /* USE_PKCS12 */

⌨️ 快捷键说明

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