📄 cmp.c
字号:
msgData.length,
PROTOCOLINFO_SET_USERID | \
PROTOCOLINFO_SET_TRANSID );
return( status );
}
/* It's a cryptlib peer, the cert is identified by an unambiguous
cert ID */
return( setProtocolInfo( protocolInfo, NULL, 0,
PROTOCOLINFO_SET_TRANSID ) );
}
/* If there's a MAC context present from a previous transaction, reuse
it for the current one */
if( cmpInfo->savedMacContext != CRYPT_ERROR )
{
setProtocolInfo( protocolInfo, NULL, 0, PROTOCOLINFO_SET_TRANSID );
protocolInfo->useMACsend = protocolInfo->useMACreceive = TRUE;
protocolInfo->iMacContext = cmpInfo->savedMacContext;
cmpInfo->savedMacContext = CRYPT_ERROR;
return( CRYPT_OK );
}
/* We're using MAC authentication, initialise the protocol info */
if( userNamePtr->flags & ATTR_FLAG_ENCODEDVALUE )
{
BYTE decodedValue[ 64 + 8 ];
int decodedValueLength;
/* It's a cryptlib-style encoded user ID, decode it into its binary
value */
status = decodePKIUserValue( decodedValue, 64, &decodedValueLength,
userNamePtr->value,
userNamePtr->valueLength );
if( cryptStatusError( status ) )
{
assert( DEBUG_WARN );
retExt( status,
( status, SESSION_ERRINFO, "Invalid PKI user value" ) );
}
status = setProtocolInfo( protocolInfo, decodedValue,
decodedValueLength, PROTOCOLINFO_SET_ALL );
zeroise( decodedValue, CRYPT_MAX_TEXTSIZE );
}
else
{
/* It's a standard user ID, use it as is */
status = setProtocolInfo( protocolInfo, userNamePtr->value,
userNamePtr->valueLength,
PROTOCOLINFO_SET_ALL );
}
if( cryptStatusError( status ) )
return( status );
/* Set up the MAC context used to authenticate messages */
if( passwordPtr->flags & ATTR_FLAG_ENCODEDVALUE )
{
BYTE decodedValue[ 64 + 8 ];
int decodedValueLength;
/* It's a cryptlib-style encoded password, decode it into its binary
value */
status = decodePKIUserValue( decodedValue, 64, &decodedValueLength,
passwordPtr->value,
passwordPtr->valueLength );
if( cryptStatusError( status ) )
{
assert( DEBUG_WARN );
retExt( status,
( status, SESSION_ERRINFO, "Invalid PKI user value" ) );
}
status = initMacInfo( protocolInfo->iMacContext, decodedValue,
decodedValueLength, protocolInfo->salt,
protocolInfo->saltSize,
protocolInfo->iterations );
zeroise( decodedValue, CRYPT_MAX_TEXTSIZE );
}
else
{
/* It's a standard password, use it as is */
status = initMacInfo( protocolInfo->iMacContext,
passwordPtr->value, passwordPtr->valueLength,
protocolInfo->salt, protocolInfo->saltSize,
protocolInfo->iterations );
}
return( status );
}
/****************************************************************************
* *
* Init/Shutdown Functions *
* *
****************************************************************************/
/* Prepare a CMP session */
static int clientStartup( SESSION_INFO *sessionInfoPtr )
{
const PROTOCOL_INFO *protocolInfoPtr = sessionInfoPtr->protocolInfo;
CMP_INFO *cmpInfo = sessionInfoPtr->sessionCMP;
NET_CONNECT_INFO connectInfo;
int status;
assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
/* Make sure that we have all the needed information. Plug-and-play PKI
uses PKIBoot to get the CA cert and generates the requests internally,
so we only need to check for these values if we're doing standard
CMP. The check for user ID and authentication information has
already been done at the general session level */
if( !( cmpInfo->flags & CMP_PFLAG_PNPPKI ) )
{
if( cmpInfo->requestType == CRYPT_REQUESTTYPE_NONE )
{
setErrorInfo( sessionInfoPtr, CRYPT_SESSINFO_CMP_REQUESTTYPE,
CRYPT_ERRTYPE_ATTR_ABSENT );
return( CRYPT_ERROR_NOTINITED );
}
if( sessionInfoPtr->iAuthInContext == CRYPT_ERROR )
{
setErrorInfo( sessionInfoPtr, CRYPT_SESSINFO_CACERTIFICATE,
CRYPT_ERRTYPE_ATTR_ABSENT );
return( CRYPT_ERROR_NOTINITED );
}
if( cmpInfo->requestType != CRYPT_REQUESTTYPE_PKIBOOT && \
sessionInfoPtr->iCertRequest == CRYPT_ERROR )
{
setErrorInfo( sessionInfoPtr, CRYPT_SESSINFO_REQUEST,
CRYPT_ERRTYPE_ATTR_ABSENT );
return( CRYPT_ERROR_NOTINITED );
}
}
/*-----------------------------------------------------------------------*/
#ifdef SKIP_IO
goto skipIO;
#endif /* SKIP_IO */
/*-----------------------------------------------------------------------*/
/* Connect to the remote server */
initSessionNetConnectInfo( sessionInfoPtr, &connectInfo );
if( sessionInfoPtr->flags & SESSION_ISHTTPTRANSPORT )
status = sNetConnect( &sessionInfoPtr->stream, STREAM_PROTOCOL_HTTP,
&connectInfo, &sessionInfoPtr->errorInfo );
else
{
const ALTPROTOCOL_INFO *altProtocolInfoPtr = \
protocolInfoPtr->altProtocolInfo;
assert( sessionInfoPtr->flags & SESSION_USEALTTRANSPORT );
/* If we're using the HTTP port for a session-specific protocol,
change it to the default port for the session-specific protocol
instead */
if( connectInfo.port == 80 )
connectInfo.port = altProtocolInfoPtr->port;
status = sNetConnect( &sessionInfoPtr->stream,
altProtocolInfoPtr->type,
&connectInfo, &sessionInfoPtr->errorInfo );
}
return( status );
}
/* Shut down a CMP session */
static void shutdownFunction( SESSION_INFO *sessionInfoPtr )
{
CMP_INFO *cmpInfo = sessionInfoPtr->sessionCMP;
assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
/* Clean up CMP-specific objects */
if( cmpInfo->userInfo != CRYPT_ERROR )
krnlSendNotifier( cmpInfo->userInfo, IMESSAGE_DECREFCOUNT );
if( cmpInfo->savedMacContext != CRYPT_ERROR )
krnlSendNotifier( cmpInfo->savedMacContext, IMESSAGE_DECREFCOUNT );
sNetDisconnect( &sessionInfoPtr->stream );
}
/* Exchange data with a CMP client/server. Since the plug-and-play PKI
client performs multiple transactions, we wrap the basic clientTransact()
in an external function that either calls it indirectly when required
from the PnP code or just passes the call through to the transaction
function */
static int clientTransact( SESSION_INFO *sessionInfoPtr )
{
CMP_INFO *cmpInfo = sessionInfoPtr->sessionCMP;
CMP_PROTOCOL_INFO protocolInfo;
int status;
assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
/* Check that everything we need is present. If it's a general CMP
session this will already have been checked in clientStartup(), but
if it's coming from the PnPPKI wrapper it doesn't go through the
startup checks each time so we double-check here. Since any problem
is just a one-off programming error, we only need a debug assertion
rather than a hardcoded check */
assert( cmpInfo->requestType != CRYPT_REQUESTTYPE_NONE );
assert( cmpInfo->requestType == CRYPT_REQUESTTYPE_PKIBOOT || \
sessionInfoPtr->iCertRequest != CRYPT_ERROR );
assert( cmpInfo->requestType == CRYPT_REQUESTTYPE_PKIBOOT || \
sessionInfoPtr->iAuthInContext != CRYPT_ERROR );
/* Initialise the client-side protocol state info */
initProtocolInfo( &protocolInfo,
sessionInfoPtr->flags & SESSION_ISCRYPTLIB );
status = initClientInfo( sessionInfoPtr, &protocolInfo );
if( cryptStatusError( status ) )
{
destroyProtocolInfo( &protocolInfo );
return( status );
}
/* Write the message into the session buffer and send it to the server */
status = writePkiMessage( sessionInfoPtr, &protocolInfo,
( cmpInfo->requestType == \
CRYPT_REQUESTTYPE_PKIBOOT ) ? \
CMPBODY_GENMSG : CMPBODY_NORMAL );
if( cryptStatusOK( status ) )
{
DEBUG_DUMP_CMP( protocolInfo.operation, 1, sessionInfoPtr );
if( ( protocolInfo.operation == CTAG_PB_GENM || \
protocolInfo.operation == CTAG_PB_RR ) && \
!( sessionInfoPtr->protocolFlags & CMP_PFLAG_RETAINCONNECTION ) )
{
/* There's no confirmation handshake for PKIBoot or a revocation
request so we mark this as the last message if required */
sioctl( &sessionInfoPtr->stream, STREAM_IOCTL_LASTMESSAGE, NULL,
TRUE );
}
status = writePkiDatagram( sessionInfoPtr, CMP_CONTENT_TYPE,
CMP_CONTENT_TYPE_LEN );
}
if( cryptStatusError( status ) )
{
destroyProtocolInfo( &protocolInfo );
return( status );
}
/* Read the server response */
status = readPkiDatagram( sessionInfoPtr );
if( cryptStatusOK( status ) )
{
const int responseType = reqToResp( protocolInfo.operation );
DEBUG_DUMP_CMP( protocolInfo.operation, 2, sessionInfoPtr );
if( cryptStatusError( responseType ) )
status = responseType;
else
{
status = readPkiMessage( sessionInfoPtr, &protocolInfo,
responseType );
}
}
if( cryptStatusOK( status ) && protocolInfo.operation == CTAG_PB_GENM )
{
/* It's a PKIBoot, add the trusted certs. If the user wants the
setting made permanent, they need to flush the config to disk
after the session has completed */
status = krnlSendMessage( sessionInfoPtr->ownerHandle,
IMESSAGE_SETATTRIBUTE,
&sessionInfoPtr->iCertResponse,
CRYPT_IATTRIBUTE_CTL );
if( status == CRYPT_ERROR_INITED )
{
/* If the certs are already present, trying to add them again
isn't an error */
status = CRYPT_OK;
}
}
if( cryptStatusError( status ) )
{
destroyProtocolInfo( &protocolInfo );
return( status );
}
/* If it's a transaction type that doesn't need a confirmation, we're
done */
if( protocolInfo.operation == CTAG_PB_GENM || \
protocolInfo.operation == CTAG_PB_RR )
{
if( protocolInfo.iMacContext != CRYPT_ERROR )
{
/* 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 );
}
/* Exchange confirmation data with the server */
if( !( sessionInfoPtr->protocolFlags & CMP_PFLAG_RETAINCONNECTION ) )
sioctl( &sessionInfoPtr->stream, STREAM_IOCTL_LASTMESSAGE, NULL,
TRUE );
status = writePkiMessage( sessionInfoPtr, &protocolInfo,
CMPBODY_CONFIRMATION );
if( cryptStatusOK( status ) )
{
DEBUG_DUMP_CMP( protocolInfo.operation, 3, sessionInfoPtr );
status = writePkiDatagram( sessionInfoPtr, CMP_CONTENT_TYPE,
CMP_CONTENT_TYPE_LEN );
}
if( cryptStatusOK( status ) )
status = readPkiDatagram( sessionInfoPtr );
if( cryptStatusOK( status ) )
{
DEBUG_DUMP_CMP( protocolInfo.operation, 4, sessionInfoPtr );
status = readPkiMessage( sessionInfoPtr, &protocolInfo, CTAG_PB_PKICONF );
}
if( cryptStatusOK( status ) && protocolInfo.iMacContext != CRYPT_ERROR )
{
/* Remember the authentication context in case we can reuse it for
another transaction */
cmpInfo->savedMacContext = protocolInfo.iMacContext;
protocolInfo.iMacContext = CRYPT_ERROR;
}
destroyProtocolInfo( &protocolInfo );
return( status );
}
static int clientTransactWrapper( SESSION_INFO *sessionInfoPtr )
{
int status;
assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
/* If it's not a plug-and-play PKI session, just pass the call on down
to the client transaction function */
if( !( sessionInfoPtr->sessionCMP->flags & CMP_PFLAG_PNPPKI ) )
return( clientTransact( sessionInfoPtr ) );
/* We're doing plug-and-play PKI, point the transaction function at the
client-transact function to execute the PnP steps, then reset it back
to the PnP wrapper after we're done */
sessionInfoPtr->transactFunction = clientTransact;
status = pnpPkiSession( sessionInfoPtr );
sessionInfoPtr->transactFunction = clientTransactWrapper;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -