📄 cmp.c
字号:
CMP_PROTOCOL_INFO *protocolInfo )
{
MESSAGE_KEYMGMT_INFO getkeyInfo;
int status;
/* Set up general authentication information and if there's client auth.
info still present from a previous transaction that used MAC
authentication, clear it */
status = setProtocolInfo( protocolInfo, NULL, 0, 0 );
if( cryptStatusError( status ) )
return( status );
if( sessionInfoPtr->cmpUserInfo != CRYPT_ERROR )
{
krnlSendNotifier( sessionInfoPtr->cmpUserInfo,
IMESSAGE_DECREFCOUNT );
sessionInfoPtr->cmpUserInfo = CRYPT_ERROR;
}
/* Get the user info for the user that originally authorised the issue
of the cert that signed the request. This serves two purposes, it
obtains the user ID if it wasn't supplied in the request (for example
if the request uses only a cert ID), and it verifies that the
authorising cert belongs to a valid user */
setMessageKeymgmtInfo( &getkeyInfo, CRYPT_IKEYID_CERTID,
protocolInfo->certID, protocolInfo->certIDsize,
NULL, 0, KEYMGMT_FLAG_GETISSUER );
status = krnlSendMessage( sessionInfoPtr->cryptKeyset,
IMESSAGE_KEY_GETKEY, &getkeyInfo,
KEYMGMT_ITEM_PKIUSER );
if( cryptStatusError( status ) )
{
protocolInfo->pkiFailInfo = CMPFAILINFO_SIGNERNOTTRUSTED;
retExt( sessionInfoPtr, status,
"Couldn't find PKI user information for owner of requesting "
"cert" );
}
if( !( sessionInfoPtr->flags & SESSION_ISENCODEDUSERID ) )
{
RESOURCE_DATA msgData;
/* There's currently no user ID present (or if it's present it's a
non-userID value such as a cert ID), replace it with the PKI user
ID */
setMessageData( &msgData, sessionInfoPtr->userName,
CRYPT_MAX_TEXTSIZE );
status = krnlSendMessage( getkeyInfo.cryptHandle,
IMESSAGE_GETATTRIBUTE_S, &msgData,
CRYPT_CERTINFO_PKIUSER_ID );
if( cryptStatusError( status ) )
retExt( sessionInfoPtr, status,
"Couldn't read PKI user data from PKI user object" );
sessionInfoPtr->userNameLength = msgData.length;
sessionInfoPtr->flags |= SESSION_ISENCODEDUSERID;
}
krnlSendNotifier( getkeyInfo.cryptHandle, IMESSAGE_DECREFCOUNT );
/* Get the public key identified by the cert ID from the cert store.
This assumes that the owner of an existing cert/existing user is
authorised to request further certs using the existing one. If we
get a not found error we report it as "signer not trusted", which
can also mean "signer unknown" */
setMessageKeymgmtInfo( &getkeyInfo, CRYPT_IKEYID_CERTID,
protocolInfo->certID, protocolInfo->certIDsize,
NULL, 0, KEYMGMT_FLAG_USAGE_SIGN );
status = krnlSendMessage( sessionInfoPtr->cryptKeyset,
IMESSAGE_KEY_GETKEY, &getkeyInfo,
KEYMGMT_ITEM_PUBLICKEY );
if( cryptStatusError( status ) )
{
protocolInfo->pkiFailInfo = CMPFAILINFO_SIGNERNOTTRUSTED;
retExt( sessionInfoPtr, status,
"Couldn't find certificate for requested user" );
}
sessionInfoPtr->iAuthInContext = getkeyInfo.cryptHandle;
protocolInfo->userIDchanged = FALSE;
return( CRYPT_OK );
}
/* Hash/MAC the message header and body */
int hashMessageContents( const CRYPT_CONTEXT iHashContext,
const void *data, const int length )
{
STREAM stream;
BYTE buffer[ 8 ];
/* Delete the hash/MAC value, which resets the context */
krnlSendMessage( iHashContext, IMESSAGE_DELETEATTRIBUTE, NULL,
CRYPT_CTXINFO_HASHVALUE );
/* Write the pseudoheader used for hashing/MACing the header and body and
hash/MAC it */
sMemOpen( &stream, buffer, 8 );
writeSequence( &stream, length );
krnlSendMessage( iHashContext, IMESSAGE_CTX_HASH, buffer,
stell( &stream ) );
sMemClose( &stream );
krnlSendMessage( iHashContext, IMESSAGE_CTX_HASH, ( void * ) data,
length );
return( krnlSendMessage( iHashContext, IMESSAGE_CTX_HASH, buffer, 0 ) );
}
/* Deliver an Einladung betreff Kehrseite to the client. We don't bother
checking the return value since there's nothing that we can do in the
case of an error except close the connection, which we do anyway since
this is the last message */
static void sendErrorResponse( SESSION_INFO *sessionInfoPtr,
CMP_PROTOCOL_INFO *protocolInfo,
const int status )
{
/* If we were going to protect the communication with the client with a
MAC and something failed, make sure that we don't try and MAC the
response since the failure could be a client MAC failure, failure to
locate the MAC key, etc etc */
protocolInfo->useMACsend = FALSE;
protocolInfo->status = status;
sioctl( &sessionInfoPtr->stream, STREAM_IOCTL_LASTMESSAGE, NULL, TRUE );
writePkiMessage( sessionInfoPtr, protocolInfo, CMPBODY_ERROR );
DEBUG_DUMP_CMP( CTAG_PB_ERROR, 1, sessionInfoPtr );
writePkiDatagram( sessionInfoPtr );
}
/* Set up information needed to perform a client-side transaction */
static int initClientInfo( SESSION_INFO *sessionInfoPtr,
CMP_PROTOCOL_INFO *protocolInfo )
{
int status;
assert( !( sessionInfoPtr->flags & SESSION_ISSERVER ) );
/* Determine what we need to do based on the request type */
protocolInfo->operation = clibReqToReq( sessionInfoPtr->cmpRequestType );
/* If we're using public key-based authentication, set up the key and
user ID information */
if( sessionInfoPtr->cmpRequestType != CRYPT_REQUESTTYPE_PKIBOOT && \
sessionInfoPtr->cmpRequestType != CRYPT_REQUESTTYPE_INITIALISATION && \
!( sessionInfoPtr->cmpRequestType == CRYPT_REQUESTTYPE_REVOCATION && \
sessionInfoPtr->passwordLength > 0 ) )
{
/* If it's an encryption-only key, remember this for later when we
need to authenticate our request messages */
status = krnlSendMessage( sessionInfoPtr->privateKey, IMESSAGE_CHECK,
NULL, MESSAGE_CHECK_PKC_SIGN );
if( cryptStatusError( status ) )
{
/* The private key can't be used for signature creation, use
the alternate authentication key instead */
protocolInfo->authContext = sessionInfoPtr->iAuthOutContext;
protocolInfo->cryptOnlyKey = TRUE;
}
else
/* The private key that we're using is capable of authenticating
requests */
protocolInfo->authContext = sessionInfoPtr->privateKey;
/* If we're not talking to a cryptlib peer, get the user ID. If
it's a standard signed request the authenticating object will be
the private key, however if the private key is an encryption-only
key the message authentication key is a separate object. To
handle this we get the user ID from the signing key rather than
automatically using the private key */
if( !protocolInfo->isCryptlib )
{
RESOURCE_DATA msgData;
BYTE userID[ CRYPT_MAX_HASHSIZE ];
setMessageData( &msgData, userID, CRYPT_MAX_HASHSIZE );
status = krnlSendMessage( protocolInfo->authContext,
IMESSAGE_GETATTRIBUTE_S, &msgData,
CRYPT_CERTINFO_SUBJECTKEYIDENTIFIER );
if( cryptStatusOK( status ) )
status = setProtocolInfo( protocolInfo, userID,
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( sessionInfoPtr->cmpSavedMacContext != CRYPT_ERROR )
{
setProtocolInfo( protocolInfo, NULL, 0, PROTOCOLINFO_SET_TRANSID );
protocolInfo->useMACsend = protocolInfo->useMACreceive = TRUE;
protocolInfo->iMacContext = sessionInfoPtr->cmpSavedMacContext;
sessionInfoPtr->cmpSavedMacContext = CRYPT_ERROR;
return( CRYPT_OK );
}
/* We're using MAC authentication, initialise the protocol info */
if( sessionInfoPtr->flags & SESSION_ISENCODEDUSERID )
{
BYTE decodedValue[ CRYPT_MAX_TEXTSIZE ];
int decodedValueLength;
/* It's a cryptlib-style encoded user ID, decode it into its binary
value */
decodedValueLength = decodePKIUserValue( decodedValue,
sessionInfoPtr->userName,
sessionInfoPtr->userNameLength );
if( cryptStatusError( decodedValueLength ) )
{
assert( NOTREACHED );
retExt( sessionInfoPtr, decodedValueLength,
"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, sessionInfoPtr->userName,
sessionInfoPtr->userNameLength,
PROTOCOLINFO_SET_ALL );
if( cryptStatusError( status ) )
return( status );
/* Set up the MAC context used to authenticate messages */
if( sessionInfoPtr->flags & SESSION_ISENCODEDPW )
{
BYTE decodedValue[ CRYPT_MAX_TEXTSIZE ];
int decodedValueLength;
/* It's a cryptlib-style encoded password, decode it into its binary
value */
decodedValueLength = decodePKIUserValue( decodedValue,
sessionInfoPtr->password,
sessionInfoPtr->passwordLength );
if( cryptStatusError( decodedValueLength ) )
{
assert( NOTREACHED );
retExt( sessionInfoPtr, decodedValueLength,
"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,
sessionInfoPtr->password,
sessionInfoPtr->passwordLength,
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;
NET_CONNECT_INFO connectInfo;
int status;
/* 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( !( sessionInfoPtr->flags & SESSION_ISPNPPKI ) )
{
if( sessionInfoPtr->cmpRequestType == 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( sessionInfoPtr->cmpRequestType != 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_TRANSACTION,
&connectInfo, sessionInfoPtr->errorMessage,
&sessionInfoPtr->errorCode );
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->errorMessage,
&sessionInfoPtr->errorCode );
}
if( cryptStatusError( status ) )
return( status );
if( sessionInfoPtr->flags & SESSION_ISHTTPTRANSPORT )
sioctl( &sessionInfoPtr->stream, STREAM_IOCTL_CONTENTTYPE,
( void * ) protocolInfoPtr->clientContentType,
strlen( protocolInfoPtr->clientContentType ) );
sioctl( &sessionInfoPtr->stream, STREAM_IOCTL_HANDSHAKETIMEOUT, NULL, 0 );
return( CRYPT_OK );
}
/* Shut down a CMP session */
static void shutdownFunction( SESSION_INFO *sessionInfoPtr )
{
/* Clean up CMP-specific objects */
if( sessionInfoPtr->cmpUserInfo != CRYPT_ERROR )
krnlSendNotifier( sessionInfoPtr->cmpUserInfo,
IMESSAGE_DECREFCOUNT );
if( sessionInfoPtr->cmpSavedMacContext != CRYPT_ERROR )
krnlSendNotifier( sessionInfoPtr->cmpSavedMacContext,
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_PROTOCOL_INFO protocolInfo;
int status;
/* 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 */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -