📄 pnppki.c
字号:
/* Clear return value */
*iCertReq = CRYPT_ERROR;
/* Create the signing key cert request */
setMessageCreateObjectInfo( &createInfo, isPKCS10 ? \
CRYPT_CERTTYPE_CERTREQUEST : \
CRYPT_CERTTYPE_REQUEST_CERT );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
IMESSAGE_DEV_CREATEOBJECT, &createInfo,
OBJECT_TYPE_CERTIFICATE );
if( cryptStatusError( status ) )
return( status );
/* Add the key information to the request and sign it if it's a CMP
request. We can't sign PKCS #10 requests (for SCEP) because the
client session has to add further information which is required by
the server to the request before it submits it */
status = krnlSendMessage( createInfo.cryptHandle, IMESSAGE_SETATTRIBUTE,
( int * ) &iPrivateKey,
CRYPT_CERTINFO_SUBJECTPUBLICKEYINFO );
if( cryptStatusOK( status ) )
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 ) );
}
/****************************************************************************
* *
* 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 KEY_TYPE keyType = ( sessionInfoPtr->type == CRYPT_SESSION_CMP ) ? \
KEYTYPE_SIGNATURE : KEYTYPE_BOTH;
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->cmpRequestType = 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 it simplifies the
implementation by requiring it to remain open */
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 */
status = getCACert( &iCACert, sessionInfoPtr->iCertResponse,
sessionInfoPtr->keyFingerprint,
sessionInfoPtr->keyFingerprintSize );
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->cmpRequestType = 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 );
}
if( sessionInfoPtr->type == CRYPT_SESSION_CMP && \
!isConnectionOpen( sessionInfoPtr ) )
{
/* 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 it
simplifies the implementation by requiring it to remain open */
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,
sessionInfoPtr->password,
sessionInfoPtr->passwordLength );
if( cryptStatusOK( status ) && keyType != KEYTYPE_BOTH )
{
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 */
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,
"Couldn't update keyset/device with %skey/certificate",
( keyType == KEYTYPE_SIGNATURE ) ? "signature " : "" );
}
/* If it's a combined encryption/signature key, we're done */
if( keyType == KEYTYPE_BOTH )
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( 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->cmpRequestType = 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,
sessionInfoPtr->password,
sessionInfoPtr->passwordLength );
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" );
}
/* 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 + -