📄 cmp.c
字号:
return( status );
}
static int serverTransact( SESSION_INFO *sessionInfoPtr )
{
CMP_INFO *cmpInfo = sessionInfoPtr->sessionCMP;
MESSAGE_CERTMGMT_INFO certMgmtInfo;
MESSAGE_KEYMGMT_INFO setkeyInfo;
CMP_PROTOCOL_INFO protocolInfo;
const ATTRIBUTE_LIST *userNamePtr = \
findSessionInfo( sessionInfoPtr->attributeList,
CRYPT_SESSINFO_USERNAME );
int status;
assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
/* Initialise the server-side protocol state info. Since the server
doesn't have a user ID (it uses what the client sends it), we set the
userID-sent flag to indicate that it's been implicitly exchanged */
initProtocolInfo( &protocolInfo,
sessionInfoPtr->flags & SESSION_ISCRYPTLIB );
protocolInfo.authContext = sessionInfoPtr->privateKey;
sessionInfoPtr->protocolFlags |= CMP_PFLAG_USERIDSENT;
if( userNamePtr != NULL )
{
/* There's already user info present from a previous transaction,
try and re-use the info from it (this can be overridden by the
client sending us new user info) */
if( userNamePtr->flags & ATTR_FLAG_ENCODEDVALUE )
{
/* It's a cryptlib-style encoded user ID, decode it into its
binary value */
status = decodePKIUserValue( protocolInfo.userID,
CRYPT_MAX_TEXTSIZE,
&protocolInfo.userIDsize,
userNamePtr->value,
userNamePtr->valueLength );
if( cryptStatusError( status ) )
retIntError();
}
else
{
/* It's a standard user ID, use it as is */
memcpy( protocolInfo.userID, userNamePtr->value,
userNamePtr->valueLength );
protocolInfo.userIDsize = userNamePtr->valueLength;
}
protocolInfo.iMacContext = cmpInfo->savedMacContext;
cmpInfo->savedMacContext = CRYPT_ERROR;
}
/* 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) */
status = readPkiDatagram( sessionInfoPtr );
if( cryptStatusError( status ) )
{
destroyProtocolInfo( &protocolInfo );
return( status );
}
status = readPkiMessage( sessionInfoPtr, &protocolInfo,
CRYPT_UNUSED );
if( cryptStatusOK( status ) )
{
cmpInfo->requestType = reqToClibReq( protocolInfo.operation );
if( cryptStatusError( cmpInfo->requestType ) )
status = cmpInfo->requestType;
}
if( cryptStatusError( status ) )
{
sendErrorResponse( sessionInfoPtr, &protocolInfo, status );
destroyProtocolInfo( &protocolInfo );
return( status );
}
DEBUG_DUMP_CMP( protocolInfo.operation, 1, sessionInfoPtr );
/* If it's a PKIBoot request, send the PKIBoot response and retry the
read unless the client closes the stream. This assumes that the
client will generally send a PKIBoot request in conjunction with a
cert management request (i.e. as part of a PnP PKI transaction),
which allows us to reuse the user authentication info to process the
request that follows the PKIBoot */
if( cmpInfo->requestType == CRYPT_REQUESTTYPE_PKIBOOT )
{
int streamState;
/* Handle the PKIBoot request */
status = writePkiMessage( sessionInfoPtr, &protocolInfo,
CMPBODY_GENMSG );
if( cryptStatusOK( status ) )
{
DEBUG_DUMP_CMP( CTAG_PB_GENM, 2, sessionInfoPtr );
status = writePkiDatagram( sessionInfoPtr, CMP_CONTENT_TYPE,
CMP_CONTENT_TYPE_LEN );
}
if( cryptStatusError( status ) )
{
sendErrorResponse( sessionInfoPtr, &protocolInfo, status );
destroyProtocolInfo( &protocolInfo );
return( status );
}
/* Check whether the client left the stream open. If they haven't,
it was a standalone PKIBoot request and we're done */
sioctl( &sessionInfoPtr->stream, STREAM_IOCTL_CONNSTATE,
&streamState, 0 );
if( !streamState )
{
destroyProtocolInfo( &protocolInfo );
return( CRYPT_OK );
}
/* Process the request that follows the PKIBoot. If the client
was only performing a standardlone PKIBoot but left the
connection open in case further transactions were necesary
later, but then shut down the connection without performing
any further transactions, we'll get a read error at this point,
which we convert into a OK status */
status = readPkiDatagram( sessionInfoPtr );
if( cryptStatusOK( status ) )
status = readPkiMessage( sessionInfoPtr, &protocolInfo,
CRYPT_UNUSED );
if( cryptStatusError( status ) )
{
sioctl( &sessionInfoPtr->stream, STREAM_IOCTL_CONNSTATE,
&streamState, 0 );
if( streamState )
/* Only send an error response if the stream is still open */
sendErrorResponse( sessionInfoPtr, &protocolInfo, status );
destroyProtocolInfo( &protocolInfo );
return( streamState ? status : CRYPT_OK );
}
}
/* Make sure that the signature on the request data is OK (unless it's a
non-signed revocation request or a request for an encryption-only
key) */
if( protocolInfo.operation != CTAG_PB_RR && !protocolInfo.cryptOnlyKey )
status = krnlSendMessage( sessionInfoPtr->iCertRequest,
IMESSAGE_CRT_SIGCHECK, NULL, CRYPT_UNUSED );
if( cryptStatusError( status ) )
{
sendErrorResponse( sessionInfoPtr, &protocolInfo, status );
destroyProtocolInfo( &protocolInfo );
retExt( status,
( status, SESSION_ERRINFO,
"Request signature check failed" ) );
}
/* Add the request to the cert store */
setMessageKeymgmtInfo( &setkeyInfo, CRYPT_KEYID_NONE, NULL, 0, NULL, 0,
( protocolInfo.operation == CTAG_PB_KUR ) ? \
KEYMGMT_FLAG_UPDATE : KEYMGMT_FLAG_NONE );
setkeyInfo.cryptHandle = sessionInfoPtr->iCertRequest;
status = krnlSendMessage( sessionInfoPtr->cryptKeyset,
IMESSAGE_KEY_SETKEY, &setkeyInfo,
KEYMGMT_ITEM_REQUEST );
if( cryptStatusError( status ) )
{
/* If the cert store reports that there's a problem with the request,
convert it to an invalid request error */
if( status == CRYPT_ARGERROR_NUM1 )
status = CRYPT_ERROR_INVALID;
/* A common error condition at this point arises when the user tries
to submit a second initialisation request for a PKI user that has
already had a cert issued for it, so we catch this condition and
provide a more informative error response than the generic
message */
if( protocolInfo.operation == CTAG_PB_IR && \
status == CRYPT_ERROR_DUPLICATE )
protocolInfo.pkiFailInfo = CMPFAILINFO_DUPLICATECERTREQ;
/* Clean up and return the appropriate error information to the
caller */
sendErrorResponse( sessionInfoPtr, &protocolInfo, status );
destroyProtocolInfo( &protocolInfo );
if( protocolInfo.operation == CTAG_PB_IR && \
status == CRYPT_ERROR_DUPLICATE )
retExtObj( status,
( status, SESSION_ERRINFO, sessionInfoPtr->cryptKeyset,
"Initialisation request couldn't be added to the "
"cert store because another initialisation request "
"has already been processed for this user" ) );
retExtObj( status,
( status, SESSION_ERRINFO, sessionInfoPtr->cryptKeyset,
"Request couldn't be added to the cert store" ) );
}
/* Create or revoke a cert from the request */
if( protocolInfo.operation != CTAG_PB_RR )
{
setMessageCertMgmtInfo( &certMgmtInfo, sessionInfoPtr->privateKey,
sessionInfoPtr->iCertRequest );
status = krnlSendMessage( sessionInfoPtr->cryptKeyset,
IMESSAGE_KEY_CERTMGMT, &certMgmtInfo,
CRYPT_CERTACTION_CERT_CREATION );
if( cryptStatusOK( status ) )
sessionInfoPtr->iCertResponse = certMgmtInfo.cryptCert;
}
else
{
setMessageCertMgmtInfo( &certMgmtInfo, CRYPT_UNUSED,
sessionInfoPtr->iCertRequest );
status = krnlSendMessage( sessionInfoPtr->cryptKeyset,
IMESSAGE_KEY_CERTMGMT, &certMgmtInfo,
CRYPT_CERTACTION_REVOKE_CERT );
}
if( cryptStatusError( status ) )
{
/* If the cert store reports that there's a problem with the request,
convert it to an invalid request error */
if( status == CRYPT_ARGERROR_NUM1 )
status = CRYPT_ERROR_INVALID;
sendErrorResponse( sessionInfoPtr, &protocolInfo, status );
destroyProtocolInfo( &protocolInfo );
retExtObj( status,
( status, SESSION_ERRINFO, sessionInfoPtr->cryptKeyset,
"%s was denied by cert store",
( protocolInfo.operation != CTAG_PB_RR ) ? \
"Cert issue" : "Revocation" ) );
}
/* Send the response to the client */
status = writePkiMessage( sessionInfoPtr, &protocolInfo, CMPBODY_NORMAL );
if( cryptStatusOK( status ) )
{
DEBUG_DUMP_CMP( protocolInfo.operation, 2, sessionInfoPtr );
status = writePkiDatagram( sessionInfoPtr, CMP_CONTENT_TYPE,
CMP_CONTENT_TYPE_LEN );
}
if( cryptStatusError( status ) )
{
sendErrorResponse( sessionInfoPtr, &protocolInfo, status );
if( protocolInfo.operation != CTAG_PB_RR )
{
/* If there was a problem, drop the partially-issued cert. We
don't have to go all the way and do a full reversal because
it hasn't really been issued yet since we couldn't get it to
the client. In addition we don't do anything with the return
status since we want to return the status that caused the
problem, not the result of the drop operation */
setMessageCertMgmtInfo( &certMgmtInfo, CRYPT_UNUSED,
sessionInfoPtr->iCertResponse );
krnlSendMessage( sessionInfoPtr->cryptKeyset,
IMESSAGE_KEY_CERTMGMT, &certMgmtInfo,
CRYPT_CERTACTION_CERT_CREATION_DROP );
}
destroyProtocolInfo( &protocolInfo );
return( status );
}
/* If it's a transaction type that doesn't need a confirmation, we're
done */
if( protocolInfo.operation == CTAG_PB_RR )
{
/* Remember the authentication context in case we can reuse it for
another transaction */
cmpInfo->savedMacContext = protocolInfo.iMacContext;
protocolInfo.iMacContext = CRYPT_ERROR;
destroyProtocolInfo( &protocolInfo );
return( CRYPT_OK );
}
/* Read back the confirmation from the client */
status = readPkiDatagram( sessionInfoPtr );
if( cryptStatusOK( status ) )
status = readPkiMessage( sessionInfoPtr, &protocolInfo,
CTAG_PB_CERTCONF );
if( cryptStatusError( status ) || \
protocolInfo.status == CRYPT_ERROR )
{
int localStatus;
/* If the client rejected the cert this isn't a protocol error so we
send back a standard ack, otherwise we send back an error response */
if( protocolInfo.status == CRYPT_ERROR )
{
localStatus = writePkiMessage( sessionInfoPtr, &protocolInfo,
CMPBODY_ACK );
if( cryptStatusOK( localStatus ) )
localStatus = writePkiDatagram( sessionInfoPtr,
CMP_CONTENT_TYPE,
CMP_CONTENT_TYPE_LEN );
if( cryptStatusOK( status ) )
{
/* If we haven't already got an error status set from an
earlier operation, remember the status from sending the
ack */
status = localStatus;
}
}
else
sendErrorResponse( sessionInfoPtr, &protocolInfo, status );
destroyProtocolInfo( &protocolInfo );
/* Reverse the cert issue operation by revoking the incompletely-
issued cert. We only return the status from this operation if
we're performing the reversal at the request of the user (i.e. if
the earlier operations succeeded), if not we return the status
that caused the failure earlier on */
setMessageCertMgmtInfo( &certMgmtInfo, CRYPT_UNUSED,
sessionInfoPtr->iCertResponse );
localStatus = krnlSendMessage( sessionInfoPtr->cryptKeyset,
IMESSAGE_KEY_CERTMGMT, &certMgmtInfo,
CRYPT_CERTACTION_CERT_CREATION_REVERSE );
return( cryptStatusOK( status ) ? localStatus : status );
}
DEBUG_DUMP_CMP( protocolInfo.operation, 3, sessionInfoPtr );
/* The client has confirmed the cert creation, finalise it */
setMessageCertMgmtInfo( &certMgmtInfo, CRYPT_UNUSED,
sessionInfoPtr->iCertResponse );
status = krnlSendMessage( sessionInfoPtr->cryptKeyset,
IMESSAGE_KEY_CERTMGMT, &certMgmtInfo,
CRYPT_CERTACTION_CERT_CREATION_COMPLETE );
if( cryptStatusError( status ) )
{
sendErrorResponse( sessionInfoPtr, &protocolInfo, status );
destroyProtocolInfo( &protocolInfo );
retExtObj( status,
( status, SESSION_ERRINFO, sessionInfoPtr->cryptKeyset,
"Cert issue completion failed" ) );
}
/* Send back the final ack and clean up. We remember the authentication
context in case we can reuse it for another transaction */
status = writePkiMessage( sessionInfoPtr, &protocolInfo, CMPBODY_ACK );
if( cryptStatusOK( status ) )
{
DEBUG_DUMP_CMP( protocolInfo.operation, 4, sessionInfoPtr );
status = writePkiDatagram( sessionInfoPtr, CMP_CONTENT_TYPE,
CMP_CONTENT_TYPE_LEN );
}
cmpInfo->savedMacContext = protocolInfo.iMacContext;
protocolInfo.iMacContext = CRYPT_ERROR;
destroyProtocolInfo( &protocolInfo );
return( status );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -