📄 cmp_wr.c
字号:
UNUSED( protocolInfo );
/* Find out how big the payload will be */
if( protocolInfo->operation != CTAG_PB_RR )
{
/* If it's an encryption-only key we return the cert in encrypted
form. The client performs POP by decrypting the returned cert */
if( protocolInfo->cryptOnlyKey )
{
void *bufPtr = sMemBufPtr( stream ) + 100;
int bufSize = sMemDataLeft( stream ) - 100;
/* Extract the response data into the session buffer and wrap
it in the standard format using the client's cert. Since the
client doesn't actually have the cert yet (only we have it,
since it's only just been issued), we have to use the S/MIME
v3 format (keys identified by key ID rather than
issuerAndSerialNumber) because the client won't know its
iAndS until it decrypts the cert */
setMessageData( &msgData, bufPtr, bufSize );
status = krnlSendMessage( sessionInfoPtr->iCertResponse,
IMESSAGE_CRT_EXPORT, &msgData,
CRYPT_CERTFORMAT_CERTIFICATE );
if( cryptStatusOK( status ) )
status = envelopeWrap( bufPtr, msgData.length,
bufPtr, &dataLength, bufSize,
CRYPT_FORMAT_CRYPTLIB,
CRYPT_CONTENT_NONE,
sessionInfoPtr->iCertResponse );
if( cryptStatusError( status ) )
return( status );
}
else
{
/* If it's a signature-capable key, return it in standard form */
setMessageData( &msgData, NULL, 0 );
status = krnlSendMessage( sessionInfoPtr->iCertResponse,
IMESSAGE_CRT_EXPORT, &msgData,
CRYPT_CERTFORMAT_CERTIFICATE );
if( cryptStatusError( status ) )
return( status );
dataLength = msgData.length;
}
payloadSize += objSize( sizeofShortInteger( 0 ) ) + \
objSize( objSize( dataLength ) );
}
/* Write the response body wrapper */
writeConstructed( stream, objSize( objSize( objSize( payloadSize ) ) ),
reqToResp( protocolInfo->operation ) );
writeSequence( stream, objSize( objSize( payloadSize ) ) );
/* Write the response. We always write an OK status here because an
error will have been communicated by sending an explicit error
response */
writeSequence( stream, objSize( payloadSize ) );
writeSequence( stream, payloadSize );
if( protocolInfo->operation != CTAG_PB_RR )
{
writeShortInteger( stream, 0, DEFAULT_TAG );
writeSequence( stream, sizeofShortInteger( 0 ) );
}
status = writeShortInteger( stream, PKISTATUS_OK, DEFAULT_TAG );
if( protocolInfo->operation == CTAG_PB_RR )
/* If it's a revocation request, there's no data included in the
response */
return( status );
/* Write the cert data, either as a standard cert or as CMS encrypted
data if the request was for an encryption-only cert */
writeSequence( stream, objSize( dataLength ) );
if( protocolInfo->cryptOnlyKey )
{
BYTE *bufPtr;
assert( startPos + 100 - stell( stream ) > 0 );
writeConstructed( stream, dataLength, CTAG_CK_NEWENCRYPTEDCERT );
bufPtr = sMemBufPtr( stream );
memmove( bufPtr, bufPtr + startPos + 100 - stell( stream ),
dataLength );
return( sSkip( stream, dataLength ) );
}
writeConstructed( stream, dataLength, CTAG_CK_CERT );
return( exportCertToStream( stream, sessionInfoPtr->iCertResponse,
CRYPT_CERTFORMAT_CERTIFICATE ) );
}
/* Write conf body */
static int writeConfBody( STREAM *stream,
const SESSION_INFO *sessionInfoPtr,
const CMP_PROTOCOL_INFO *protocolInfo )
{
RESOURCE_DATA msgData;
BYTE hashBuffer[ CRYPT_MAX_HASHSIZE ];
int length, status;
/* Get the certificate hash */
setMessageData( &msgData, hashBuffer, CRYPT_MAX_HASHSIZE );
status = krnlSendMessage( sessionInfoPtr->iCertResponse,
IMESSAGE_GETATTRIBUTE_S, &msgData,
( protocolInfo->confHashAlgo == CRYPT_ALGO_SHA ) ? \
CRYPT_CERTINFO_FINGERPRINT_SHA : \
CRYPT_CERTINFO_FINGERPRINT_MD5 );
if( cryptStatusError( status ) )
return( status );
length = ( int ) objSize( msgData.length ) + sizeofShortInteger( 0 );
/* Write the confirmation body */
writeConstructed( stream, objSize( objSize( length ) ),
CTAG_PB_CERTCONF );
writeSequence( stream, objSize( length ) );
writeSequence( stream, length );
writeOctetString( stream, hashBuffer, msgData.length, DEFAULT_TAG );
return( writeShortInteger( stream, 0, DEFAULT_TAG ) );
}
/* Write genMsg body */
static int writeGenMsgBody( STREAM *stream,
SESSION_INFO *sessionInfoPtr,
const CMP_PROTOCOL_INFO *protocolInfo )
{
CRYPT_CERTIFICATE iCTL;
RESOURCE_DATA msgData;
int status;
UNUSED( protocolInfo );
/* Get the CTL from the CA object. We recreate this each time rather
than cacheing it in the session to ensure that changes in the trusted
cert set while the session is active get reflected back to the
caller.
In addition to the explicitly trusted certs, we also include the CA
cert(s) in the CTL as implicitly-trusted certs. This is done both
because users often forget to mark them as trusted on the server and
then wonder where their CA certs are on the client, and because these
should inherently be trusted, since the user is about to get their
certs issued by them */
status = krnlSendMessage( sessionInfoPtr->ownerHandle,
IMESSAGE_GETATTRIBUTE, &iCTL,
CRYPT_IATTRIBUTE_CTL );
if( cryptStatusError( status ) )
return( status );
status = krnlSendMessage( iCTL, IMESSAGE_SETATTRIBUTE,
( void * ) &sessionInfoPtr->privateKey,
CRYPT_IATTRIBUTE_CERTCOLLECTION );
if( cryptStatusError( status ) )
return( status );
setMessageData( &msgData, NULL, 0 );
status = krnlSendMessage( iCTL, IMESSAGE_CRT_EXPORT, &msgData,
CRYPT_CERTFORMAT_CERTCHAIN );
if( cryptStatusError( status ) )
{
krnlSendNotifier( iCTL, IMESSAGE_DECREFCOUNT );
return( status );
}
/* Write the response body wrapper. As with the cert ID, we can use the
imprecision of the ASN.1 that CMP is specified in to interpret the
InfoTypeAndValue:
InfoTypeAndValue ::= SEQUENCE {
infoType OBJECT IDENTIFIER,
infoValue ANY DEFINED BY infoType OPTIONAL
}
as:
infoType ::= id-signedData
infoValue ::= [0] EXPLICIT SignedData
which makes it standard CMS data that can be passed directly to the
CMS code */
writeConstructed( stream, objSize( msgData.length ), CTAG_PB_GENP );
writeSequence( stream, msgData.length );
status = exportCertToStream( stream, iCTL, CRYPT_CERTFORMAT_CERTCHAIN );
krnlSendNotifier( iCTL, IMESSAGE_DECREFCOUNT );
return( status );
}
/* Write error body */
static int writeErrorBody( STREAM *stream,
const CMP_PROTOCOL_INFO *protocolInfo )
{
const int length = writePkiStatusInfo( NULL, protocolInfo->status,
protocolInfo->pkiFailInfo );
/* Write the error body. We don't write the error text string because
it reveals too much about the internal operation of the CA, some of
which may aid an attacker */
writeConstructed( stream, objSize( length ), CTAG_PB_ERROR );
writeSequence( stream, length );
return( writePkiStatusInfo( stream, protocolInfo->status,
protocolInfo->pkiFailInfo ) );
}
/****************************************************************************
* *
* Write a PKI Header *
* *
****************************************************************************/
/* Write a PKI header. Fields marked with a * are redundant and are only
sent when we're not sending minimal headers. Fields marked with a + are
only sent in the first message or when not sending minimal headers:
header SEQUENCE {
version INTEGER (2),
*sender [4] EXPLICIT DirectoryName, -- DN of initiator
*recipient [4] EXPLICIT DirectoryName, -- DN of responder
protAlgo [1] EXPLICIT AlgorithmIdentifier,
+protKeyID [2] EXPLICIT OCTET STRING,
transID [4] EXPLICIT OCTET STRING SIZE (16),-- Random/copied from sender
*nonce [5] EXPLICIT OCTET STRING SIZE (16),-- Random
*nonceX [6] EXPLICIT OCTET STRING SIZE (n), -- Copied from sender
generalInfo [8] EXPLICIT SEQUENCE OF Info OPT -- cryptlib-specific info
} */
static int writePkiHeader( STREAM *stream, SESSION_INFO *sessionInfoPtr,
CMP_PROTOCOL_INFO *protocolInfo )
{
CRYPT_HANDLE senderNameObject = \
( sessionInfoPtr->flags & SESSION_ISSERVER ) ? \
sessionInfoPtr->privateKey : \
protocolInfo->cryptOnlyKey ? \
sessionInfoPtr->iAuthOutContext : \
sessionInfoPtr->iCertRequest;
const CRYPT_HANDLE recipNameObject = \
( sessionInfoPtr->flags & SESSION_ISSERVER ) ? \
sessionInfoPtr->iCertResponse : sessionInfoPtr->iAuthInContext;
STREAM nullStream;
RESOURCE_DATA msgData;
#ifdef USE_FULL_HEADERS
const BOOLEAN useFullHeader = TRUE;
#else
const BOOLEAN useFullHeader = !( protocolInfo->isCryptlib || \
protocolInfo->operation == CTAG_PB_GENM );
/* Send a minimal header if the other side is cryptlib or if
we're doing PKIBoot, for which we couldn't send full headers
if we wanted to */
#endif /* USE_MINIMAL_HEADERS */
BOOLEAN sendClibID = FALSE, sendCertID = FALSE;
int senderNameLength = 0, recipNameLength = 0, attributeLength = 0;
int protInfoLength, totalLength, status;
assert( !useFullHeader || protocolInfo->userIDsize > 0 );
krnlSendMessage( sessionInfoPtr->ownerHandle, IMESSAGE_GETATTRIBUTE,
&protocolInfo->hashAlgo, CRYPT_OPTION_ENCR_HASH );
/* Determine how big the sender and recipient info will be. We
shouldn't need to send a recipient name for an ir because it won't
usually be known yet, but various implementations can't handle a zero-
length GeneralName, so we supply it if it's available even though it's
redundant */
if( useFullHeader )
{
/* Get the sender DN info */
setMessageData( &msgData, NULL, 0 );
status = krnlSendMessage( senderNameObject, IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_IATTRIBUTE_SUBJECT );
if( status == CRYPT_ERROR_NOTFOUND && \
!( sessionInfoPtr->flags & SESSION_ISSERVER ) && \
protocolInfo->operation == CTAG_PB_IR )
{
/* If there's no subject DN present and it's the first message
in a client's ir exchange, this isn't an error because the
subject may not know their DN yet (at least that's the
theory, most servers will reject a message with no sender
name) */
if( sessionInfoPtr->iCertResponse == CRYPT_ERROR )
{
senderNameObject = CRYPT_ERROR;
msgData.length = ( int ) sizeofObject( 0 );
status = CRYPT_OK;
}
else
{
/* Try again with the response from the server, which
contains our newly-allocated DN */
senderNameObject = sessionInfoPtr->iCertResponse;
status = krnlSendMessage( senderNameObject,
IMESSAGE_GETATTRIBUTE_S, &msgData,
CRYPT_IATTRIBUTE_SUBJECT );
}
}
if( cryptStatusError( status ) )
return( status );
senderNameLength = msgData.length;
/* Get the recipient DN info */
setMessageData( &msgData, NULL, 0 );
if( recipNameObject != CRYPT_ERROR )
status = krnlSendMessage( recipNameObject,
IMESSAGE_GETATTRIBUTE_S, &msgData,
CRYPT_IATTRIBUTE_SUBJECT );
else
/* If we're sending an error response there may not be any
recipient name information present yet if the error occurred
before the recipient information could be established, and if
this is a MAC-authenticated PKIBoot we don't have the CA's
cert yet so we don't know its DN. To work around this we
send a zero-length DN (this is one of those places where an
optional field is specified as being mandatory, to lend
balance to the places where mandatory fields are specified as
optional) */
msgData.length = ( int ) sizeofObject( 0 );
if( cryptStatusError( status ) )
return( status );
recipNameLength = msgData.length;
}
/* Determine how big the remaining header data will be */
sMemOpen( &nullStream, NULL, 0 );
if( protocolInfo->useMACsend )
writeMacInfo( &nullStream, protocolInfo,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -