📄 pkcs12.c
字号:
}
/* We're ready to go, lock the object for our exclusive use */
status = krnlSendNotifier( cryptHandle, IMESSAGE_LOCK );
if( cryptStatusError( status ) )
return( status );
/* Write the cert if necessary. We do this one first because it's the
easiest to back out of */
if( certPresent )
{
RESOURCE_DATA msgData;
/* Select the leaf cert in case it's a cert chain */
krnlSendMessage( cryptHandle, IMESSAGE_SETATTRIBUTE,
MESSAGE_VALUE_CURSORFIRST,
CRYPT_CERTINFO_CURRENT_CERTIFICATE );
/* Get the encoded cert */
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 );
return( status );
}
}
/* 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, keysetInfo->ownerHandle,
password, passwordLength, pkcs12infoPtr );
if( cryptStatusOK( status ) && pkcs12infoPtr->iMacContext == CRYPT_ERROR )
status = createMacContext( pkcs12infoPtr, keysetInfo->ownerHandle,
password, passwordLength );
if( cryptStatusError( status ) )
{
pkcs12freeEntry( pkcs12infoPtr );
krnlSendNotifier( cryptHandle, IMESSAGE_UNLOCK );
return( status );
}
/* 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 );
writeOctetStringHole( &stream, privKeyInfoSize, DEFAULT_TAG );
assert( stell( &stream ) < 64 );
assert( sStatusOK( &stream ) );
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 );
return( status );
}
/****************************************************************************
* *
* 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, status;
while( checkEOC( stream ) != TRUE )
{
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;
}
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 */
static int initFunction( KEYSET_INFO *keysetInfo, const char *name,
const CRYPT_KEYOPT_TYPE options )
{
PKCS12_INFO *pkcs12info;
STREAM *stream = &keysetInfo->keysetFile->stream, memStream;
BYTE *buffer;
BOOLEAN isIndefinite = FALSE;
long length;
int totalLength, status;
assert( name == NULL );
/* 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 ) )
return( status );
if( version != 3 )
return( CRYPT_ERROR_BADDATA );
}
/* Allocate the PKCS #12 object info */
if( ( pkcs12info = clAlloc( "initFunction", \
sizeof( PKCS12_INFO ) * \
MAX_PKCS12_OBJECTS ) ) == NULL )
return( CRYPT_ERROR_MEMORY );
memset( pkcs12info, 0, sizeof( PKCS12_INFO ) * MAX_PKCS12_OBJECTS );
keysetInfo->keyData = pkcs12info;
keysetInfo->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 );
return( status );
}
/* 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 );
}
}
sMemDisconnect( &memStream );
clFree( "initFunction", buffer );
return( CRYPT_OK );
}
/* Shut down the PKCS #12 state, flushing information to disk if necessary */
static void shutdownFunction( KEYSET_INFO *keysetInfo )
{
/* If the contents have been changed, commit the changes to disk */
if( keysetInfo->flags & KEYSET_DIRTY )
{
int status;
sseek( &keysetInfo->keysetFile->stream, 0 );
status = pkcs12Flush( &keysetInfo->keysetFile->stream,
keysetInfo->keyData );
if( status == OK_SPECIAL )
keysetInfo->flags |= KEYSET_EMPTY;
}
/* Free the PKCS #12 object info */
if( keysetInfo->keyData != NULL )
{
pkcs12Free( keysetInfo->keyData );
zeroise( keysetInfo->keyData, keysetInfo->keyDataSize );
clFree( "shutdownFunction", keysetInfo->keyData );
}
}
/****************************************************************************
* *
* Keyset Access Routines *
* *
****************************************************************************/
int setAccessMethodPKCS12( KEYSET_INFO *keysetInfo )
{
/* Set the access method pointers */
keysetInfo->initFunction = initFunction;
keysetInfo->shutdownFunction = shutdownFunction;
keysetInfo->getItemFunction = getItemFunction;
keysetInfo->setItemFunction = setItemFunction;
return( CRYPT_OK );
}
#endif /* USE_PKCS12 */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -