Example #1
0
static int readDlpPrivateKey( INOUT STREAM *stream, 
							  INOUT CONTEXT_INFO *contextInfoPtr )
	{
	PKC_INFO *dlpKey = contextInfoPtr->ctxPKC;

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

	REQUIRES( contextInfoPtr->type == CONTEXT_PKC && \
			  ( contextInfoPtr->capabilityInfo->cryptAlgo == CRYPT_ALGO_DH || \
				contextInfoPtr->capabilityInfo->cryptAlgo == CRYPT_ALGO_DSA || \
				contextInfoPtr->capabilityInfo->cryptAlgo == CRYPT_ALGO_ELGAMAL ) );

	/* Read the key components */
	if( peekTag( stream ) == BER_SEQUENCE )
		{
		/* Erroneously written in older code */
		readSequence( stream, NULL );
		return( readBignumTag( stream, &dlpKey->dlpParam_x,
							   DLPPARAM_MIN_X, DLPPARAM_MAX_X, 
							   &dlpKey->dlpParam_p, 0 ) );
		}
	return( readBignum( stream, &dlpKey->dlpParam_x,
						DLPPARAM_MIN_X, DLPPARAM_MAX_X,
						&dlpKey->dlpParam_p ) );
	}
Example #2
0
static int readAVABitstring( INOUT STREAM *stream, 
							 OUT_LENGTH_SHORT_Z int *length, 
							 OUT_TAG_ENCODED_Z int *stringTag )
	{
	long streamPos;
	int bitStringLength, innerTag, innerLength = DUMMY_INIT, status;

	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( isWritePtr( length, sizeof( int ) ) );
	assert( isWritePtr( stringTag, sizeof( int ) ) );

	/* Bitstrings are used for uniqueIdentifiers, however these usually 
	   encapsulate something else:

		BIT STRING {
			IA5String 'xxxxx'
			}

	   so we try and dig one level deeper to find the encapsulated string if 
	   there is one.  This gets a bit complicated because we have to 
	   speculatively try and decode the inner content and if that fails 
	   assume that it's raw bitstring data.  First we read the bitstring 
	   wrapper and remember where the bitstring data starts */
	status = readBitStringHole( stream, &bitStringLength, 2, DEFAULT_TAG );
	if( cryptStatusError( status ) )
		return( status );
	streamPos = stell( stream );

	/* Then we try and read any inner content */
	status = innerTag = peekTag( stream );
	if( !cryptStatusError( status ) )
		status = readGenericHole( stream, &innerLength, 1, innerTag );
	if( !cryptStatusError( status ) && \
		bitStringLength == sizeofObject( innerLength ) )
		{
		/* There was inner content present, treat it as the actual type and 
		   value of the bitstring.  This assumes that the inner content is
		   a string data type, which always seems to be the case (in any 
		   event it's not certain what we should be returning to the user if
		   we find, for example, a SEQUENCE with further encapsulated 
		   content at this point) */
		*stringTag = innerTag;
		*length = innerLength;

		return( CRYPT_OK );
		}

	/* We couldn't identify any (obvious) inner content, it must be raw
	   bitstring data.  Unfortunately we have no idea what format this is
	   in, it could in fact really be raw binary data but never actually 
	   seems to be this, it's usually ASCII text so we mark it as such and 
	   let the string-read routines sort it out */
	sClearError( stream );
	sseek( stream, streamPos );
	*stringTag = BER_STRING_IA5;
	*length = bitStringLength;

	return( CRYPT_OK );
	}
static int readPubkeyAttributes( INOUT STREAM *stream, 
								 INOUT PKCS15_INFO *pkcs15infoPtr,
								 IN_LENGTH const int endPos, 
								 const BOOLEAN isPubKeyObject )
	{
	int usageFlags, status;

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

	REQUIRES( endPos > 0 && endPos > stell( stream ) && \
			  endPos < MAX_INTLENGTH );

	status = readBitString( stream, &usageFlags );		/* Usage flags */
	if( canContinue( stream, status, endPos ) &&		/* Native flag */
		peekTag( stream ) == BER_BOOLEAN )
		status = readUniversal( stream );
	if( canContinue( stream, status, endPos ) &&		/* Access flags */
		peekTag( stream ) == BER_BITSTRING )
		status = readUniversal( stream );
	if( canContinue( stream, status, endPos ) &&		/* Key reference */
		peekTag( stream ) == BER_INTEGER )
		status = readUniversal( stream );
	if( canContinue( stream, status, endPos ) &&		/* Start date */
		peekTag( stream ) == BER_TIME_GENERALIZED )
		status = readGeneralizedTime( stream, &pkcs15infoPtr->validFrom );
	if( canContinue( stream, status, endPos ) &&		/* End date */
		peekTag( stream ) == MAKE_CTAG( CTAG_KA_VALIDTO ) )
		status = readGeneralizedTimeTag( stream, &pkcs15infoPtr->validTo, 
										 CTAG_KA_VALIDTO );
	if( cryptStatusError( status ) )
		return( status );
	if( isPubKeyObject )
		pkcs15infoPtr->pubKeyUsage = usageFlags;
	else
		pkcs15infoPtr->privKeyUsage = usageFlags;

	return( CRYPT_OK );
	}
Example #4
0
static int readAVA( INOUT STREAM *stream, 
					OUT_INT_Z int *type, 
					OUT_LENGTH_SHORT_Z int *length, 
					OUT_TAG_ENCODED_Z int *stringTag )
	{
	const DN_COMPONENT_INFO *dnComponentInfo;
	BYTE oid[ MAX_OID_SIZE + 8 ];
	int oidLength, tag, status;

	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( isWritePtr( type, sizeof( int ) ) );
	assert( isWritePtr( length, sizeof( int ) ) );
	assert( isWritePtr( stringTag, sizeof( int ) ) );

	/* Clear return values */
	*type = 0;
	*length = 0;
	*stringTag = 0;

	/* Read the start of the AVA and determine the type from the 
	   AttributeType field.  If we find something that we don't recognise we 
	   indicate it as a non-component type that can be read or written but 
	   not directly accessed by the user (although it can still be accessed 
	   using the cursor functions) */
	readSequence( stream, NULL );
	status = readEncodedOID( stream, oid, MAX_OID_SIZE, &oidLength, 
							 BER_OBJECT_IDENTIFIER );
	if( cryptStatusError( status ) )
		return( status );
	dnComponentInfo = findDNInfoByOID( oid, oidLength );
	if( dnComponentInfo == NULL )
		{
		/* If we don't recognise the component type at all, skip it */
		status = readUniversal( stream );
		return( cryptStatusError( status ) ? status : OK_SPECIAL );
		}
	*type = dnComponentInfo->type;

	/* We've reached the data value, make sure that it's in order.  When we
	   read the wrapper around the string type with readGenericHole() we have 
	   to allow a minimum length of zero instead of one because of broken 
	   AVAs with zero-length strings */
	tag = peekTag( stream );
	if( cryptStatusError( tag ) )
		return( tag );
	if( tag == BER_BITSTRING )
		return( readAVABitstring( stream, length, stringTag ) );
	*stringTag = tag;
	return( readGenericHole( stream, length, 0, tag ) );
	}
pangoTagType PacketStreamReader::Stream::syncToTag() //scan through chars one by one until the last three look like a tag
{
    peekTag();
    char * buffer = reinterpret_cast<char*>(&_tag);

    buffer[3] = 0;

    do
    {
        buffer[0] = buffer[1];
        buffer[1] = buffer[2];
        buffer[2] = get();
    }
    while (good() && !valid(_tag));

    if (!good())
        _tag = TAG_END;

    return _tag;

}
PacketStreamReader::FrameInfo PacketStreamReader::Stream::peekFrameHeader(const PacketStreamReader& p)
{
    if (_frame)
        return _frame;

    _frame.frame_streampos = tellg();

    if (peekTag() == TAG_SRC_JSON)
    {
        readTag(TAG_SRC_JSON);
        _frame.src = readUINT();
        json::parse(_frame.meta, *this);
    }

    _frame.packet_streampos = tellg();

    readTag(TAG_SRC_PACKET);
    _frame.time = readTimestamp();

    if (_frame)
    {
        if (readUINT() != _frame.src)
            throw std::runtime_error("Frame preceded by metadata for a mismatched source. Stream may be corrupt.");
    }
    else
        _frame.src = readUINT();

    _frame.size = p.Sources()[_frame.src].data_size_bytes;
    if (!_frame.size)
        _frame.size = readUINT();
    _frame.sequence_num = p.GetPacketIndex(_frame.src);

    _tag = TAG_SRC_PACKET;

    return _frame;
}
Example #7
0
   obvious whether this is really a serious problem or not though (apart from
   it being a certificational weakness), a too-short length will result in 
   whatever additional padding is present being skipped by the general ASN1-
   read code, a too-long length will result in an immediate error as the 
   decoder encounters garbage from reading past the TLV that follows */

CHECK_RETVAL_BOOL STDC_NONNULL_ARG( ( 1 ) ) \
static BOOLEAN checkEncapsulation( INOUT STREAM *stream, 
								   IN_LENGTH const int length,
								   const BOOLEAN isBitstring,
								   IN_ENUM_OPT( ASN1_STATE ) \
									const ASN1_STATE state )
	{
	BOOLEAN isEncapsulated = TRUE;
	const long streamPos = stell( stream );
	const int tag = peekTag( stream );
	int innerLength, status;

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

	REQUIRES_B( length > 0 && length < MAX_INTLENGTH );
	REQUIRES_B( state >= STATE_NONE && state < STATE_ERROR );
	REQUIRES_B( streamPos >= 0 && streamPos < MAX_INTLENGTH );

	/* Make sure that the tag is in order */
	if( cryptStatusError( tag ) )
		{
		sClearError( stream );
		sseek( stream, streamPos );
		return( FALSE );
		}
Example #8
0
static int readConfigOption( INOUT STREAM *stream, 
							 IN_HANDLE CRYPT_USER iCryptUser )
	{
	CRYPT_ATTRIBUTE_TYPE attributeType;
	const BUILTIN_OPTION_INFO *builtinOptionInfoPtr;
	MESSAGE_DATA msgData;
	void *dataPtr DUMMY_INIT_PTR;
	long optionCode;
	int value, tag, length, status;

	/* Read the wrapper and option index and map it to the actual option.  
	   If we find an unknown index or one that shouldn't be writeable to 
	   persistent storage, we skip it and continue.  This is done to handle 
	   new options that may have been added after this version of cryptlib 
	   was built (for unknown indices) and because the stored configuration 
	   options are an untrusted source so we have to check for attempts to 
	   feed in bogus values (for non-writeable options) */
	readSequence( stream, NULL );
	status = readShortInteger( stream, &optionCode );
	if( cryptStatusError( status ) )
		return( status );
	if( optionCode < 0 || optionCode > LAST_OPTION_INDEX )
		{
		/* Unknown option, ignore it */
		return( readUniversal( stream ) );
		}
	builtinOptionInfoPtr = getBuiltinOptionInfoByCode( optionCode );
	if( builtinOptionInfoPtr == NULL || \
		builtinOptionInfoPtr->index < 0 || \
		builtinOptionInfoPtr->index > LAST_OPTION_INDEX || \
		builtinOptionInfoPtr->index == CRYPT_UNUSED )
		{
		/* Unknown option, ignore it */
		return( readUniversal( stream ) );
		}
	attributeType = builtinOptionInfoPtr->option;

	/* Read the option value and set the option.  We don't treat a failure 
	   to set the option as a problem since the user probably doesn't want 
	   the entire system to fail because of a bad configuration option, and 
	   in any case we'll fall back to a safe default value */
	status = tag = peekTag( stream );
	if( cryptStatusError( status ) )
		return( status );
	if( tag == BER_BOOLEAN || tag == BER_INTEGER )
		{
		/* It's a numeric value, read the appropriate type and try and set 
		   the option */
		if( tag == BER_BOOLEAN )
			status = readBoolean( stream, &value );
		else
			{
			long integer;

			status = readShortInteger( stream, &integer );
			if( cryptStatusOK( status ) )
				value = ( int ) integer;
			}
		if( cryptStatusError( status ) )
			return( status );
		( void ) krnlSendMessage( iCryptUser, IMESSAGE_SETATTRIBUTE, 
								  &value, attributeType );
		return( CRYPT_OK );
		}

	/* It's a string value, set the option straight from the encoded data */
	status = readGenericHole( stream, &length, 1, BER_STRING_UTF8 );
	if( cryptStatusOK( status ) )
		status = sMemGetDataBlock( stream, &dataPtr, length );
	if( cryptStatusOK( status ) )
		status = sSkip( stream, length, SSKIP_MAX );
	if( cryptStatusError( status ) )
		return( status );
	setMessageData( &msgData, dataPtr, length );
	( void ) krnlSendMessage( iCryptUser, IMESSAGE_SETATTRIBUTE_S, 
							  &msgData, attributeType );

	return( CRYPT_OK );
	}
Example #9
0
static int getObjectInfo( INOUT STREAM *stream, 
						  OUT QUERY_INFO *queryInfo )
	{
	const long startPos = stell( stream );
	long value;
	int tag, length, status;

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

	/* Clear return value */
	memset( queryInfo, 0, sizeof( QUERY_INFO ) );

	/* We always need at least MIN_CRYPT_OBJECTSIZE more bytes to do
	   anything */
	if( sMemDataLeft( stream ) < MIN_CRYPT_OBJECTSIZE )
		return( CRYPT_ERROR_UNDERFLOW );

	/* Get the type, length, and version information */
	status = getStreamObjectLength( stream, &length );
	if( cryptStatusError( status ) )
		return( status );
	queryInfo->formatType = CRYPT_FORMAT_CRYPTLIB;
	queryInfo->size = length;
	tag = peekTag( stream );
	if( cryptStatusError( tag ) )
		return( tag );
	readGenericHole( stream, NULL, 16, tag );
	status = readShortInteger( stream, &value );
	if( cryptStatusError( status ) )
		return( status );
	queryInfo->version = value;
	switch( tag )
		{
		case BER_SEQUENCE:
			/* This could be a signature or a PKC-encrypted key, see what
			   follows */
			switch( value )
				{
				case KEYTRANS_VERSION:
				case KEYTRANS_EX_VERSION:
					queryInfo->type = CRYPT_OBJECT_PKCENCRYPTED_KEY;
					break;

				case SIGNATURE_VERSION:
				case SIGNATURE_EX_VERSION:
					queryInfo->type = CRYPT_OBJECT_SIGNATURE;
					break;

				default:
					return( CRYPT_ERROR_BADDATA );
				}
			if( value == KEYTRANS_VERSION || value == SIGNATURE_VERSION )
				queryInfo->formatType = CRYPT_FORMAT_CMS;
			break;

		case MAKE_CTAG( CTAG_RI_KEYAGREE ):
			/* It's CMS' wierd X9.42-inspired key agreement mechanism, we
			   can't do much with this (mind you neither can anyone else)
			   so we should probably really treat it as a 
			   CRYPT_ERROR_BADDATA if we encounter it rather than just 
			   ignoring it */
			queryInfo->type = CRYPT_OBJECT_NONE;
			DEBUG_DIAG(( "Found keyAgreeRecipientInfo" ));
			assert( DEBUG_WARN );
			break;

		case MAKE_CTAG( CTAG_RI_PWRI ):
			queryInfo->type = CRYPT_OBJECT_ENCRYPTED_KEY;
			break;

		default:
			queryInfo->type = CRYPT_OBJECT_NONE;
			if( tag > MAKE_CTAG( CTAG_RI_PWRI ) && \
				tag <= MAKE_CTAG( CTAG_RI_MAX ) )
				{
				/* This is probably a new RecipientInfo type, skip it */
				DEBUG_DIAG(( "Found unknown RecipientInfo %X", tag ));
				assert( DEBUG_WARN );
				break;
				}
			return( CRYPT_ERROR_BADDATA );
		}

	/* Reset the stream and make sure that all of the data is present */
	sseek( stream, startPos );
	return( sMemDataLeft( stream ) < queryInfo->size ? \
			CRYPT_ERROR_UNDERFLOW : CRYPT_OK );
	}
pangoTagType PacketStreamReader::Stream::readTag()
{
    auto r = peekTag();
    _tag = 0;
    return r;
}
static int readCertAttributes( INOUT STREAM *stream, 
							   INOUT PKCS15_INFO *pkcs15infoPtr,
							   IN_LENGTH const int endPos )
	{
	int length, status = CRYPT_OK;

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

	REQUIRES( endPos > 0 && endPos > stell( stream ) && \
			  endPos < MAX_INTLENGTH );

	if( peekTag( stream ) == BER_BOOLEAN )			/* Authority flag */
		status = readUniversal( stream );
	if( canContinue( stream, status, endPos ) &&	/* Identifier */
		peekTag( stream ) == BER_SEQUENCE )
		status = readUniversal( stream );
	if( canContinue( stream, status, endPos ) &&	/* Thumbprint */
		peekTag( stream ) == MAKE_CTAG( CTAG_CA_DUMMY ) )
		status = readUniversal( stream );
	if( canContinue( stream, status, endPos ) &&	/* Trusted usage */
		peekTag( stream ) == MAKE_CTAG( CTAG_CA_TRUSTED_USAGE ) )
		{
		readConstructed( stream, NULL, CTAG_CA_TRUSTED_USAGE );
		status = readBitString( stream, &pkcs15infoPtr->trustedUsage );
		}
	if( canContinue( stream, status, endPos ) &&	/* Identifiers */
		peekTag( stream ) == MAKE_CTAG( CTAG_CA_IDENTIFIERS ) )
		{
		status = readConstructed( stream, &length, CTAG_CA_IDENTIFIERS );
		if( cryptStatusOK( status ) )
			status = readKeyIdentifiers( stream, pkcs15infoPtr, 
										 stell( stream ) + length );
		}
	if( canContinue( stream, status, endPos ) &&	/* Implicitly trusted */
		peekTag( stream ) == MAKE_CTAG_PRIMITIVE( CTAG_CA_TRUSTED_IMPLICIT ) )
		status = readBooleanTag( stream, &pkcs15infoPtr->implicitTrust,
								 CTAG_CA_TRUSTED_IMPLICIT );
	if( canContinue( stream, status, endPos ) &&	/* Validity */
		peekTag( stream ) == MAKE_CTAG( CTAG_CA_VALIDTO ) )
		{
		/* Due to miscommunication between PKCS #15 and 7816-15 there are 
		   two ways to encode the validity information for certificates, one 
		   based on the format used elsewhere in PKCS #15 (for PKCS #15) and 
		   the other based on the format used in certificates (for 7816-15).  
		   Luckily they can be distinguished by the tagging type */
		readConstructed( stream, NULL, CTAG_CA_VALIDTO );
		readUTCTime( stream, &pkcs15infoPtr->validFrom );
		status = readUTCTime( stream, &pkcs15infoPtr->validTo );
		}
	else
		{
		if( canContinue( stream, status, endPos ) &&	/* Start date */
			peekTag( stream ) == BER_TIME_GENERALIZED )
			status = readGeneralizedTime( stream, &pkcs15infoPtr->validFrom );
		if( canContinue( stream, status, endPos ) &&	/* End date */
			peekTag( stream ) == MAKE_CTAG_PRIMITIVE( CTAG_CA_VALIDTO ) )
			status = readGeneralizedTimeTag( stream, &pkcs15infoPtr->validTo,
											 CTAG_CA_VALIDTO );
		}

	return( status );
	}
Example #12
0
static int readRsaPrivateKey( INOUT STREAM *stream, 
							  INOUT CONTEXT_INFO *contextInfoPtr )
	{
	PKC_INFO *rsaKey = contextInfoPtr->ctxPKC;
	int status;

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

	REQUIRES( contextInfoPtr->type == CONTEXT_PKC && \
			  contextInfoPtr->capabilityInfo->cryptAlgo == CRYPT_ALGO_RSA );

	/* Read the header */
	status = readSequence( stream, NULL );
	if( cryptStatusOK( status ) && \
		peekTag( stream ) == MAKE_CTAG( 0 ) )
		{
		/* Erroneously written in older code */
		status = readConstructed( stream, NULL, 0 );
		}
	if( cryptStatusError( status ) )
		return( status );

	/* Read the key components */
	if( peekTag( stream ) == MAKE_CTAG_PRIMITIVE( 0 ) )
		{
		/* The public components may already have been read when we read a
		   corresponding public key or certificate so we only read them if
		   they're not already present */
		if( BN_is_zero( &rsaKey->rsaParam_n ) && \
			BN_is_zero( &rsaKey->rsaParam_e ) )
			{
			status = readBignumTag( stream, &rsaKey->rsaParam_n, 
									RSAPARAM_MIN_N, RSAPARAM_MAX_N, 
									NULL, 0 );
			if( cryptStatusOK( status ) )
				{
				status = readBignumTag( stream, &rsaKey->rsaParam_e, 
										RSAPARAM_MIN_E, RSAPARAM_MAX_E, 
										&rsaKey->rsaParam_n, 1 );
				}
			}
		else
			{
			/* The key components are already present, skip them */
			REQUIRES( !BN_is_zero( &rsaKey->rsaParam_n ) && \
					  !BN_is_zero( &rsaKey->rsaParam_e ) );
			readUniversal( stream );
			status = readUniversal( stream );
			}
		if( cryptStatusError( status ) )
			return( status );
		}
	if( peekTag( stream ) == MAKE_CTAG_PRIMITIVE( 2 ) )
		{
		/* d isn't used so we skip it */
		status = readUniversal( stream );
		if( cryptStatusError( status ) )
			return( status );
		}
	status = readBignumTag( stream, &rsaKey->rsaParam_p, 
							RSAPARAM_MIN_P, RSAPARAM_MAX_P, 
							&rsaKey->rsaParam_n, 3 );
	if( cryptStatusOK( status ) )
		status = readBignumTag( stream, &rsaKey->rsaParam_q, 
								RSAPARAM_MIN_Q, RSAPARAM_MAX_Q, 
								&rsaKey->rsaParam_n, 4 );
	if( cryptStatusError( status ) )
		return( status );
	if( peekTag( stream ) == MAKE_CTAG_PRIMITIVE( 5 ) )
		{
		status = readBignumTag( stream, &rsaKey->rsaParam_exponent1, 
								RSAPARAM_MIN_EXP1, RSAPARAM_MAX_EXP1, 
								&rsaKey->rsaParam_n, 5 );
		if( cryptStatusOK( status ) )
			status = readBignumTag( stream, &rsaKey->rsaParam_exponent2, 
									RSAPARAM_MIN_EXP2, RSAPARAM_MAX_EXP2, 
									&rsaKey->rsaParam_n, 6 );
		if( cryptStatusOK( status ) )
			status = readBignumTag( stream, &rsaKey->rsaParam_u, 
									RSAPARAM_MIN_U, RSAPARAM_MAX_U, 
									&rsaKey->rsaParam_n, 7 );
		}
	return( status );
	}
Example #13
0
								   const BOOLEAN isBitstring,
								   IN_ENUM_OPT( ASN1_STATE ) \
									const ASN1_STATE state )
	{
	BOOLEAN isEncapsulated = TRUE;
	const long streamPos = stell( stream );
	int tag, innerLength, status;

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

	REQUIRES_B( length > 0 && length < MAX_BUFFER_SIZE );
	REQUIRES_B( state >= ASN1_STATE_NONE && state < ASN1_STATE_ERROR );
	REQUIRES_B( streamPos >= 0 && streamPos < MAX_INTLENGTH );

	/* Make sure that the tag is in order */
	status = tag = peekTag( stream );
	if( cryptStatusError( status ) )
		{
		sClearError( stream );
		sseek( stream, streamPos );
		return( FALSE );
		}

	/* Make sure that there's an encapsulated object present.  This is a 
	   reasonably effective check, but unfortunately this same effectiveness 
	   means that it'll reject nested objects with incorrect lengths.  It's 
	   not really possible to fix this, either there'll be false positives 
	   due to true OCTET/BIT STRINGs that look like they might contain 
	   nested data or there'll be no false positives but nested content 
	   with slightly incorrect encodings will be missed (see the comment at
	   the start for more on this) */
Example #14
0
static int readPkiHeader( INOUT STREAM *stream, 
						  INOUT CMP_PROTOCOL_INFO *protocolInfo,
						  INOUT ERROR_INFO *errorInfo,
						  const BOOLEAN isServerInitialMessage )
	{
	int length, endPos, status;

	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( isWritePtr( protocolInfo, sizeof( CMP_PROTOCOL_INFO ) ) );
	assert( isWritePtr( errorInfo, sizeof( ERROR_INFO ) ) );

	/* Clear per-message state information */
	protocolInfo->userIDchanged = protocolInfo->certIDchanged = \
		protocolInfo->useMACreceive = FALSE;
	protocolInfo->macInfoPos = CRYPT_ERROR;
	protocolInfo->senderDNPtr = NULL;
	protocolInfo->senderDNlength = 0;
	protocolInfo->headerRead = FALSE;

	/* Read the wrapper and skip the static information, which matches what 
	   we sent and is protected by the MAC so there's little point in 
	   looking at it */
	status = readSequence( stream, &length );
	if( cryptStatusError( status ) )
		return( status );
	endPos = stell( stream ) + length;
	readShortInteger( stream, NULL );		/* Version */
	if( !protocolInfo->isCryptlib )
		{
		/* The ID of the key used for integrity protection (or in general
		   the identity of the sender) can be specified either as the sender
		   DN or the senderKID or both, or in some cases even indirectly via
		   the transaction ID.  With no real guidance as to which one to 
		   use, implementors are using any of these options to identify the 
		   key.  Since we need to check that the integrity-protection key 
		   that we're using is correct so that we can report a more 
		   appropriate error than bad signature or bad data, we need to 
		   remember the sender DN for later in case this is the only form of 
		   key identification provided.  Unfortunately since the sender DN 
		   can't uniquely identify a certificate, if this is the only 
		   identifier that we're given then the caller can still get a bad 
		   signature error, yet another one of CMPs many wonderful features */
		status = readConstructed( stream, &protocolInfo->senderDNlength, 4 );
		if( cryptStatusOK( status ) && protocolInfo->senderDNlength > 0 )
			{
			status = sMemGetDataBlock( stream, &protocolInfo->senderDNPtr, 
									   protocolInfo->senderDNlength );
			if( cryptStatusOK( status ) )
				status = readUniversal( stream );
			}
		}
	else
		{
		/* cryptlib includes a proper certID so the whole signer
		   identification mess is avoided and we can ignore the sender DN */
		status = readUniversal( stream );	/* Sender DN */
		}
	if( cryptStatusOK( status ) )
		status = readUniversal( stream );	/* Recipient DN */
	if( peekTag( stream ) == MAKE_CTAG( CTAG_PH_MESSAGETIME ) )
		status = readUniversal( stream );	/* Message time */
	if( cryptStatusError( status ) )
		{
		retExt( CRYPT_ERROR_BADDATA, 
				( CRYPT_ERROR_BADDATA, errorInfo, 
				  "Invalid DN information in PKI header" ) );
		}
	if( peekTag( stream ) != MAKE_CTAG( CTAG_PH_PROTECTIONALGO ) )
		{
		/* The message was sent without integrity protection, report it as
		   a signature error rather than the generic bad data error that
		   we'd get from the following read */
		retExt( CRYPT_ERROR_SIGNATURE,
				( CRYPT_ERROR_SIGNATURE, errorInfo, 
				  "Message was sent without integrity protection" ) );
		}
	status = readProtectionAlgo( stream, protocolInfo );
	if( cryptStatusError( status ) )
		{
		retExt( status,
				( status, errorInfo, 
				  "Invalid integrity protection information in PKI "
				  "header" ) );
		}
	if( peekTag( stream ) == MAKE_CTAG( CTAG_PH_SENDERKID ) )
		{								/* Sender protection keyID */
		status = readUserID( stream, protocolInfo );
		if( cryptStatusError( status ) )
			{
			retExt( status,
					( status, errorInfo, 
					  "Invalid PKI user ID in PKI header" ) );
			}
		}
	else
		{
		/* If we're the server, the client must provide a PKI user ID in the
		   first message unless we got one in an earlier transaction */
		if( isServerInitialMessage && protocolInfo->userIDsize <= 0 )
			{
			retExt( CRYPT_ERROR_BADDATA, 
					( CRYPT_ERROR_BADDATA, errorInfo, 
					  "Missing PKI user ID in PKI header" ) );
			}
		}
	if( peekTag( stream ) == MAKE_CTAG( CTAG_PH_RECIPKID ) )
		readUniversal( stream );			/* Recipient protection keyID */

	/* Record the transaction ID (which is effectively the nonce) or make 
	   sure that it matches the one that we sent.  There's no real need to 
	   do an explicit duplicate check since a replay attempt will be 
	   rejected as a duplicate by the certificate store and the locking 
	   performed at that level makes it a much better place to catch 
	   duplicates, but we do it anyway because it doesn't cost anything and
	   we can catch at least some problems a bit earlier */
	status = readConstructed( stream, NULL, CTAG_PH_TRANSACTIONID );
	if( cryptStatusError( status ) )
		{
		retExt( status, 
				( status, errorInfo, 
				  "Missing transaction ID in PKI header" ) );
		}
	status = readTransactionID( stream, protocolInfo, 
								isServerInitialMessage );
	if( cryptStatusError( status ) )
		{
		protocolInfo->pkiFailInfo = CMPFAILINFO_BADRECIPIENTNONCE;
		retExt( status, 
				( status, errorInfo, 
				  ( status == CRYPT_ERROR_SIGNATURE ) ? \
				  "Returned message transaction ID doesn't match our "
						"transaction ID" : \
				  "Invalid transaction ID in PKI header" ) );
		}

	/* Read the sender nonce, which becomes the new recipient nonce, and skip
	   the recipient nonce if there's one present.  These values may be
	   absent, either because the other side doesn't implement them or
	   because they're not available, for example because it's sending a
	   response to an error that occurred before it could read the nonce from
	   a request.  In any case we don't bother checking the nonce values
	   since the transaction ID serves the same purpose */
	if( stell( stream ) < endPos && \
		peekTag( stream ) == MAKE_CTAG( CTAG_PH_SENDERNONCE ) )
		{
		readConstructed( stream, NULL, CTAG_PH_SENDERNONCE );
		status = readOctetString( stream, protocolInfo->recipNonce,
								  &protocolInfo->recipNonceSize,
								  4, CRYPT_MAX_HASHSIZE );
		if( cryptStatusError( status ) )
			{
			protocolInfo->pkiFailInfo = CMPFAILINFO_BADSENDERNONCE;
			retExt( status,
					( status, errorInfo, 
					  "Invalid sender nonce in PKI header" ) );
			}
		}
	if( stell( stream ) < endPos && \
		peekTag( stream ) == MAKE_CTAG( CTAG_PH_RECIPNONCE ) )
		{
		readConstructed( stream, NULL, CTAG_PH_RECIPNONCE );
		status = readUniversal( stream );
		if( cryptStatusError( status ) )
			{
			protocolInfo->pkiFailInfo = CMPFAILINFO_BADRECIPIENTNONCE;
			retExt( status,
					( status, errorInfo, 
					  "Invalid recipient nonce in PKI header" ) );
			}
		}

	/* Remember that we've successfully read enough of the header 
	   information to generate a response */
	protocolInfo->headerRead = TRUE;

	/* Skip any further junk and process the general information if there is 
	   any */
	if( stell( stream ) < endPos && \
		peekTag( stream ) == MAKE_CTAG( CTAG_PH_FREETEXT ) )
		{
		status = readUniversal( stream );	/* Junk */
		if( cryptStatusError( status ) )
			return( status );
		}
	if( stell( stream ) < endPos && \
		peekTag( stream ) == MAKE_CTAG( CTAG_PH_GENERALINFO ) )
		{
		status = readGeneralInfo( stream, protocolInfo );
		if( cryptStatusError( status ) )
			{
			retExt( status,
					( status, errorInfo, 
					  "Invalid generalInfo information in PKI header" ) );
			}
		}

	return( CRYPT_OK );
	}