📄 pkcs12.c
字号:
( sizeofOID( oid ) + \
sizeofObject( sizeofObject( length ) ) + \
sizeofObject( attrDataLength ) ) );
writeOID( stream, oid );
writeConstructed( stream, ( int ) sizeofObject( length ), 0 );
writeSequence( stream, length );
}
/* Write a PKCS #12 item ("safeBag"). We can't write this directly to the
output stream but have to buffer it via an intermediate stream so we can
MAC it */
static void writeItem( STREAM *stream, const PKCS12_INFO *pkcs12info,
const BOOLEAN isPrivateKey, const BOOLEAN macData )
{
STREAM memStream;
BYTE buffer[ 256 ];
void *dataPtr;
const int idDataSize = ( int ) \
( sizeofOID( OID_PKCS9_LOCALKEYID ) + \
sizeofObject( \
sizeofObject( 1 ) ) );
const int labelDataSize = ( int ) \
( sizeofOID( OID_PKCS9_FRIENDLYNAME ) + \
sizeofObject( \
sizeofObject( pkcs12info->labelLength * 2 ) ) );
const int attrDataSize = ( int ) \
( sizeofObject( idDataSize ) + \
sizeofObject( labelDataSize ) );
int dataSize, i, j;
sMemOpen( &memStream, buffer, 256 );
/* Write the item wrapper and item data */
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 ) );
swrite( stream, dataPtr, dataSize );
/* Mac the payload data if necessary */
if( macData )
{
krnlSendMessage( pkcs12info->iMacContext, IMESSAGE_CTX_HASH,
buffer, stell( &memStream ) );
krnlSendMessage( pkcs12info->iMacContext, IMESSAGE_CTX_HASH,
dataPtr, dataSize );
}
/* 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 it's
a 32-bit int or a similar type of value */
sseek( &memStream, 0 );
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++ )
{
/* Convert the ASCII string to a BMP string */
sputc( &memStream, 0 );
sputc( &memStream, pkcs12info->label[ i ] );
}
assert( stell( &memStream ) < 256 );
swrite( stream, buffer, stell( &memStream ) );
/* Mac the attribute data if necessary */
if( macData )
krnlSendMessage( pkcs12info->iMacContext, IMESSAGE_CTX_HASH,
buffer, stell( &memStream ) );
sMemClose( &memStream );
}
/* Flush a PKCS #12 collection to a stream */
static int pkcs12Flush( STREAM *stream, const PKCS12_INFO *pkcs12info )
{
STREAM memStream;
RESOURCE_DATA msgData;
BYTE buffer[ 32 ];
BOOLEAN privateKeyPresent = FALSE;
int safeDataSize, authSafeDataSize, macDataSize, i, status;
/* Determine the overall size of the objects */
sMemOpen( &memStream, NULL, 0 );
for( i = 0; i < MAX_PKCS12_OBJECTS; i++ )
{
if( pkcs12info[ i ].privKeyDataSize )
{
privateKeyPresent = TRUE;
writeItem( &memStream, pkcs12info, TRUE, FALSE );
}
if( pkcs12info[ i ].certDataSize )
writeItem( &memStream, pkcs12info, FALSE, FALSE );
}
safeDataSize = stell( &memStream );
sMemClose( &memStream );
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 ) );
krnlSendMessage( pkcs12info->iMacContext, IMESSAGE_CTX_HASH,
buffer, stell( &memStream ) );
sMemClose( &memStream );
/* Write the individual objects */
for( i = 0; i < MAX_PKCS12_OBJECTS; i++ )
{
if( pkcs12info[ i ].privKeyDataSize )
writeItem( stream, pkcs12info, TRUE, TRUE );
if( pkcs12info[ i ].certDataSize )
writeItem( stream, pkcs12info, FALSE, TRUE );
}
/* 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 );
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 );
writeShortInteger( stream, pkcs12info->macIterations, DEFAULT_TAG );
return( sflush( stream ) );
}
/* Add an item to the PKCS #12 keyset */
static int setItemFunction( KEYSET_INFO *keysetInfo,
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 = keysetInfo->keyData;
STREAM stream;
BOOLEAN certPresent = FALSE, contextPresent;
BOOLEAN pkcs12keyPresent = pkcs12infoPtr->privKeyDataSize ? TRUE : FALSE;
int privKeyInfoSize, pbeInfoDataSize;
int value, status;
assert( itemType == KEYMGMT_ITEM_PUBLICKEY || \
itemType == KEYMGMT_ITEM_PRIVATEKEY );
/* If there's already a key and cert present, we can't add anything
else. This check also catches the (invalid) case of a cert being
present without a corresponding private key */
if( pkcs12infoPtr->certDataSize )
return( CRYPT_ERROR_INITED );
/* 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 )
/* PKCS #12 can only store RSA keys */
status = CRYPT_ARGERROR_NUM1;
}
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 cert 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
cert */
status = krnlSendMessage( cryptHandle, IMESSAGE_GETATTRIBUTE,
&value, CRYPT_CERTINFO_CERTTYPE );
if( cryptStatusOK( status ) && \
( value == CRYPT_CERTTYPE_CERTIFICATE || \
value == CRYPT_CERTTYPE_CERTCHAIN ) )
{
/* If the cert isn't signed, we can't store it in this state */
status = krnlSendMessage( cryptHandle, IMESSAGE_GETATTRIBUTE,
&value, CRYPT_CERTINFO_IMMUTABLE );
if( cryptStatusError( status ) || !value )
return( CRYPT_ERROR_NOTINITED );
certPresent = TRUE;
if( !pkcs12keyPresent )
/* We can't add a cert 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 */
return( CRYPT_ERROR_NOTINITED );
}
else
/* If we're trying to add a standalone key and there's already one
present, we can't add another one */
if( pkcs12keyPresent )
return( CRYPT_ERROR_INITED );
/* 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 cert, 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 )
{
RESOURCE_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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -