Ejemplo n.º 1
0
static int writeRequestBody( INOUT STREAM *stream,
							 const SESSION_INFO *sessionInfoPtr,
							 const CMP_PROTOCOL_INFO *protocolInfo )
	{
	const CRYPT_CERTFORMAT_TYPE certType = \
				( protocolInfo->operation == CTAG_PB_RR ) ? \
				CRYPT_ICERTFORMAT_DATA : CRYPT_CERTFORMAT_CERTIFICATE;
	MESSAGE_DATA msgData;
	int status;

	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	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 (via the certType specifier) 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 ) );
	}
Ejemplo n.º 2
0
static int writeKeyDerivationInfo( INOUT STREAM *stream,
								   IN_HANDLE const CRYPT_CONTEXT iCryptContext )
	{
	MESSAGE_DATA msgData;
	BYTE salt[ CRYPT_MAX_HASHSIZE + 8 ];
	int saltLength, keySetupIterations, prfAlgo = DUMMY_INIT;
	int derivationInfoSize, status;

	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	
	REQUIRES( isHandleRangeValid( iCryptContext ) );

	/* Get the key derivation information */
	status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE,
							  &keySetupIterations,
							  CRYPT_CTXINFO_KEYING_ITERATIONS );
	if( cryptStatusOK( status ) )
		status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE,
								  &prfAlgo, CRYPT_CTXINFO_KEYING_ALGO );
	if( cryptStatusError( status ) )
		return( status );
	setMessageData( &msgData, salt, CRYPT_MAX_HASHSIZE );
	status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE_S,
							  &msgData, CRYPT_CTXINFO_KEYING_SALT );
	if( cryptStatusError( status ) )
		return( status );
	saltLength = msgData.length;
	derivationInfoSize = ( int ) sizeofObject( saltLength ) + \
						 sizeofShortInteger( keySetupIterations );
	if( prfAlgo != CRYPT_ALGO_HMAC_SHA1 )
		derivationInfoSize += sizeofAlgoID( prfAlgo );

	/* Write the PBKDF2 information */
	writeConstructed( stream, sizeofOID( OID_PBKDF2 ) +
					  ( int ) sizeofObject( derivationInfoSize ), CTAG_KK_DA );
	writeOID( stream, OID_PBKDF2 );
	writeSequence( stream, derivationInfoSize );
	writeOctetString( stream, salt, saltLength, DEFAULT_TAG );
	status = writeShortInteger( stream, keySetupIterations, DEFAULT_TAG );
	if( prfAlgo != CRYPT_ALGO_HMAC_SHA1 )
		status = writeAlgoID( stream, prfAlgo );
	zeroise( salt, CRYPT_MAX_HASHSIZE );
	return( status );
	}
Ejemplo n.º 3
0
int writeDN( INOUT STREAM *stream, 
			 IN_OPT const DN_PTR *dnComponentList,
			 IN_TAG const int tag )
	{
	DN_COMPONENT *dnComponentPtr;
	int size, iterationCount, status;

	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( dnComponentList == NULL || \
			isReadPtr( dnComponentList, sizeof( DN_COMPONENT ) ) );

	REQUIRES_S( tag == DEFAULT_TAG || ( tag >= 0 && tag < MAX_TAG_VALUE ) );

	/* Special case for empty DNs */
	if( dnComponentList == NULL )
		return( writeConstructed( stream, 0, tag ) );

	status = preEncodeDN( ( DN_COMPONENT * ) dnComponentList, &size );
	if( cryptStatusError( status ) )
		return( status );

	/* Write the DN */
	writeConstructed( stream, size, tag );
	for( dnComponentPtr = ( DN_COMPONENT * ) dnComponentList, \
			iterationCount = 0;
		 dnComponentPtr != NULL && \
			iterationCount < FAILSAFE_ITERATIONS_MED;
		 dnComponentPtr = dnComponentPtr->next, iterationCount++ )
		{
		const DN_COMPONENT_INFO *dnComponentInfo = dnComponentPtr->typeInfo;
		BYTE dnString[ MAX_ATTRIBUTE_SIZE + 8 ];
		int dnStringLength;

		/* Write the RDN wrapper */
		if( dnComponentPtr->encodedRDNdataSize > 0 )
			{
			/* If it's the start of an RDN, write the RDN header */
			writeSet( stream, dnComponentPtr->encodedRDNdataSize );
			}
		writeSequence( stream, dnComponentPtr->encodedAVAdataSize );
		status = swrite( stream, dnComponentInfo->oid, 
						 sizeofOID( dnComponentInfo->oid ) );
		if( cryptStatusError( status ) )
			return( status );

		/* Convert the string to an ASN.1-compatible format and write it
		   out */
		status = copyToAsn1String( dnString, MAX_ATTRIBUTE_SIZE, 
								   &dnStringLength, dnComponentPtr->value,
								   dnComponentPtr->valueLength,
								   dnComponentPtr->valueStringType );
		if( cryptStatusError( status ) )
			return( status );
		if( dnComponentPtr->asn1EncodedStringType == BER_STRING_IA5 && \
			!dnComponentInfo->ia5OK )
			{
			/* If an IA5String isn't allowed in this instance, use a
			   T61String instead */
			dnComponentPtr->asn1EncodedStringType = BER_STRING_T61;
			}
		status = writeCharacterString( stream, dnString, dnStringLength,
									   dnComponentPtr->asn1EncodedStringType );
		if( cryptStatusError( status ) )
			return( status );
		}
	ENSURES( iterationCount < FAILSAFE_ITERATIONS_MED );

	return( CRYPT_OK );
	}
Ejemplo n.º 4
0
static int writePkiHeader( INOUT STREAM *stream,
                           INOUT SESSION_INFO *sessionInfoPtr,
                           INOUT CMP_PROTOCOL_INFO *protocolInfo )
{
    CRYPT_HANDLE senderNameObject = DUMMY_INIT, recipNameObject = DUMMY_INIT;
    STREAM nullStream;
    MESSAGE_DATA msgData;
#ifdef USE_FULL_HEADERS
    const BOOLEAN sendFullHeader = TRUE;
#else
    BOOLEAN sendFullHeader = FALSE;
#endif /* USE_FULL_HEADERS */
    BOOLEAN sendClibID = FALSE, sendCertID = FALSE, sendMacInfo = FALSE;
    BOOLEAN sendUserID = FALSE;
    int senderNameLength, recipNameLength, attributeLength = 0;
    int protInfoLength = DUMMY_INIT, totalLength, hashAlgo, status;

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

    /* Determine which of the many unnecessary and inexplicable bits of the
       CMP header we actually have to send:

    	sendCertID: Sent on the first message where it's required (which
    		isn't necessarily the first message in an exchange, for example
    		it's not used in an ir/ip), either to identify the CA's cert in
    		a CTL sent in a PKIBoot response or to identify the signing
    		certificate when we're using signature-based message
    		authentication.

    	sendClibID: Sent on the first message to tell the other side that
    		this is a cryptlib client/server.

    	sendFullHeader: Sent if the other side isn't running cryptlib, unless
    		we're doing PKIBoot, for which we couldn't send full headers even
    		if we wanted to

    	sendMacInfo: Sent if we're using MAC integrity protection and the
    		the other side isn't running cryptlib, or if this is the first
    		message.

    	sendUserID: Sent on the first message or if we're sending full
    		headers, provided that it's actually available to send */
    if( !( sessionInfoPtr->protocolFlags & CMP_PFLAG_CERTIDSENT ) && \
            ( ( isServer( sessionInfoPtr ) && \
                protocolInfo->operation == CTAG_PB_GENM ) || \
              !protocolInfo->useMACsend ) )
        sendCertID = TRUE;
    if( !( sessionInfoPtr->protocolFlags & CMP_PFLAG_CLIBIDSENT ) )
        sendClibID = TRUE;
#ifndef USE_FULL_HEADERS
    if( !protocolInfo->isCryptlib && \
            protocolInfo->operation != CTAG_PB_GENM )
        sendFullHeader = TRUE;
#endif /* !USE_FULL_HEADERS */
    if( protocolInfo->useMACsend && \
            !( protocolInfo->isCryptlib && \
               ( sessionInfoPtr->protocolFlags & CMP_PFLAG_MACINFOSENT ) ) )
        sendMacInfo = TRUE;
    if( ( sendFullHeader || \
            !( sessionInfoPtr->protocolFlags & CMP_PFLAG_USERIDSENT ) ) && \
            ( protocolInfo->userIDsize > 0 ) )
        sendUserID = TRUE;

    REQUIRES( !sendFullHeader || !protocolInfo->headerRead || \
              ( protocolInfo->userIDsize > 0 && \
                protocolInfo->userIDsize < MAX_INTLENGTH_SHORT ) );
    REQUIRES( protocolInfo->transIDsize > 0 && \
              protocolInfo->transIDsize < MAX_INTLENGTH_SHORT );

    /* Get any other state information that we may need */
    status = krnlSendMessage( sessionInfoPtr->ownerHandle,
                              IMESSAGE_GETATTRIBUTE, &hashAlgo,
                              CRYPT_OPTION_ENCR_HASH );
    ENSURES( cryptStatusOK( status ) );
    protocolInfo->hashAlgo = hashAlgo;	/* int vs.enum */

    /* Determine how big the sender and recipient information 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( sendFullHeader )
    {
        status = initDNInfo( sessionInfoPtr, &senderNameObject,
                             &recipNameObject, &senderNameLength,
                             &recipNameLength,
                             ( protocolInfo->operation == CTAG_PB_IR ) ? \
                             TRUE : FALSE,
                             protocolInfo->cryptOnlyKey );
        if( cryptStatusError( status ) )
            return( status );
    }
    else
    {
        /* We're not using sender or recipient information since it doesn't
           serve any useful purpose, just set the fields to an empty
           SEQUENCE */
        senderNameLength = recipNameLength = sizeofObject( 0 );
    }

    /* Determine how big the remaining header data will be */
    sMemNullOpen( &nullStream );
    if( protocolInfo->useMACsend )
    {
        status = writeMacInfo( &nullStream, protocolInfo, sendMacInfo );
    }
    else
    {
        status = writeContextAlgoID( &nullStream, protocolInfo->authContext,
                                     protocolInfo->hashAlgo );
    }
    if( cryptStatusOK( status ) )
        protInfoLength = stell( &nullStream );
    sMemClose( &nullStream );
    if( cryptStatusError( status ) )
        return( status );
    if( sendClibID )
    {
        attributeLength += sizeofObject( \
                                         sizeofOID( OID_CRYPTLIB_PRESENCECHECK ) + \
                                         sizeofObject( 0 ) );
    }
    if( sendCertID )
    {
        const int certIDsize = sizeofCertID( protocolInfo->authContext );

        ENSURES( certIDsize > 0 && certIDsize < MAX_INTLENGTH_SHORT );

        attributeLength += certIDsize;
    }
    totalLength = sizeofShortInteger( CMP_VERSION ) + \
                  objSize( senderNameLength ) + objSize( recipNameLength ) + \
                  objSize( protInfoLength ) + \
                  objSize( sizeofObject( protocolInfo->transIDsize ) );
    if( sendUserID )
        totalLength += objSize( sizeofObject( protocolInfo->userIDsize ) );
    if( sendFullHeader )
    {
        if( protocolInfo->senderNonceSize > 0 )
            totalLength += objSize( \
                                    sizeofObject( protocolInfo->senderNonceSize ) );
        if( protocolInfo->recipNonceSize > 0 )
            totalLength += objSize( \
                                    sizeofObject( protocolInfo->recipNonceSize ) );
    }
    if( attributeLength > 0 )
        totalLength += objSize( objSize( attributeLength ) );

    /* Perform an early check for data-size problems before we go through
       all of the following code */
    if( sizeofObject( totalLength ) <= 0 || \
            sizeofObject( totalLength ) > sMemDataLeft( stream ) )
        return( CRYPT_ERROR_OVERFLOW );

    /* Write the PKI header wrapper, version information, and sender and
       recipient names if there's name information present */
    writeSequence( stream, totalLength );
    writeShortInteger( stream, CMP_VERSION, DEFAULT_TAG );
    if( sendFullHeader )
    {
        writeConstructed( stream, senderNameLength, 4 );
        if( senderNameObject != CRYPT_ERROR )
        {
            status = exportAttributeToStream( stream, senderNameObject,
                                              CRYPT_IATTRIBUTE_SUBJECT );
            if( cryptStatusError( status ) )
                return( status );
        }
        else
            writeSequence( stream, 0 );
        writeConstructed( stream, recipNameLength, 4 );
        if( recipNameObject != CRYPT_ERROR )
        {
            status = exportAttributeToStream( stream, recipNameObject,
                                              CRYPT_IATTRIBUTE_SUBJECT );
        }
        else
            status = writeSequence( stream, 0 );
    }
    else
    {
        /* This is one of the portions of CMP where an optional field is
           marked as mandatory, to balance out the mandatory fields that are
           marked as optional.  To work around this we write the names as
           zero-length DNs */
        writeConstructed( stream, senderNameLength, 4 );
        writeSequence( stream, 0 );
        writeConstructed( stream, recipNameLength, 4 );
        status = writeSequence( stream, 0 );
    }
    if( cryptStatusError( status ) )
        return( status );

    /* Write the protection information, assorted nonces and IDs, and extra
       information that the other side may be able to make use of */
    writeConstructed( stream, protInfoLength, CTAG_PH_PROTECTIONALGO );
    if( protocolInfo->useMACsend )
    {
        status = writeMacInfo( stream, protocolInfo, sendMacInfo );
        sessionInfoPtr->protocolFlags |= CMP_PFLAG_MACINFOSENT;
    }
    else
    {
        status = writeContextAlgoID( stream, protocolInfo->authContext,
                                     protocolInfo->hashAlgo );
    }
    if( cryptStatusError( status ) )
        return( status );
    if( sendUserID )
    {
        /* We're using full headers or we're the client sending our first
           message, identify the sender key */
        writeConstructed( stream, objSize( protocolInfo->userIDsize ),
                          CTAG_PH_SENDERKID );
        writeOctetString( stream, protocolInfo->userID,
                          protocolInfo->userIDsize, DEFAULT_TAG );
        DEBUG_PRINT(( "%s: Writing userID.\n",
                      protocolInfo->isServer ? "SVR" : "CLI" ));
        DEBUG_DUMP_HEX( protocolInfo->isServer ? "SVR" : "CLI",
                        protocolInfo->userID, protocolInfo->userIDsize );
        sessionInfoPtr->protocolFlags |= CMP_PFLAG_USERIDSENT;
    }
    writeConstructed( stream, objSize( protocolInfo->transIDsize ),
                      CTAG_PH_TRANSACTIONID );
    status = writeOctetString( stream, protocolInfo->transID,
                               protocolInfo->transIDsize, DEFAULT_TAG );
    if( cryptStatusError( status ) )
        return( status );
    if( sendFullHeader )
    {
        if( protocolInfo->senderNonceSize > 0 )
        {
            /* We're using nonces, generate a new sender nonce (the initial
               nonce will have been set when the protocol state was
               initialised) */
            setMessageData( &msgData, protocolInfo->senderNonce,
                            protocolInfo->senderNonceSize );
            krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_GETATTRIBUTE_S,
                             &msgData, CRYPT_IATTRIBUTE_RANDOM_NONCE );
            writeConstructed( stream,
                              objSize( protocolInfo->senderNonceSize ),
                              CTAG_PH_SENDERNONCE );
            status = writeOctetString( stream, protocolInfo->senderNonce,
                                       protocolInfo->senderNonceSize,
                                       DEFAULT_TAG );
        }
        if( protocolInfo->recipNonceSize > 0 )
        {
            writeConstructed( stream,
                              objSize( protocolInfo->recipNonceSize ),
                              CTAG_PH_RECIPNONCE );
            status = writeOctetString( stream, protocolInfo->recipNonce,
                                       protocolInfo->recipNonceSize,
                                       DEFAULT_TAG );
        }
    }
    if( cryptStatusError( status ) )
        return( status );
    if( attributeLength > 0 )
    {
        ENSURES( sendClibID || sendCertID );

        /* We haven't sent any messages yet, let the other side know that
           we're running cryptlib and identify our signing certificate as
           required */
        writeConstructed( stream, objSize( attributeLength ),
                          CTAG_PH_GENERALINFO );
        writeSequence( stream, attributeLength );
        if( sendClibID )
        {
            sessionInfoPtr->protocolFlags |= CMP_PFLAG_CLIBIDSENT;
            writeSequence( stream, sizeofOID( OID_CRYPTLIB_PRESENCECHECK ) + \
                           sizeofObject( 0 ) );
            writeOID( stream, OID_CRYPTLIB_PRESENCECHECK );
            status = writeSet( stream, 0 );
        }
        if( sendCertID )
        {
            sessionInfoPtr->protocolFlags |= CMP_PFLAG_CERTIDSENT;
            status = writeCertID( stream, protocolInfo->authContext );
        }
    }
    return( status );
}