📄 scep.c
字号:
/* For some bizarre reason integer status values are encoded as strings,
so we have to convert them to numeric values before we can do anything
with them */
int getScepStatusValue( const CRYPT_CERTIFICATE iCmsAttributes,
const CRYPT_ATTRIBUTE_TYPE attributeType,
int *value )
{
MESSAGE_DATA msgData;
BYTE buffer[ 128 + 8 ];
int numericValue, status;
assert( isHandleRangeValid( iCmsAttributes ) );
assert( attributeType == CRYPT_CERTINFO_SCEP_MESSAGETYPE || \
attributeType == CRYPT_CERTINFO_SCEP_PKISTATUS || \
attributeType == CRYPT_CERTINFO_SCEP_FAILINFO );
assert( isWritePtr( value, sizeof( int ) ) );
*value = CRYPT_ERROR;
setMessageData( &msgData, buffer, 128 );
status = krnlSendMessage( iCmsAttributes, IMESSAGE_GETATTRIBUTE_S,
&msgData, attributeType );
if( cryptStatusError( status ) )
return( status );
status = strGetNumeric( buffer, msgData.length, &numericValue, 0, 20 );
if( cryptStatusError( status ) )
return( CRYPT_ERROR_BADDATA );
*value = numericValue;
return( CRYPT_OK );
}
/****************************************************************************
* *
* Request Management Functions *
* *
****************************************************************************/
/* Create a self-signed certificate for signing the request and decrypting
the response */
static int createScepCert( SESSION_INFO *sessionInfoPtr,
SCEP_PROTOCOL_INFO *protocolInfo )
{
CRYPT_CERTIFICATE iNewCert;
MESSAGE_CREATEOBJECT_INFO createInfo;
MESSAGE_DATA msgData;
int status;
assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
assert( isWritePtr( protocolInfo, sizeof( SCEP_PROTOCOL_INFO ) ) );
/* Create a certificate, add the cert request and other information
required by SCEP to it, and sign it. SCEP requires that the
certificate serial number match the user name/transaction ID, the
spec actually says that the transaction ID should be a hash of the
public key, but since it never specifies exactly what is hashed
("MD5 hash on [sic] public key") this can probably be anything. We
use the user name, which is required to identify the pkiUser entry
in the CA cert store */
setMessageCreateObjectInfo( &createInfo, CRYPT_CERTTYPE_CERTIFICATE );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_DEV_CREATEOBJECT,
&createInfo, OBJECT_TYPE_CERTIFICATE );
if( cryptStatusError( status ) )
return( status );
status = krnlSendMessage( createInfo.cryptHandle, IMESSAGE_SETATTRIBUTE,
&sessionInfoPtr->iCertRequest,
CRYPT_CERTINFO_CERTREQUEST );
if( cryptStatusOK( status ) )
{
const ATTRIBUTE_LIST *userNamePtr = \
findSessionInfo( sessionInfoPtr->attributeList,
CRYPT_SESSINFO_USERNAME );
/* Set the serial number to the user name/transaction ID,
required by SCEP. This is the only time that we can write a
serial number to a certificate, normally it's set automagically
by the cert-management code */
setMessageData( &msgData, userNamePtr->value,
userNamePtr->valueLength );
status = krnlSendMessage( createInfo.cryptHandle,
IMESSAGE_SETATTRIBUTE_S, &msgData,
CRYPT_CERTINFO_SERIALNUMBER );
}
if( cryptStatusOK( status ) )
{
static const int keyUsage = CRYPT_KEYUSAGE_DIGITALSIGNATURE | \
CRYPT_KEYUSAGE_KEYENCIPHERMENT;
/* Set the cert usage to signing (to sign the request) and
encryption (to decrypt the response). We've already checked that
these capabilities are available when the key was added to the
session.
We delete the attribute before we try and set it in case there
was already one present in the request */
krnlSendMessage( createInfo.cryptHandle, IMESSAGE_DELETEATTRIBUTE,
NULL, CRYPT_CERTINFO_KEYUSAGE );
status = krnlSendMessage( createInfo.cryptHandle,
IMESSAGE_SETATTRIBUTE, ( void * ) &keyUsage,
CRYPT_CERTINFO_KEYUSAGE );
}
if( cryptStatusOK( status ) )
status = krnlSendMessage( createInfo.cryptHandle,
IMESSAGE_SETATTRIBUTE, MESSAGE_VALUE_TRUE,
CRYPT_CERTINFO_SELFSIGNED );
if( cryptStatusOK( status ) )
status = krnlSendMessage( createInfo.cryptHandle,
IMESSAGE_CRT_SIGN, NULL,
sessionInfoPtr->privateKey );
if( cryptStatusError( status ) )
{
krnlSendNotifier( createInfo.cryptHandle, IMESSAGE_DECREFCOUNT );
retExt( status,
( status, SESSION_ERRINFO,
"Couldn't create ephemeral self-signed SCEP "
"certificate" ) );
}
/* Now that we have a cert, attach it to the private key. This is
somewhat ugly since it alters the private key by attaching a cert
that (as far as the user is concerned) shouldn't really exist, but
we need to do this to allow signing and decryption. A side-effect
is that it constrains the private-key actions to make them internal-
only since it now has a cert attached, hopefully the user won't
notice this since the key will have a proper CA-issued cert attached
to it shortly.
To further complicate things, we can't directly attach the newly-
created cert because it already has a public-key context attached to
it, which would result in two keys being associated with the single
cert. To resolve this, we create a second copy of the cert as a
data-only cert and attach that to the private key */
status = krnlSendMessage( createInfo.cryptHandle, IMESSAGE_GETATTRIBUTE,
&iNewCert, CRYPT_IATTRIBUTE_CERTCOPY_DATAONLY );
if( cryptStatusOK( status ) )
krnlSendMessage( sessionInfoPtr->privateKey, IMESSAGE_SETDEPENDENT,
&iNewCert, SETDEP_OPTION_NOINCREF );
protocolInfo->iScepCert = createInfo.cryptHandle;
return( CRYPT_OK );
}
/* Complete the user-supplied PKCS #10 request by adding SCEP-internal
attributes and information */
static int createScepCertRequest( SESSION_INFO *sessionInfoPtr )
{
const ATTRIBUTE_LIST *attributeListPtr = \
findSessionInfo( sessionInfoPtr->attributeList,
CRYPT_SESSINFO_PASSWORD );
MESSAGE_DATA msgData;
int status = CRYPT_ERROR_NOTINITED;
assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
/* Add the password to the PKCS #10 request as a ChallengePassword
attribute and sign the request. We always send this in its
ASCII string form even if it's an encoded value because the
ChallengePassword attribute has to be a text string */
if( attributeListPtr != NULL )
{
setMessageData( &msgData, attributeListPtr->value,
attributeListPtr->valueLength );
status = krnlSendMessage( sessionInfoPtr->iCertRequest,
IMESSAGE_SETATTRIBUTE_S, &msgData,
CRYPT_CERTINFO_CHALLENGEPASSWORD );
}
if( cryptStatusOK( status ) )
{
status = krnlSendMessage( sessionInfoPtr->iCertRequest,
IMESSAGE_CRT_SIGN, NULL,
sessionInfoPtr->privateKey );
}
if( cryptStatusError( status ) )
{
retExt( status,
( status, SESSION_ERRINFO,
"Couldn't finalise PKCS #10 cert request" ) );
}
return( CRYPT_OK );
}
/* Create SCEP signing attributes */
int createScepAttributes( SESSION_INFO *sessionInfoPtr,
SCEP_PROTOCOL_INFO *protocolInfo,
CRYPT_CERTIFICATE *iScepAttributes,
const BOOLEAN isInitiator, const int scepStatus )
{
const ATTRIBUTE_LIST *userNamePtr = \
findSessionInfo( sessionInfoPtr->attributeList,
CRYPT_SESSINFO_USERNAME );
CRYPT_CERTIFICATE iCmsAttributes;
MESSAGE_CREATEOBJECT_INFO createInfo;
MESSAGE_DATA msgData;
int status;
assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
assert( isWritePtr( protocolInfo, sizeof( SCEP_PROTOCOL_INFO ) ) );
assert( isWritePtr( iScepAttributes, sizeof( CRYPT_CERTIFICATE ) ) );
/* Clear return value */
*iScepAttributes = CRYPT_ERROR;
/* Create the signing attributes needed by SCEP and add the user name/
transaction ID and message type */
setMessageCreateObjectInfo( &createInfo, CRYPT_CERTTYPE_CMS_ATTRIBUTES );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
IMESSAGE_DEV_CREATEOBJECT, &createInfo,
OBJECT_TYPE_CERTIFICATE );
if( cryptStatusError( status ) )
return( status );
iCmsAttributes = createInfo.cryptHandle;
setMessageData( &msgData, userNamePtr->value, userNamePtr->valueLength );
status = krnlSendMessage( iCmsAttributes, IMESSAGE_SETATTRIBUTE_S,
&msgData, CRYPT_CERTINFO_SCEP_TRANSACTIONID );
if( cryptStatusOK( status ) )
{
const char *messageType = isInitiator ? MESSAGETYPE_PKCSREQ : \
MESSAGETYPE_CERTREP;
setMessageData( &msgData, ( void * ) messageType,
strlen( messageType ) );
status = krnlSendMessage( iCmsAttributes, IMESSAGE_SETATTRIBUTE_S,
&msgData, CRYPT_CERTINFO_SCEP_MESSAGETYPE );
}
if( cryptStatusError( status ) )
{
krnlSendNotifier( iCmsAttributes, IMESSAGE_DECREFCOUNT );
return( status );
}
/* Add the message status */
if( !isInitiator && cryptStatusError( scepStatus ) )
{
const char *failInfo = ( scepStatus == CRYPT_ERROR_SIGNATURE ) ? \
MESSAGEFAILINFO_BADMESSAGECHECK : MESSAGEFAILINFO_BADREQUEST;
/* SCEP provides an extremely limited set of error codes so there's
not much that we can return in the way of additional failure
info */
setMessageData( &msgData, ( void * ) failInfo, strlen( failInfo ) );
krnlSendMessage( iCmsAttributes, IMESSAGE_SETATTRIBUTE_S,
&msgData, CRYPT_CERTINFO_SCEP_FAILINFO );
setMessageData( &msgData, MESSAGESTATUS_FAILURE,
strlen( MESSAGESTATUS_FAILURE ) );
}
else
setMessageData( &msgData, MESSAGESTATUS_SUCCESS,
strlen( MESSAGESTATUS_SUCCESS ) );
status = krnlSendMessage( iCmsAttributes, IMESSAGE_SETATTRIBUTE_S,
&msgData, CRYPT_CERTINFO_SCEP_PKISTATUS );
if( cryptStatusError( status ) )
{
krnlSendNotifier( iCmsAttributes, IMESSAGE_DECREFCOUNT );
return( status );
}
/* Add the nonce, identified as a sender nonce if we're the initiator and
a recipient nonce if we're the responder */
if( isInitiator )
{
/* If we're the initiator, generate a new nonce */
setMessageData( &msgData, protocolInfo->nonce, SCEP_NONCE_SIZE );
krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_IATTRIBUTE_RANDOM_NONCE );
protocolInfo->nonceSize = SCEP_NONCE_SIZE;
}
else
{
/* We're the responder, use the initiator's nonce */
setMessageData( &msgData, protocolInfo->nonce,
protocolInfo->nonceSize );
}
status = krnlSendMessage( iCmsAttributes, IMESSAGE_SETATTRIBUTE_S,
&msgData, isInitiator ? \
CRYPT_CERTINFO_SCEP_SENDERNONCE : \
CRYPT_CERTINFO_SCEP_RECIPIENTNONCE );
if( cryptStatusError( status ) )
krnlSendNotifier( iCmsAttributes, IMESSAGE_DECREFCOUNT );
else
*iScepAttributes = iCmsAttributes;
return( status );
}
/****************************************************************************
* *
* Init/Shutdown Functions *
* *
****************************************************************************/
/* Exchange data with an SCEP client/server */
static int clientTransact( SESSION_INFO *sessionInfoPtr )
{
SCEP_PROTOCOL_INFO protocolInfo;
int status;
assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
/* Get the issuing CA certificate via SCEP's bolted-on HTTP GET facility
if necessary */
if( sessionInfoPtr->iAuthInContext == CRYPT_ERROR )
{
status = createAdditionalScepRequest( sessionInfoPtr );
if( cryptStatusError( status ) )
return( status );
}
/* Create the self-signed cert that we need in order to sign and decrypt
messages */
initProtocolInfo( &protocolInfo );
status = createScepCertRequest( sessionInfoPtr );
if( cryptStatusOK( status ) )
status = createScepCert( sessionInfoPtr, &protocolInfo );
if( cryptStatusError( status ) )
return( status );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -