📄 pkcs12.c
字号:
/* 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 + -