📄 pkcs15_rd.c
字号:
if( pkcs15infoPtr->certData != NULL )
{
/* There's a certificate present, import it and reconstruct the
public-key information from it if we're creating a partial PKC
context */
status = iCryptImportCertIndirect( &iCryptContext,
iCryptKeysetCallback, keyIDtype, keyID,
keyIDlength, publicComponentsOnly ? \
KEYMGMT_FLAG_NONE : \
KEYMGMT_FLAG_DATAONLY_CERT );
if( cryptStatusError( status ) )
{
retExt( status,
( status, errorInfo,
"Couldn't recreate certificate from stored "
"certificate data" ) );
}
if( !publicComponentsOnly )
{
DYNBUF pubKeyDB;
/* We got the certificate, now create the public part of the
context from the certificate's encoded public-key
components */
iDataCert = iCryptContext;
status = dynCreate( &pubKeyDB, iDataCert,
CRYPT_IATTRIBUTE_SPKI );
if( cryptStatusError( status ) )
return( status );
sMemConnect( &stream, dynData( pubKeyDB ),
dynLength( pubKeyDB ) );
status = iCryptReadSubjectPublicKey( &stream, &iCryptContext,
TRUE );
sMemDisconnect( &stream );
dynDestroy( &pubKeyDB );
if( cryptStatusError( status ) )
{
krnlSendNotifier( iDataCert, IMESSAGE_DECREFCOUNT );
retExt( status,
( status, errorInfo,
"Couldn't recreate public key from "
"certificate" ) );
}
}
}
else
{
const int pubKeyStartOffset = pkcs15infoPtr->pubKeyOffset;
const int pubKeyTotalSize = pkcs15infoPtr->pubKeyDataSize;
/* There's no certificate present, create the public-key context
directly */
REQUIRES( rangeCheck( pubKeyStartOffset,
pubKeyTotalSize - pubKeyStartOffset,
pubKeyTotalSize ) );
sMemConnect( &stream,
( BYTE * ) pkcs15infoPtr->pubKeyData + pubKeyStartOffset,
pubKeyTotalSize - pubKeyStartOffset );
status = iCryptReadSubjectPublicKey( &stream, &iCryptContext,
!publicComponentsOnly );
sMemDisconnect( &stream );
if( cryptStatusError( status ) )
{
retExt( status,
( status, errorInfo,
"Couldn't recreate public key from stored public key "
"data" ) );
}
}
/* Get the permitted usage flags for each object type that we'll be
instantiating. If there's a public key present we apply its usage
flags to whichever PKC context we create, even if it's done indirectly
via the certificate import. Since the private key can also perform
the actions of the public key we set its action flags to the union of
the two */
status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE,
&cryptAlgo, CRYPT_CTXINFO_ALGO );
if( cryptStatusOK( status ) && pkcs15infoPtr->pubKeyData != NULL )
{
status = getPermittedActions( pkcs15infoPtr->pubKeyUsage, cryptAlgo,
pubkeyActionFlags );
}
if( cryptStatusOK( status ) && !publicComponentsOnly )
{
status = getPermittedActions( pkcs15infoPtr->privKeyUsage, cryptAlgo,
privkeyActionFlags );
}
if( cryptStatusError( status ) )
{
krnlSendNotifier( iCryptContext, IMESSAGE_DECREFCOUNT );
if( iDataCert != CRYPT_ERROR )
krnlSendNotifier( iDataCert, IMESSAGE_DECREFCOUNT );
retExt( status,
( status, errorInfo,
"Public/private key usage flags don't allow any type of "
"key usage" ) );
}
/* Return the newly-created objects to the caller */
*iCryptContextPtr = iCryptContext;
*iDataCertPtr = iDataCert;
return( CRYPT_OK );
}
/****************************************************************************
* *
* Read Public/Private Key Components *
* *
****************************************************************************/
/* Read private-key components from a PKCS #15 object entry */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3, 5 ) ) \
int readPrivateKeyComponents( const PKCS15_INFO *pkcs15infoPtr,
IN_HANDLE const CRYPT_CONTEXT iCryptContext,
IN_BUFFER( passwordLength ) const void *password,
IN_LENGTH_NAME const int passwordLength,
INOUT ERROR_INFO *errorInfo )
{
CRYPT_CONTEXT iSessionKey;
MESSAGE_CREATEOBJECT_INFO createInfo;
MECHANISM_WRAP_INFO mechanismInfo;
MESSAGE_DATA msgData;
QUERY_INFO queryInfo, contentQueryInfo;
STREAM stream;
const int privKeyStartOffset = pkcs15infoPtr->privKeyOffset;
const int privKeyTotalSize = pkcs15infoPtr->privKeyDataSize;
void *encryptedKey, *encryptedContent = DUMMY_INIT_PTR;
int encryptedContentLength = DUMMY_INIT;
int tag, status;
assert( isReadPtr( pkcs15infoPtr, sizeof( PKCS15_INFO ) ) );
assert( isReadPtr( password, passwordLength ) );
REQUIRES( isHandleRangeValid( iCryptContext ) );
REQUIRES( passwordLength >= MIN_NAME_LENGTH && \
passwordLength < MAX_ATTRIBUTE_SIZE );
REQUIRES( errorInfo != NULL );
/* Skip the outer wrapper, version number, and header for the SET OF
EncryptionInfo, and query the exported key information to determine
the parameters required to reconstruct the decryption key */
REQUIRES( rangeCheck( privKeyStartOffset,
privKeyTotalSize - privKeyStartOffset,
privKeyTotalSize ) );
sMemConnect( &stream,
( BYTE * ) pkcs15infoPtr->privKeyData + privKeyStartOffset,
privKeyTotalSize - privKeyStartOffset );
tag = status = peekTag( &stream );
if( cryptStatusError( status ) )
return( status );
if( tag == CTAG_OV_FUTUREUSE )
{
/* Future versions of cryptlib will use AuthEnvelopedData to protect
keys which will presumably be identified with a new tag because
CTAG_OV_DIRECTPROTECTED implies EnvelopedData. For forwards-
compatibility we check for this tag and warn the user about it */
retExt( CRYPT_ERROR_NOTAVAIL,
( CRYPT_ERROR_NOTAVAIL, errorInfo,
"Key is protected using AuthEnvelopedData, this requires "
"a newer version of cryptlib to process" ) );
}
readConstructed( &stream, NULL, CTAG_OV_DIRECTPROTECTED );
readShortInteger( &stream, NULL );
readSet( &stream, NULL );
status = queryAsn1Object( &stream, &queryInfo );
if( cryptStatusOK( status ) && \
queryInfo.type != CRYPT_OBJECT_ENCRYPTED_KEY )
status = CRYPT_ERROR_BADDATA;
if( cryptStatusError( status ) )
{
sMemDisconnect( &stream );
zeroise( &queryInfo, sizeof( QUERY_INFO ) );
retExt( status,
( status, errorInfo,
"Invalid encrypted key data header" ) );
}
status = sMemGetDataBlock( &stream, &encryptedKey, queryInfo.size );
if( cryptStatusOK( status ) )
status = readUniversal( &stream ); /* Skip the exported key */
if( cryptStatusError( status ) )
{
sMemDisconnect( &stream );
zeroise( &queryInfo, sizeof( QUERY_INFO ) );
return( status );
}
/* Read the header for the encrypted key and make sure that all of the
data is present in the stream */
status = readCMSencrHeader( &stream, dataOIDinfo,
FAILSAFE_ARRAYSIZE( dataOIDinfo, OID_INFO ),
&iSessionKey, &contentQueryInfo );
if( cryptStatusOK( status ) )
{
encryptedContentLength = contentQueryInfo.size;
status = sMemGetDataBlock( &stream, &encryptedContent,
encryptedContentLength );
if( cryptStatusOK( status ) && \
( encryptedContentLength == CRYPT_UNUSED || \
encryptedContentLength < MIN_OBJECT_SIZE || \
encryptedContentLength > MAX_INTLENGTH_SHORT ) )
{
/* Indefinite length or too-small object */
status = CRYPT_ERROR_BADDATA;
}
}
zeroise( &contentQueryInfo, sizeof( QUERY_INFO ) );
sMemDisconnect( &stream );
if( cryptStatusError( status ) )
{
zeroise( &queryInfo, sizeof( QUERY_INFO ) );
retExt( status,
( status, errorInfo, "Invalid encrypted key data header" ) );
}
/* Create an encryption context, derive the user password into it using
the given parameters, and import the session key. If there's an
error in the parameters stored with the exported key we'll get an arg
or attribute error when we try to set the attribute so we translate
it into an error code which is appropriate for the situation */
setMessageCreateObjectInfo( &createInfo, queryInfo.cryptAlgo );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_DEV_CREATEOBJECT,
&createInfo, OBJECT_TYPE_CONTEXT );
if( cryptStatusError( status ) )
{
zeroise( &queryInfo, sizeof( QUERY_INFO ) );
return( status );
}
status = krnlSendMessage( createInfo.cryptHandle, IMESSAGE_SETATTRIBUTE,
&queryInfo.cryptMode, CRYPT_CTXINFO_MODE );
if( cryptStatusOK( status ) )
status = krnlSendMessage( createInfo.cryptHandle, IMESSAGE_SETATTRIBUTE,
&queryInfo.keySetupAlgo,
CRYPT_CTXINFO_KEYING_ALGO );
if( cryptStatusOK( status ) )
status = krnlSendMessage( createInfo.cryptHandle, IMESSAGE_SETATTRIBUTE,
&queryInfo.keySetupIterations,
CRYPT_CTXINFO_KEYING_ITERATIONS );
if( cryptStatusOK( status ) )
{
setMessageData( &msgData, queryInfo.salt, queryInfo.saltLength );
status = krnlSendMessage( createInfo.cryptHandle, IMESSAGE_SETATTRIBUTE_S,
&msgData, CRYPT_CTXINFO_KEYING_SALT );
}
if( cryptStatusOK( status ) )
{
setMessageData( &msgData, ( void * ) password, passwordLength );
status = krnlSendMessage( createInfo.cryptHandle, IMESSAGE_SETATTRIBUTE_S,
&msgData, CRYPT_CTXINFO_KEYING_VALUE );
}
if( cryptStatusOK( status ) )
{
status = iCryptImportKey( encryptedKey, queryInfo.size,
CRYPT_FORMAT_CRYPTLIB,
createInfo.cryptHandle, iSessionKey, NULL );
}
krnlSendNotifier( createInfo.cryptHandle, IMESSAGE_DECREFCOUNT );
zeroise( &queryInfo, sizeof( QUERY_INFO ) );
if( cryptStatusError( status ) )
{
krnlSendNotifier( iSessionKey, IMESSAGE_DECREFCOUNT );
if( cryptArgError( status ) )
status = CRYPT_ERROR_BADDATA;
retExt( status,
( status, errorInfo,
"Couldn't create decryption context for private key from "
"user password" ) );
}
/* Import the encrypted key into the PKC context */
setMechanismWrapInfo( &mechanismInfo, ( void * ) encryptedContent,
encryptedContentLength, NULL, 0, iCryptContext,
iSessionKey );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_DEV_IMPORT,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -