📄 pnppki.c
字号:
status = krnlSendMessage( createInfo.cryptHandle, IMESSAGE_SETATTRIBUTE,
( int * ) &keyInfo[ keyType ].keyUsage,
CRYPT_CERTINFO_KEYUSAGE );
if( cryptStatusOK( status ) && iSubjDNCert != CRYPT_UNUSED )
status = krnlSendMessage( createInfo.cryptHandle, IMESSAGE_SETATTRIBUTE,
( int * ) &iSubjDNCert,
CRYPT_CERTINFO_CERTIFICATE );
if( cryptStatusOK( status ) && !isPKCS10 )
status = krnlSendMessage( createInfo.cryptHandle, IMESSAGE_CRT_SIGN,
NULL, iPrivateKey );
if( cryptStatusError( status ) )
{
krnlSendNotifier( createInfo.cryptHandle, IMESSAGE_DECREFCOUNT );
return( status );
}
*iCertReq = createInfo.cryptHandle;
return( CRYPT_OK );
}
/* Update a keyset/device with a newly-created key and cert */
static int updateKeys( const CRYPT_HANDLE iCryptHandle,
const CRYPT_CONTEXT iPrivateKey,
const CRYPT_CERTIFICATE iCryptCert,
const char *password, const int passwordLength )
{
MESSAGE_KEYMGMT_INFO setkeyInfo;
int value, status;
/* Find out whether the storage object is a keyset or a device. If it's
a device there's no need to add the private key since it'll have been
created inside the device */
status = krnlSendMessage( iCryptHandle, IMESSAGE_GETATTRIBUTE, &value,
CRYPT_IATTRIBUTE_TYPE );
if( cryptStatusError( status ) )
return( status );
/* Add the private key and certificate to the keyset/device */
if( value == OBJECT_TYPE_KEYSET )
{
setMessageKeymgmtInfo( &setkeyInfo, CRYPT_KEYID_NONE, NULL, 0,
( void * ) password, passwordLength,
KEYMGMT_FLAG_NONE );
setkeyInfo.cryptHandle = iPrivateKey;
status = krnlSendMessage( iCryptHandle, IMESSAGE_KEY_SETKEY,
&setkeyInfo, KEYMGMT_ITEM_PRIVATEKEY );
if( cryptStatusError( status ) )
return( status );
}
setMessageKeymgmtInfo( &setkeyInfo, CRYPT_KEYID_NONE, NULL, 0,
NULL, 0, KEYMGMT_FLAG_NONE );
setkeyInfo.cryptHandle = iCryptCert;
return( krnlSendMessage( iCryptHandle, IMESSAGE_KEY_SETKEY,
&setkeyInfo, KEYMGMT_ITEM_PUBLICKEY ) );
}
/* Update the keyset/device with any required trusted certs up to the root.
This ensures that we can still build a full cert chain even if the
PKIBoot trusted certs aren't preserved */
static int updateTrustedCerts( const CRYPT_HANDLE iCryptHandle,
const CRYPT_HANDLE iLeafCert )
{
CRYPT_CERTIFICATE iCertCursor = iLeafCert;
int status;
do
{
/* Get the trusted issuer cert for the current cert and send it to
the keyset/device */
status = krnlSendMessage( iCertCursor,
IMESSAGE_SETATTRIBUTE, &iCertCursor,
CRYPT_IATTRIBUTE_CERT_TRUSTEDISSUER );
if( cryptStatusOK( status ) )
{
MESSAGE_KEYMGMT_INFO setkeyInfo;
setMessageKeymgmtInfo( &setkeyInfo, CRYPT_KEYID_NONE, NULL, 0,
NULL, 0, KEYMGMT_FLAG_NONE );
setkeyInfo.cryptHandle = iCertCursor;
status = krnlSendMessage( iCryptHandle, IMESSAGE_KEY_SETKEY,
&setkeyInfo, KEYMGMT_ITEM_PUBLICKEY );
}
}
while( cryptStatusOK( status ) );
return( CRYPT_OK );
}
/****************************************************************************
* *
* PnP PKI Session Management *
* *
****************************************************************************/
/* Run a plug-and-play PKI session */
int pnpPkiSession( SESSION_INFO *sessionInfoPtr )
{
CRYPT_DEVICE iCryptDevice = SYSTEM_OBJECT_HANDLE;
CRYPT_CONTEXT iPrivateKey1, iPrivateKey2 ;
CRYPT_CERTIFICATE iCertReq, iCACert;
const ATTRIBUTE_LIST *attributeListPtr;
const ATTRIBUTE_LIST *passwordPtr = \
findSessionAttribute( sessionInfoPtr->attributeList,
CRYPT_SESSINFO_PASSWORD );
const KEY_TYPE keyType = ( sessionInfoPtr->type == CRYPT_SESSION_CMP ) ? \
KEYTYPE_SIGNATURE : KEYTYPE_BOTH;
BOOLEAN isCAcert;
int value, status;
/* If we've been passed a device as the private-key storage location,
create the key in the device instead of as a local object */
status = krnlSendMessage( sessionInfoPtr->privKeyset,
IMESSAGE_GETATTRIBUTE, &value,
CRYPT_IATTRIBUTE_TYPE );
if( cryptStatusError( status ) )
return( status );
if( value == OBJECT_TYPE_DEVICE )
iCryptDevice = sessionInfoPtr->privKeyset;
/* Make sure that the named objects that are about to be created aren't
already present in the keyset/device */
if( isNamedObjectPresent( sessionInfoPtr->privKeyset, keyType ) )
retExt( sessionInfoPtr, CRYPT_ERROR_DUPLICATE,
"%s is already present in keyset/device",
( keyType == KEYTYPE_SIGNATURE ) ? "Signature key" : "Key" );
if( sessionInfoPtr->type == CRYPT_SESSION_CMP )
{
if( isNamedObjectPresent( sessionInfoPtr->privKeyset,
KEYTYPE_ENCRYPTION ) )
retExt( sessionInfoPtr, CRYPT_ERROR_DUPLICATE,
"Encryption key is already present in keyset/device" );
}
/* Perform the PKIBoot exchange to get the initial trusted cert set. We
also set the retain-connection flag since we're going to follow this
with another transaction */
if( sessionInfoPtr->type == CRYPT_SESSION_CMP )
sessionInfoPtr->sessionCMP->requestType = CRYPT_REQUESTTYPE_PKIBOOT;
sessionInfoPtr->protocolFlags |= CMP_PFLAG_RETAINCONNECTION;
status = sessionInfoPtr->transactFunction( sessionInfoPtr );
if( cryptStatusError( status ) )
return( status );
if( !isConnectionOpen( sessionInfoPtr ) )
{
/* If the connection was shut down by the other side, signal an
error. This is possibly a bit excessive since we could always
try reactivating the session, but there's no good reason for the
other side to simply close the connection and requiring it to
remain open simplifies the implementation */
krnlSendNotifier( sessionInfoPtr->iCertResponse,
IMESSAGE_DECREFCOUNT );
retExt( sessionInfoPtr, CRYPT_ERROR_READ,
"Server closed connection after PKIBoot phase before any "
"certificates could be issued" );
}
/* Get the CA/RA cert from the returned CTL and set it as the cert to
use for authenticating server responses */
attributeListPtr = \
findSessionAttribute( sessionInfoPtr->attributeList,
CRYPT_SESSINFO_SERVER_FINGERPRINT );
if( attributeListPtr == NULL )
status = CRYPT_ERROR_NOTFOUND;
else
status = getCACert( &iCACert, sessionInfoPtr->iCertResponse,
attributeListPtr->value,
attributeListPtr->valueLength );
krnlSendNotifier( sessionInfoPtr->iCertResponse, IMESSAGE_DECREFCOUNT );
sessionInfoPtr->iCertResponse = CRYPT_ERROR;
if( cryptStatusError( status ) )
retExt( sessionInfoPtr, status,
"Couldn't read CA/RA certificate from returned certificate "
"trust list" );
sessionInfoPtr->iAuthInContext = iCACert;
/* Create a private key and a cert request for it */
status = generateKey( &iPrivateKey1, sessionInfoPtr->ownerHandle,
iCryptDevice, keyType );
if( cryptStatusError( status ) )
retExt( sessionInfoPtr, status, "Couldn't create %s key",
( keyType == KEYTYPE_SIGNATURE ) ? "signature" : "private" );
status = createCertRequest( &iCertReq, iPrivateKey1, CRYPT_UNUSED,
keyType );
if( cryptStatusError( status ) )
{
cleanupObject( iPrivateKey1, keyType );
retExt( sessionInfoPtr, status,
"Couldn't create %skey cert request",
( keyType == KEYTYPE_SIGNATURE ) ? "signature " : "" );
}
/* Set up the request info and activate the session */
if( sessionInfoPtr->type == CRYPT_SESSION_CMP )
/* If it's CMP, start with an ir. The second cert will be fetched
with a cr */
sessionInfoPtr->sessionCMP->requestType = CRYPT_REQUESTTYPE_INITIALISATION;
sessionInfoPtr->iCertRequest = iCertReq;
status = sessionInfoPtr->transactFunction( sessionInfoPtr );
krnlSendNotifier( sessionInfoPtr->iCertRequest, IMESSAGE_DECREFCOUNT );
sessionInfoPtr->iCertRequest = CRYPT_ERROR;
if( cryptStatusError( status ) )
{
cleanupObject( iPrivateKey1, keyType );
return( status );
}
/* Check whether we've been issued a standalone CA cert rather than a
standard signature cert to be followed by an encryption cert */
status = krnlSendMessage( sessionInfoPtr->iCertResponse,
IMESSAGE_GETATTRIBUTE, &isCAcert,
CRYPT_CERTINFO_CA );
if( cryptStatusError( status ) )
isCAcert = FALSE;
/* If the connection was shut down by the other side and we're
performing a multi-part operation that requires it to remain open,
signal an error. This is possibly a bit excessive since we could
always try reactivating the session, but there's no good reason for
the other side to simply close the connection and requiring it to
remain open simplifies the implementation */
if( sessionInfoPtr->type == CRYPT_SESSION_CMP && \
!isConnectionOpen( sessionInfoPtr ) && !isCAcert )
{
cleanupObject( iPrivateKey1, keyType );
krnlSendNotifier( sessionInfoPtr->iCertResponse,
IMESSAGE_DECREFCOUNT );
sessionInfoPtr->iCertResponse = CRYPT_ERROR;
retExt( sessionInfoPtr, CRYPT_ERROR_READ,
"Server closed connection before second (encryption) "
"certificate could be issued" );
}
/* We've got the first cert, update the keyset/device */
status = updateKeys( sessionInfoPtr->privKeyset, iPrivateKey1,
sessionInfoPtr->iCertResponse,
passwordPtr->value, passwordPtr->valueLength );
if( cryptStatusOK( status ) )
{
CRYPT_CERTIFICATE iNewCert;
/* Recreate the cert as a data-only cert and attach it to the
signing key so that we can use it to authenticate a request for
an encryption key. We need to recreate the cert because we're
about to attach it to the private-key context for further
operations, and attaching a cert with a public-key context
already attached isn't possible. Even if we're not getting a
second cert, we still need the current cert attached so that we
can use it as the base cert for the trusted cert update that
we perform before we exit */
status = recreateCert( &iNewCert, sessionInfoPtr->iCertResponse,
TRUE );
if( cryptStatusOK( status ) )
krnlSendMessage( iPrivateKey1, IMESSAGE_SETDEPENDENT, &iNewCert,
SETDEP_OPTION_NOINCREF );
}
krnlSendNotifier( sessionInfoPtr->iCertResponse, IMESSAGE_DECREFCOUNT );
sessionInfoPtr->iCertResponse = CRYPT_ERROR;
if( cryptStatusError( status ) )
{
cleanupObject( iPrivateKey1, keyType );
retExt( sessionInfoPtr, ( status == CRYPT_ARGERROR_NUM1 ) ? \
CRYPT_ERROR_INVALID : status,
"Couldn't update keyset/device with %skey/certificate",
isCAcert ? "CA " : \
( keyType == KEYTYPE_SIGNATURE ) ? "signature " : "" );
}
/* If it's a combined encryption/signature key or a standalone CA key,
we're done. See the comment at the end for the trusted-certs update
process */
if( keyType == KEYTYPE_BOTH || isCAcert )
{
updateTrustedCerts( sessionInfoPtr->privKeyset, iPrivateKey1 );
krnlSendNotifier( iPrivateKey1, IMESSAGE_DECREFCOUNT );
return( CRYPT_OK );
}
/* We're running a CMP session from this point on. Create the second,
encryption private key and a cert request for it */
status = generateKey( &iPrivateKey2, sessionInfoPtr->ownerHandle,
iCryptDevice, KEYTYPE_ENCRYPTION );
if( status == OK_SPECIAL )
{
/* Encryption isn't available via this device, exit without going
through the second phase of the exchange, leaving only the
signature key and certs set up */
updateTrustedCerts( sessionInfoPtr->privKeyset, iPrivateKey1 );
krnlSendNotifier( iPrivateKey1, IMESSAGE_DECREFCOUNT );
return( CRYPT_OK );
}
if( cryptStatusError( status ) )
{
cleanupObject( iPrivateKey1, KEYTYPE_SIGNATURE );
retExt( sessionInfoPtr, status, "Couldn't create encryption key" );
}
status = createCertRequest( &iCertReq, iPrivateKey2, iPrivateKey1,
KEYTYPE_ENCRYPTION );
if( cryptStatusError( status ) )
{
cleanupObject( iPrivateKey1, KEYTYPE_SIGNATURE );
cleanupObject( iPrivateKey2, KEYTYPE_ENCRYPTION );
retExt( sessionInfoPtr, status,
"Couldn't create encryption key cert request" );
}
/* Set up the request info and activate the session. This request is
slightly different to the previous one since we now have a signature
cert that we can use to authenticate the request (in fact we have to
use this since we can't authenticate the message with an encryption-
only key). In addition since this is the last transaction we turn
off the retain-connection flag */
sessionInfoPtr->protocolFlags &= ~CMP_PFLAG_RETAINCONNECTION;
sessionInfoPtr->sessionCMP->requestType = CRYPT_REQUESTTYPE_CERTIFICATE;
sessionInfoPtr->iCertRequest = iCertReq;
sessionInfoPtr->privateKey = iPrivateKey2;
sessionInfoPtr->iAuthOutContext = iPrivateKey1;
status = sessionInfoPtr->transactFunction( sessionInfoPtr );
sessionInfoPtr->privateKey = CRYPT_ERROR;
sessionInfoPtr->iAuthOutContext = CRYPT_ERROR;
krnlSendNotifier( sessionInfoPtr->iCertRequest, IMESSAGE_DECREFCOUNT );
sessionInfoPtr->iCertRequest = CRYPT_ERROR;
if( cryptStatusError( status ) )
{
cleanupObject( iPrivateKey1, KEYTYPE_SIGNATURE );
cleanupObject( iPrivateKey2, KEYTYPE_ENCRYPTION );
return( status );
}
/* We've got the second cert, update the keyset/device */
status = updateKeys( sessionInfoPtr->privKeyset, iPrivateKey2,
sessionInfoPtr->iCertResponse,
passwordPtr->value, passwordPtr->valueLength );
krnlSendNotifier( sessionInfoPtr->iCertResponse, IMESSAGE_DECREFCOUNT );
sessionInfoPtr->iCertResponse = CRYPT_ERROR;
if( cryptStatusError( status ) )
{
cleanupObject( iPrivateKey1, KEYTYPE_SIGNATURE );
cleanupObject( iPrivateKey2, KEYTYPE_ENCRYPTION );
retExt( sessionInfoPtr, status,
"Couldn't update keyset/device with encryption "
"key/certificate" );
}
/* Finally, update the keyset/device with any required trusted certs up
to the root. This ensures that we can still build a full cert chain
even if the PKIBoot trusted certs aren't preserved. We don't check
for errors from this function since it's not worth aborting the
process for some minor CA cert update problem, the user keys and certs
will still function without them */
updateTrustedCerts( sessionInfoPtr->privKeyset, iPrivateKey1 );
/* Both keys were certified and the keys and certs sent to the keyset/
device, we're done */
krnlSendNotifier( iPrivateKey1, IMESSAGE_DECREFCOUNT );
krnlSendNotifier( iPrivateKey2, IMESSAGE_DECREFCOUNT );
return( CRYPT_OK );
}
#endif /* USE_CMP */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -