📄 scep.c
字号:
"signing/encryption" );
}
/* Get the nonce and transaction ID and save it for the reply */
setMessageData( &msgData, protocolInfo->nonce, CRYPT_MAX_HASHSIZE );
status = krnlSendMessage( iCmsAttributes, IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_CERTINFO_SCEP_SENDERNONCE );
if( cryptStatusOK( status ) )
{
protocolInfo->nonceSize = msgData.length;
setMessageData( &msgData, protocolInfo->transID, CRYPT_MAX_HASHSIZE );
status = krnlSendMessage( iCmsAttributes, IMESSAGE_GETATTRIBUTE_S,
&msgData,
CRYPT_CERTINFO_SCEP_TRANSACTIONID );
}
if( cryptStatusError( status ) )
{
krnlSendNotifier( iCmsAttributes, IMESSAGE_DECREFCOUNT );
retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
"Request is missing nonce/transaction ID" );
}
protocolInfo->transIDsize = msgData.length;
/* We've got a transaction ID (user ID), remember it for later and record
whether it's a cryptlib encoded ID */
memcpy( sessionInfoPtr->userName, protocolInfo->transID,
protocolInfo->transIDsize );
sessionInfoPtr->userNameLength = protocolInfo->transIDsize;
if( protocolInfo->transIDsize == 17 && \
isPKIUserValue( protocolInfo->transID, protocolInfo->transIDsize ) )
sessionInfoPtr->flags |= SESSION_ISENCODEDUSERID;
/* Check that we've been sent the correct type of message */
status = getStatusValue( iCmsAttributes,
CRYPT_CERTINFO_SCEP_MESSAGETYPE, &value );
if( cryptStatusOK( status ) && value != MESSAGETYPE_PKCSREQ_VALUE )
status = CRYPT_ERROR_BADDATA;
krnlSendNotifier( iCmsAttributes, IMESSAGE_DECREFCOUNT );
if( cryptStatusError( status ) )
retExt( sessionInfoPtr, status, "Incorrect SCEP message type %d",
value );
/* Phase 2: Decrypt the data using our CA key */
status = envelopeUnwrap( sessionInfoPtr->receiveBuffer, dataLength,
sessionInfoPtr->receiveBuffer, &dataLength,
sessionInfoPtr->receiveBufSize,
sessionInfoPtr->privateKey );
if( cryptStatusError( status ) )
retExt( sessionInfoPtr, status,
"Couldn't decrypt CMS enveloped data in client request" );
/* Finally, import the request as a PKCS #10 request */
setMessageCreateObjectIndirectInfo( &createInfo,
sessionInfoPtr->receiveBuffer, dataLength,
CRYPT_CERTTYPE_CERTREQUEST );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
IMESSAGE_DEV_CREATEOBJECT_INDIRECT,
&createInfo, OBJECT_TYPE_CERTIFICATE );
if( cryptStatusError( status ) )
retExt( sessionInfoPtr, status,
"Invalid PKCS #10 request in client request" );
sessionInfoPtr->iCertRequest = createInfo.cryptHandle;
return( CRYPT_OK );
}
/* Create an SCEP response message */
static int createPkcsResponse( SESSION_INFO *sessionInfoPtr,
SCEP_PROTOCOL_INFO *protocolInfo )
{
CRYPT_CERTIFICATE iCmsAttributes;
RESOURCE_DATA msgData;
int dataLength, status;
/* Extract the response data into the session buffer */
setMessageData( &msgData, sessionInfoPtr->receiveBuffer,
sessionInfoPtr->receiveBufSize );
status = krnlSendMessage( sessionInfoPtr->iCertResponse,
IMESSAGE_CRT_EXPORT, &msgData,
CRYPT_CERTFORMAT_CERTCHAIN );
if( cryptStatusError( status ) )
retExt( sessionInfoPtr, status,
"Couldn't get PKCS #7 cert chain from SCEP response object" );
DEBUG_DUMP( "scep_sresp0", sessionInfoPtr->receiveBuffer, msgData.length );
/* Phase 1: Encrypt the data using the client's key */
status = envelopeWrap( sessionInfoPtr->receiveBuffer, msgData.length,
sessionInfoPtr->receiveBuffer, &dataLength,
sessionInfoPtr->receiveBufSize,
CRYPT_FORMAT_CMS, CRYPT_UNUSED,
protocolInfo->iScepCert );
if( cryptStatusError( status ) )
retExt( sessionInfoPtr, status,
"Couldn't encrypt response data with client key" );
DEBUG_DUMP( "scep_sresp1", sessionInfoPtr->receiveBuffer, dataLength );
/* Create the SCEP signing attributes */
status = createScepAttributes( sessionInfoPtr, protocolInfo,
&iCmsAttributes, FALSE, CRYPT_OK );
if( cryptStatusError( status ) )
retExt( sessionInfoPtr, status,
"Couldn't create SCEP response signing attributes" );
/* Phase 2: Sign the data using the CA key and SCEP attributes */
status = envelopeSign( sessionInfoPtr->receiveBuffer, dataLength,
sessionInfoPtr->receiveBuffer,
&sessionInfoPtr->receiveBufEnd,
sessionInfoPtr->receiveBufSize,
CRYPT_CONTENT_NONE, sessionInfoPtr->privateKey,
iCmsAttributes );
krnlSendNotifier( iCmsAttributes, IMESSAGE_DECREFCOUNT );
if( cryptStatusError( status ) )
retExt( sessionInfoPtr, status,
"Couldn't sign response data with CA key" );
DEBUG_DUMP( "scep_sresp2", sessionInfoPtr->receiveBuffer,
sessionInfoPtr->receiveBufEnd );
return( CRYPT_OK );
}
/****************************************************************************
* *
* Init/Shutdown Functions *
* *
****************************************************************************/
/* Exchange data with an SCEP client/server */
static int clientTransact( SESSION_INFO *sessionInfoPtr )
{
SCEP_PROTOCOL_INFO protocolInfo;
int status;
/* Make sure that we have all of the needed information */
if( sessionInfoPtr->iAuthInContext == CRYPT_ERROR )
{
setErrorInfo( sessionInfoPtr, CRYPT_SESSINFO_CACERTIFICATE,
CRYPT_ERRTYPE_ATTR_ABSENT );
return( CRYPT_ERROR_NOTINITED );
}
/* Create the self-signed cert that we need in order to sign and decrypt
messages */
initProtocolInfo( &protocolInfo );
status = createScepRequest( sessionInfoPtr );
if( cryptStatusOK( status ) )
status = createScepCert( sessionInfoPtr, &protocolInfo );
if( cryptStatusError( status ) )
return( status );
/* Get a new cert from the server */
status = createPkcsRequest( sessionInfoPtr, &protocolInfo );
if( cryptStatusOK( status ) )
status = writePkiDatagram( sessionInfoPtr );
if( cryptStatusOK( status ) )
status = readPkiDatagram( sessionInfoPtr );
if( cryptStatusOK( status ) )
status = checkPkcsResponse( sessionInfoPtr, &protocolInfo );
krnlSendNotifier( protocolInfo.iScepCert, IMESSAGE_DECREFCOUNT );
return( status );
}
static int serverTransact( SESSION_INFO *sessionInfoPtr )
{
SCEP_PROTOCOL_INFO protocolInfo;
int status;
/* Read the initial message from the client. We don't write an error
response at the initial read stage to prevent scanning/DOS attacks
(vir sapit qui pauca loquitur) */
initProtocolInfo( &protocolInfo );
status = readPkiDatagram( sessionInfoPtr );
if( cryptStatusOK( status ) )
status = checkPkcsRequest( sessionInfoPtr, &protocolInfo );
if( cryptStatusError( status ) )
return( status );
/* Check that the request is permitted and convert it into a
certificate */
status = checkPkiUserInfo( sessionInfoPtr, &protocolInfo );
if( cryptStatusOK( status ) )
{
MESSAGE_KEYMGMT_INFO setkeyInfo;
setMessageKeymgmtInfo( &setkeyInfo, CRYPT_KEYID_NONE, NULL, 0,
NULL, 0, KEYMGMT_FLAG_NONE );
setkeyInfo.cryptHandle = sessionInfoPtr->iCertRequest;
status = krnlSendMessage( sessionInfoPtr->cryptKeyset,
IMESSAGE_KEY_SETKEY, &setkeyInfo,
KEYMGMT_ITEM_REQUEST );
if( cryptStatusError( status ) )
strcpy( sessionInfoPtr->errorMessage,
"Request couldn't be added to cert store" );
}
if( cryptStatusOK( status ) )
{
MESSAGE_CERTMGMT_INFO certMgmtInfo;
setMessageCertMgmtInfo( &certMgmtInfo, sessionInfoPtr->privateKey,
sessionInfoPtr->iCertRequest );
status = krnlSendMessage( sessionInfoPtr->cryptKeyset,
IMESSAGE_KEY_CERTMGMT, &certMgmtInfo,
CRYPT_CERTACTION_ISSUE_CERT );
if( cryptStatusOK( status ) )
sessionInfoPtr->iCertResponse = certMgmtInfo.cryptCert;
else
strcpy( sessionInfoPtr->errorMessage,
"Couldn't issue certificate for user" );
}
if( cryptStatusError( status ) )
{
sendErrorResponse( sessionInfoPtr, &protocolInfo, status );
destroyProtocolInfo( &protocolInfo );
return( status );
}
/* Return the certificate to the client */
status = createPkcsResponse( sessionInfoPtr, &protocolInfo );
if( cryptStatusOK( status ) )
status = writePkiDatagram( sessionInfoPtr );
destroyProtocolInfo( &protocolInfo );
return( status );
}
/****************************************************************************
* *
* Control Information Management Functions *
* *
****************************************************************************/
static int setAttributeFunction( SESSION_INFO *sessionInfoPtr,
const void *data,
const CRYPT_ATTRIBUTE_TYPE type )
{
CRYPT_CERTIFICATE cryptCert = *( ( CRYPT_CERTIFICATE * ) data );
int value, status;
assert( type == CRYPT_SESSINFO_REQUEST || \
type == CRYPT_SESSINFO_CACERTIFICATE );
/* Make sure that everything is set up ready to go */
status = krnlSendMessage( cryptCert, IMESSAGE_GETATTRIBUTE, &value,
CRYPT_CERTINFO_IMMUTABLE );
#if 0
if( cryptStatusError( status ) || !value )
return( CRYPT_ARGERROR_NUM1 );
#else
if( type == CRYPT_SESSINFO_CACERTIFICATE )
{
if( cryptStatusError( status ) || !value )
return( CRYPT_ARGERROR_NUM1 );
}
else
/* For now we require that the PKCS #10 request be unsigned so that
we can add the challengePassword */
if( cryptStatusError( status ) || value )
return( CRYPT_ARGERROR_NUM1 );
#endif
if( type == CRYPT_SESSINFO_CACERTIFICATE )
{
#if 0 /* RA certs aren't necessarily CA certs */
/* Make sure that it really is a CA cert */
status = krnlSendMessage( cryptCert, IMESSAGE_CHECK, NULL,
MESSAGE_CHECK_CA );
if( cryptStatusError( status ) )
{
setErrorInfo( sessionInfoPtr, CRYPT_CERTINFO_CA,
CRYPT_ERRTYPE_ATTR_ABSENT );
return( CRYPT_ARGERROR_NUM1 );
}
#endif /* 0 */
/* Make sure that it can sign and encrypt (normally a bad idea for CA
certs, but needed for SCEP) */
status = krnlSendMessage( cryptCert, IMESSAGE_CHECK, NULL,
MESSAGE_CHECK_PKC_SIGCHECK );
if( cryptStatusOK( status ) )
status = krnlSendMessage( cryptCert, IMESSAGE_CHECK, NULL,
MESSAGE_CHECK_PKC_ENCRYPT );
if( cryptStatusError( status ) )
{
setErrorInfo( sessionInfoPtr, CRYPT_CERTINFO_KEYUSAGE,
CRYPT_ERRTYPE_ATTR_VALUE );
return( CRYPT_ARGERROR_NUM1 );
}
}
/* Add the request and increment its usage count */
krnlSendNotifier( cryptCert, IMESSAGE_INCREFCOUNT );
if( type == CRYPT_SESSINFO_CACERTIFICATE )
sessionInfoPtr->iAuthInContext = cryptCert;
else
sessionInfoPtr->iCertRequest = cryptCert;
return( CRYPT_OK );
}
static int checkAttributeFunction( SESSION_INFO *sessionInfoPtr,
const CRYPT_HANDLE cryptHandle,
const CRYPT_ATTRIBUTE_TYPE type )
{
int status;
if( type != CRYPT_SESSINFO_PRIVATEKEY )
return( CRYPT_OK );
/* If it's a client key, make sure that there's no cert attached */
if( !( sessionInfoPtr->flags & SESSION_ISSERVER ) )
{
int value;
status = krnlSendMessage( cryptHandle, IMESSAGE_GETATTRIBUTE, &value,
CRYPT_CERTINFO_CERTTYPE );
if( cryptStatusOK( status ) )
return( CRYPT_ARGERROR_NUM1 );
}
return( CRYPT_OK );
}
/****************************************************************************
* *
* Session Access Routines *
* *
****************************************************************************/
int setAccessMethodSCEP( SESSION_INFO *sessionInfoPtr )
{
static const PROTOCOL_INFO protocolInfo = {
/* General session information */
TRUE, /* Request-response protocol */
SESSION_ISHTTPTRANSPORT, /* Flags */
80, /* HTTP port */
SESSION_NEEDS_USERID | /* Client attributes */
SESSION_NEEDS_PASSWORD | \
SESSION_NEEDS_PRIVATEKEY | \
SESSION_NEEDS_PRIVKEYSIGN | \
SESSION_NEEDS_PRIVKEYCRYPT | \
SESSION_NEEDS_REQUEST,
SESSION_NEEDS_PRIVATEKEY | /* Server attributes */
SESSION_NEEDS_PRIVKEYSIGN | \
SESSION_NEEDS_PRIVKEYCRYPT | \
SESSION_NEEDS_PRIVKEYCERT | \
SESSION_NEEDS_PRIVKEYCACERT | \
SESSION_NEEDS_CERTSTORE,
1, 1, 1, /* Version 1 */
"application/x-pki-message",/* Client content-type */
"application/x-pki-message",/* Server content-type */
};
/* Set the access method pointers */
sessionInfoPtr->protocolInfo = &protocolInfo;
if( sessionInfoPtr->flags & SESSION_ISSERVER )
sessionInfoPtr->transactFunction = serverTransact;
else
sessionInfoPtr->transactFunction = clientTransact;
sessionInfoPtr->setAttributeFunction = setAttributeFunction;
sessionInfoPtr->checkAttributeFunction = checkAttributeFunction;
return( CRYPT_OK );
}
#endif /* USE_SCEP */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -