⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cmp_wr.c

📁 cryptlib安全工具包
💻 C
📖 第 1 页 / 共 3 页
字号:
	assert( isReadPtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
	assert( isReadPtr( protocolInfo, sizeof( CMP_PROTOCOL_INFO ) ) );

	/* Find out how big the payload will be.  Since revocation requests are
	   unsigned entities we have to vary the attribute type that we're 
	   reading based on whether we're submitting a signed or unsigned object 
	   in the request */
	setMessageData( &msgData, NULL, 0 );
	status = krnlSendMessage( sessionInfoPtr->iCertRequest,
							  IMESSAGE_CRT_EXPORT, &msgData, certType );
	if( cryptStatusError( status ) )
		return( status );

	/* Write the request body */
	writeConstructed( stream, objSize( msgData.length ),
					  protocolInfo->operation );
	writeSequence( stream, msgData.length );
	return( exportCertToStream( stream, sessionInfoPtr->iCertRequest, 
								certType ) );
	}

/* Write response body.  If we're returning an encryption-only cert we send 
   it as standard CMS data under a new tag to avoid having to hand-assemble 
   the garbled mess that CMP uses for this */

CHECK_RETVAL_BOOL STDC_NONNULL_ARG( ( 1 ) ) \
static int writeResponseBodyHeader( INOUT STREAM *stream, 
									IN_RANGE( CTAG_PB_IR, CTAG_PB_CERTCONF ) \
										const int operationType,
									IN_LENGTH_SHORT_Z const int payloadSize )
	{
	int totalPayloadSize;

	assert( isWritePtr( stream, sizeof( STREAM ) ) );

	REQUIRES( operationType >= CTAG_PB_IR && operationType < CTAG_PB_LAST );
	REQUIRES( payloadSize >= 0 && payloadSize < MAX_INTLENGTH_SHORT );
	
	/* Calculate the overall size of the header and payload.  For an empty
	   response there's only an integer status, for a nonempty response
	   there's also an integer ID */
	totalPayloadSize = payloadSize + sizeofShortInteger( 0 );
	if( operationType != CTAG_PB_RR )
		totalPayloadSize += objSize( sizeofShortInteger( 0 ) );

	/* Write the response body wrapper */
	writeConstructed( stream, objSize( objSize( objSize( totalPayloadSize ) ) ),
					  reqToResp( operationType ) );
	writeSequence( stream, objSize( objSize( totalPayloadSize ) ) );

	/* 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( totalPayloadSize ) );
	writeSequence( stream, totalPayloadSize );
	if( operationType != CTAG_PB_RR )
		{
		writeShortInteger( stream, 0, DEFAULT_TAG );
		writeSequence( stream, sizeofShortInteger( 0 ) );
		}
	return( writeShortInteger( stream, PKISTATUS_OK, DEFAULT_TAG ) );
	}

CHECK_RETVAL_BOOL STDC_NONNULL_ARG( ( 1, 2, 3 ) ) \
static int writeEncryptedResponseBody( INOUT INOUT STREAM *stream,
									   const SESSION_INFO *sessionInfoPtr,
									   const CMP_PROTOCOL_INFO *protocolInfo )
	{
	MESSAGE_DATA msgData;
	void *srcPtr, *destPtr;
	int dataLength, destLength, status;

	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( isReadPtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
	assert( isReadPtr( protocolInfo, sizeof( CMP_PROTOCOL_INFO ) ) );

	/* Get a pointer into the stream buffer.  To avoid having to juggle two
	   buffers we use the stream buffer some distance ahead of the write
	   position as a temporary location to store the encoded certificate for
	   encryption */
	status = sMemGetDataBlockRemaining( stream, &srcPtr, &dataLength );
	if( cryptStatusError( status ) )
		return( status );
	srcPtr = ( BYTE * ) srcPtr + 100;
	dataLength -= 100;
	ENSURES( dataLength >= 1024 && dataLength < sMemDataLeft( stream ) );

	/* 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, srcPtr, dataLength );
	status = krnlSendMessage( sessionInfoPtr->iCertResponse,
							  IMESSAGE_CRT_EXPORT, &msgData,
							  CRYPT_CERTFORMAT_CERTIFICATE );
	if( cryptStatusError( status ) )
		return( status );
	status = envelopeWrap( srcPtr, msgData.length, srcPtr, dataLength, 
						   &dataLength, CRYPT_FORMAT_CRYPTLIB, 
						   CRYPT_CONTENT_NONE, 
						   sessionInfoPtr->iCertResponse );
	if( cryptStatusError( status ) )
		return( status );

	/* Write the response body header */
	status = writeResponseBodyHeader( stream, protocolInfo->operation, 
									  objSize( objSize( dataLength ) ) );
	if( cryptStatusError( status ) )
		return( status );

	/* Write the encrypted certificate.  In theory we could use an swrite()
	   to move the data rather than an memcpy() directly into the buffer but 
	   this is a bit risky because the read position is only about 30-40 
	   bytes ahead of the write position and it's not guaranteed that the 
	   two won't interfere */
	writeSequence( stream, objSize( dataLength ) );
	writeConstructed( stream, dataLength, CTAG_CK_NEWENCRYPTEDCERT );
	status = sMemGetDataBlockRemaining( stream, &destPtr, &destLength );
	if( cryptStatusOK( status ) && dataLength > destLength )
		status = CRYPT_ERROR_OVERFLOW;
	if( cryptStatusError( status ) )
		return( status );
	memmove( destPtr, srcPtr, dataLength );
	return( sSkip( stream, dataLength ) );
	}

CHECK_RETVAL_BOOL STDC_NONNULL_ARG( ( 1, 2, 3 ) ) \
static int writeResponseBody( INOUT STREAM *stream,
							  const SESSION_INFO *sessionInfoPtr,
							  const CMP_PROTOCOL_INFO *protocolInfo )
	{
	MESSAGE_DATA msgData;
	int dataLength = DUMMY_INIT, status;

	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( isReadPtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
	assert( isReadPtr( protocolInfo, sizeof( CMP_PROTOCOL_INFO ) ) );

	/* Revocation request responses have no body */
	if( protocolInfo->operation == CTAG_PB_RR )
		return( writeResponseBodyHeader( stream, protocolInfo->operation, 
										 0 ) );

	/* If it's an encryption-only key we return the certificate in encrypted
	   form, the client performs POP by decrypting the returned cert */
	if( protocolInfo->cryptOnlyKey )
		return( writeEncryptedResponseBody( stream, sessionInfoPtr, 
											protocolInfo ) );

	/* Write the response body header */
	setMessageData( &msgData, NULL, 0 );
	status = krnlSendMessage( sessionInfoPtr->iCertResponse, 
							  IMESSAGE_CRT_EXPORT, &msgData,
							  CRYPT_CERTFORMAT_CERTIFICATE );
	if( cryptStatusOK( status ) )
		{
		dataLength = msgData.length;
		status = writeResponseBodyHeader( stream, protocolInfo->operation, 
										  objSize( objSize( dataLength ) ) );
		}
	if( cryptStatusError( status ) )
		return( status );

	/* Write the certificate data */
	writeSequence( stream, objSize( dataLength ) );
	writeConstructed( stream, dataLength, CTAG_CK_CERT );
	return( exportCertToStream( stream, sessionInfoPtr->iCertResponse, 
								CRYPT_CERTFORMAT_CERTIFICATE ) );
	}

/* Write conf body */

CHECK_RETVAL_BOOL STDC_NONNULL_ARG( ( 1, 2, 3 ) ) \
static int writeConfBody( INOUT STREAM *stream,
						  const SESSION_INFO *sessionInfoPtr,
						  const CMP_PROTOCOL_INFO *protocolInfo )
	{
	MESSAGE_DATA msgData;
	BYTE hashBuffer[ CRYPT_MAX_HASHSIZE + 8 ];
	int length, status;

	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( isReadPtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
	assert( isReadPtr( protocolInfo, sizeof( CMP_PROTOCOL_INFO ) ) );

	/* Get the certificate hash */
	setMessageData( &msgData, hashBuffer, CRYPT_MAX_HASHSIZE );
	status = krnlSendMessage( sessionInfoPtr->iCertResponse,
						IMESSAGE_GETATTRIBUTE_S, &msgData,
						( protocolInfo->confHashAlgo == CRYPT_ALGO_SHA1 ) ? \
							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 */

CHECK_RETVAL_BOOL STDC_NONNULL_ARG( ( 1, 2 ) ) \
static int writeGenMsgBody( INOUT STREAM *stream,
							const SESSION_INFO *sessionInfoPtr )
	{
	CRYPT_CERTIFICATE iCTL;
	MESSAGE_DATA msgData;
	int status;

	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( isReadPtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );

	/* 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 */

CHECK_RETVAL_BOOL STDC_NONNULL_ARG( ( 1, 2 ) ) \
static int writeErrorBody( INOUT STREAM *stream,
						   const CMP_PROTOCOL_INFO *protocolInfo )
	{
	const int length = writePkiStatusInfo( NULL, protocolInfo->status,
										   protocolInfo->pkiFailInfo );

	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( isReadPtr( protocolInfo, sizeof( CMP_PROTOCOL_INFO ) ) );

	/* 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
		} 

   The handling can get a bit complex if we're writing a header in response
   to an error in reading the other side's header.  Since CMP includes such a
   large amount of unnecessary or redundant information, it's not really 
   possible to detect in advance if we've got enough information to send a
   header or not, the best we can do is to require that enough of the header
   fields have been read (indicated by the 'headerRead' flag in the protocol
   info) before we try and create our own header in response */

static int writePkiHeader( STREAM *stream, SESSION_INFO *sessionInfoPtr,
						   CMP_PROTOCOL_INFO *protocolInfo )
	{
	CRYPT_HANDLE senderNameObject = isServer( sessionInfoPtr ) ? \
				sessionInfoPtr->privateKey : \
									protocolInfo->cryptOnlyKey ? \
				sessionInfoPtr->iAuthOutContext : \
				sessionInfoPtr->iCertRequest;
	const CRYPT_HANDLE recipNameObject = isServer( sessionInfoPtr ) ? \
			sessionInfoPtr->iCertResponse : sessionInfoPtr->iAuthInContext;
	STREAM nullStream;
	MESSAGE_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, recipNameLength, attributeLength = 0;
	int protInfoLength, totalLength, status;

	assert( !useFullHeader || !protocolInfo->headerRead || \
			( protocolInfo->userIDsize > 0 ) );
	assert( protocolInfo->transIDsize > 0 );

	krnlSendMessage( sessionInfoPtr->ownerHandle, IMESSAGE_GETATTRIBUTE, 
					 &protocolInfo->hashAlgo, CRYPT_OPTION_ENCR_HASH );

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -