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

📄 asn1objs.c

📁 提供了很多种加密算法和CA认证及相关服务如CMP、OCSP等的开发
💻 C
📖 第 1 页 / 共 2 页
字号:
	writeSequence( stream, ( int ) sizeofObject( recipientKeyInfoSize ) );
	writeSequence( stream, recipientKeyInfoSize );
	writeConstructed( stream, ( int ) sizeofObject( rKeyIDlength ), 0 );
	writeOctetString( stream, rKeyID, rKeyIDlength, DEFAULT_TAG );
	writeOctetString( stream, wrappedKey, wrappedKeyLength, DEFAULT_TAG );

	return( sGetStatus( stream ) );
	}

/* Read a key agreement record */

int readKeyAgreeInfo( STREAM *stream, QUERY_INFO *queryInfo,
					  CRYPT_CONTEXT *iKeyAgreeContext )
	{
	CRYPT_CONTEXT iLocalKeyAgreeContext;
	long value;
	int status;

	/* Clear return values */
	memset( queryInfo, 0, sizeof( QUERY_INFO ) );
	if( iKeyAgreeContext != NULL )
		*iKeyAgreeContext = CRYPT_ERROR;

	/* Read the header and version number */
	readConstructed( stream, NULL, CTAG_RI_KEYAGREE );
	status = readShortInteger( stream, &value );
	if( cryptStatusError( status ) )
		return( status );
	if( value != 3 )
		return( CRYPT_ERROR_BADDATA );

	/* Read the public key information and encryption algorithm information */
	status = readPublicKey( stream, &iLocalKeyAgreeContext, 
							READKEY_OPTION_NONE, DEFAULT_TAG );
	if( cryptStatusError( status ) )
		return( status );

	/* If we're doing a query we're not interested in the key agreement
	   context so we just copy out the information we need and destroy it */
	if( iKeyAgreeContext == NULL )
		{
		RESOURCE_DATA msgData;

		setResourceData( &msgData, queryInfo->keyID, 
						 queryInfo->keyIDlength );
		status = krnlSendMessage( iLocalKeyAgreeContext, 
								  RESOURCE_IMESSAGE_GETATTRIBUTE_S, &msgData, 
								  CRYPT_IATTRIBUTE_KEYID );
		if( cryptStatusOK( status ) )
			status = krnlSendMessage( iLocalKeyAgreeContext, 
									  RESOURCE_IMESSAGE_GETATTRIBUTE, 
									  &queryInfo->cryptAlgo, 
									  CRYPT_CTXINFO_ALGO );
		krnlSendNotifier( iLocalKeyAgreeContext, RESOURCE_IMESSAGE_DECREFCOUNT );
		if( cryptStatusError( status ) )
			return( status );
		}
	else
		/* Make the key agreement context externally visible */
		*iKeyAgreeContext = iLocalKeyAgreeContext;

	return( CRYPT_OK );
	}

/****************************************************************************
*																			*
*								Signature Routines							*
*																			*
****************************************************************************/

/* Write a signature.  The handling of CMS signatures is non-orthogonal to
   readSignature() because creating a CMS signature involves adding assorted 
   additional data like iAndS and signed attributes which present too much 
   information to pass into a basic writeSignature() call */

int writeSignature( STREAM *stream, const CRYPT_CONTEXT iSignContext,
					const CRYPT_ALGO hashAlgo, const CRYPT_ALGO signAlgo, 
					const BYTE *signature, const int signatureLength,
					const SIGNATURE_TYPE signatureType )
	{
	/* If it's an X.509 signature, write the algorithm identifier and
	   signature data wrapped in a BIT STRING.  If it's a raw signature,
	   just write the BIT STRING */
	if( signatureType == SIGNATURE_RAW || signatureType == SIGNATURE_X509 )
		{
		/* Write the hash+signature algorithm identifier if necessary
		   followed by the BIT STRING wrapper */
		if( signatureType == SIGNATURE_X509 )
			writeContextAlgoID( stream, iSignContext, hashAlgo,
								ALGOID_FLAG_ALGOID_ONLY );
		writeTag( stream, BER_BITSTRING );
		writeLength( stream, signatureLength + 1 );
		sputc( stream, 0 );		/* Write bit remainder octet */
		return( writeRawObject( stream, signature, signatureLength ) );
		}

	/* If it's a PGP signature, write the signature in the form expected by 
	   PGP */
	if( signatureType == SIGNATURE_PGP )
		{
		int pgpWriteMPI( STREAM *stream, const BYTE *data, const int length );

		if( isDlpAlgo( signAlgo ) )
			/* We've already specified the DLP output format as PGP so 
			   there's no need for further processing */
			return( swrite( stream, signature, signatureLength ) );
		return( pgpWriteMPI( stream, signature, signatureLength ) );
		}

	/* Write the signature identification information and signature data
	   wrapped as an OCTET STRING */
	if( signatureType == SIGNATURE_CRYPTLIB )
		{
		RESOURCE_DATA msgData;
		BYTE keyID[ CRYPT_MAX_HASHSIZE ];

		/* Get the key ID */
		setResourceData( &msgData, keyID, CRYPT_MAX_HASHSIZE );
		krnlSendMessage( iSignContext, RESOURCE_IMESSAGE_GETATTRIBUTE_S,
						 &msgData, CRYPT_IATTRIBUTE_KEYID );

		/* Write the header */
		writeSequence( stream, sizeofShortInteger( SIGNATURE_EX_VERSION ) +
					   ( int ) sizeofObject( msgData.length ) +
					   sizeofContextAlgoID( iSignContext, CRYPT_ALGO_NONE, \
											ALGOID_FLAG_ALGOID_ONLY ) +
					   sizeofAlgoID( hashAlgo ) +
					   ( int ) sizeofObject( signatureLength ) );

		/* Write the version, key ID and algorithm identifier */
		writeShortInteger( stream, SIGNATURE_EX_VERSION, DEFAULT_TAG );
		writeOctetString( stream, msgData.data, msgData.length, CTAG_SI_SKI );
		writeAlgoID( stream, hashAlgo );
		writeContextAlgoID( stream, iSignContext, CRYPT_ALGO_NONE,
							ALGOID_FLAG_ALGOID_ONLY );
		}
	else
		{
		assert( signatureType == SIGNATURE_CMS );

		/* Write the signature algorithm identifier.  Since full CMS sigs 
		   include signed attributes */
		writeContextAlgoID( stream, iSignContext, CRYPT_ALGO_NONE,
							ALGOID_FLAG_ALGOID_ONLY );
		}
	return( writeOctetString( stream, signature, signatureLength, DEFAULT_TAG ) );
	}

/* Read a signature */

int readSignature( STREAM *stream, QUERY_INFO *queryInfo,
				   const SIGNATURE_TYPE signatureType, 
				   const CRYPT_ALGO signAlgo )
	{
	int length, status;

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

	/* If it's an X.509 signature, it's just a signature+hash algorithm ID.
	   If it's a raw signature it's the same without the algorithm ID */
	if( signatureType == SIGNATURE_RAW || signatureType == SIGNATURE_X509 )
		{
		/* Read the signature/hash algorithm information if necessary 
		   followed by the start of the signature */
		if( signatureType == SIGNATURE_X509 )
			{
			status = readAlgoIDex( stream, &queryInfo->cryptAlgo,
								   &queryInfo->hashAlgo, NULL );
			if( cryptStatusError( status ) )
				return( status );
			}
		status = readBitStringHole( stream, &queryInfo->dataLength, 
									DEFAULT_TAG );
		if( cryptStatusOK( status ) )
			queryInfo->dataStart = sMemBufPtr( stream );
		return( status );
		}

	/* If it's a PGP signature, it's either handled directly or it's an RSA 
	   MPI which only needs to have its length stripped */
	if( signatureType == SIGNATURE_PGP )
		{
		if( isDlpAlgo( signAlgo ) )
			{
			queryInfo->dataStart = sMemBufPtr( stream );
			queryInfo->dataLength = sMemDataLeft( stream );
			}
		else
			{
			assert( signAlgo == CRYPT_ALGO_RSA );

			queryInfo->dataStart = sMemBufPtr( stream ) + 2;
			queryInfo->dataLength = sMemDataLeft( stream ) - 2;
			}
		return( CRYPT_OK );
		}

	/* If it's a CMS signature, read the issuer ID and hash algorithm
	   identifier and skip the authenticated attributes if there are any
	   present after remembering where they start */
	if( signatureType == SIGNATURE_CMS )
		{
		long value;

		/* Read the header */
		readSequence( stream, NULL );
		status = readShortInteger( stream, &value );
		if( cryptStatusOK( status ) && value != SIGNATURE_VERSION )
			status = CRYPT_ERROR_BADDATA;
		if( cryptStatusError( status ) )
			return( status );

		/* Read the issuer and serial number and hash algorithm ID */
		queryInfo->iAndSStart = sMemBufPtr( stream );
		queryInfo->iAndSLength = getObjectLength( queryInfo->iAndSStart, 
												  sMemDataLeft( stream ) );
		readUniversal( stream );
		status = readAlgoID( stream, &queryInfo->hashAlgo );
		if( cryptStatusError( status ) )
			return( status );

		/* Read the authenticated attributes if there are any present */
		if( peekTag( stream ) == MAKE_CTAG( 0 ) )
			{
			queryInfo->attributeStart = sMemBufPtr( stream );
			status = readConstructed( stream, &length, 0 );
			if( cryptStatusError( status ) )
				return( status );
			queryInfo->attributeLength = ( int ) sizeofObject( length );
			sSkip( stream, length );
			}
		}
	else
		/* If it's a cryptlib signature, read the key ID */
		if( signatureType == SIGNATURE_CRYPTLIB )
			{
			long value;

			/* Read the header */
			readSequence( stream, NULL );
			status = readShortInteger( stream, &value );
			if( cryptStatusOK( status ) && value != SIGNATURE_EX_VERSION )
				status = CRYPT_ERROR_BADDATA;
			if( cryptStatusError( status ) )
				return( status );

			/* Read the key ID and hash algorithm identifier */
			readOctetStringTag( stream, queryInfo->keyID, 
								&queryInfo->keyIDlength, CRYPT_MAX_HASHSIZE, 
								MAKE_CTAG_PRIMITIVE( CTAG_SI_SKI ) );
			status = readAlgoID( stream, &queryInfo->hashAlgo );
			if( cryptStatusError( status ) )
				return( status );
			}
		else
			assert( signatureType == SIGNATURE_CMS );

	/* Read the CMS/cryptlib signature algorithm and start of the signature */
	readAlgoID( stream, &queryInfo->cryptAlgo );
	status = readOctetStringHole( stream, &queryInfo->dataLength, 
								  DEFAULT_TAG );
	if( cryptStatusOK( status ) )
		queryInfo->dataStart = sMemBufPtr( stream );
	return( status );
	}

/****************************************************************************
*																			*
*								Object Query Routines						*
*																			*
****************************************************************************/

/* Read the type and start of a cryptlib object */

static int readObjectType( STREAM *stream, CRYPT_OBJECT_TYPE *objectType,
						   int *length, CRYPT_FORMAT_TYPE *formatType )
	{
	const long startPos = stell( stream );
	int tag, status;

	/* Get the type and length information.  We can't use getObjectLength()
	   because the stream will typically have an unknown size (the higher-
	   level routines which call this function don't know the size of the 
	   object they have until the queryObject() call has told them */
	*formatType = CRYPT_FORMAT_CRYPTLIB;
	*objectType = CRYPT_OBJECT_NONE;
	*length = getObjectLength( sMemBufPtr( stream ), 
							   sMemDataLeft( stream ) );
	tag = readTag( stream );
	if( tag == BER_SEQUENCE )
		{
		long value;

		/* This could be a signature or a PKC-encrypted key.  Read the
		   length and see what follows */
		readShortLength( stream );			/* Skip previous length */
		status = readShortInteger( stream, &value );
		if( cryptStatusError( status ) )
			return( status );
		if( value == KEYTRANS_VERSION || value == KEYTRANS_EX_VERSION )
			*objectType = CRYPT_OBJECT_PKCENCRYPTED_KEY;
		else
			if( value == SIGNATURE_VERSION || value == SIGNATURE_EX_VERSION )
				*objectType = CRYPT_OBJECT_SIGNATURE;
			else
				{
				*objectType = CRYPT_OBJECT_NONE;
				return( CRYPT_ERROR_BADDATA );
				}
		if( value == KEYTRANS_VERSION || value == SIGNATURE_VERSION )
			*formatType = CRYPT_FORMAT_CMS;
		}
	else
		{
		switch( tag )
			{
			case MAKE_CTAG( CTAG_RI_KEYAGREE ):
				*objectType = CRYPT_OBJECT_KEYAGREEMENT;
				break;

			case MAKE_CTAG( CTAG_RI_PWRI ):
				*objectType = CRYPT_OBJECT_ENCRYPTED_KEY;
				break;

			default:
				*objectType = 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 */
					break;
				return( CRYPT_ERROR_BADDATA );
			}
		}
	return( sseek( stream, startPos ) );
	}

/* Low-level object query function.  This is used by a number of library
   routines to get information on objects at a lower level than that provided
   by cryptQueryObject() (for example the enveloping functions use it to
   determine whether there is enough data available to allow a full
   cryptQueryObject()).  At this level the stream error code (which is
   independant of the crypt error code returned by the ASN.1 routines) is
   available to provide more information via sGetError().

   Note that this function doens't perform a full check of all the fields in
   an object, all it does is extract enough information from the start to
   satisfy the query, and confirm that there's enough data in the stream to
   contain the rest of the non-payload portion of the object.  The
   appropriate import function checks the validity of the entire object, but
   has side-effects such as creating encryption contexts and/or performing
   signature checks as part of the import function.  It's not really possible
   to check the validity of the octet or bit string which makes up an
   encrypted session key or signature without actually performing the import,
   so once we've read the rest of the header we just make sure the final
   octet or bit string is complete without checking its validity */

int queryObject( STREAM *stream, QUERY_INFO *queryInfo )
	{
	CRYPT_FORMAT_TYPE formatType;
	CRYPT_OBJECT_TYPE objectType;
	int startPos = ( int ) stell( stream ), length, status;

	/* Clear the return value and determine the object type */
	memset( queryInfo, 0, sizeof( QUERY_INFO ) );
	status = readObjectType( stream, &objectType, &length, &formatType );
	if( cryptStatusError( status ) )
		return( status );

	/* Call the appropriate routine to find out more about the object */
	switch( objectType )
		{
		case CRYPT_OBJECT_ENCRYPTED_KEY:
			status = readKEKInfo( stream, queryInfo );
			break;

		case CRYPT_OBJECT_PKCENCRYPTED_KEY:
			status = readKeyTransInfo( stream, queryInfo );
			break;

		case CRYPT_OBJECT_KEYAGREEMENT:
			status = readKeyAgreeInfo( stream, queryInfo, NULL );
			break;

		case CRYPT_OBJECT_SIGNATURE:
			status = readSignature( stream, queryInfo,
							( formatType == CRYPT_FORMAT_CRYPTLIB ) ? \
							SIGNATURE_CRYPTLIB : SIGNATURE_CMS, 
							CRYPT_ALGO_NONE );
			break;

		case CRYPT_OBJECT_NONE:
			/* New, unrecognised RecipientInfo type */
			status = readUniversal( stream );
			break;

		default:
			assert( NOTREACHED );
		}
	if( cryptStatusOK( status ) )
		{
		queryInfo->formatType = formatType;
		queryInfo->type = objectType;
		queryInfo->size = length;
		}

	/* Sometimes there's extra information (such as an encrypted key or
	   signature) which we don't read since it's passed directly to the
	   decrypt function, so if there's any unread data left in the header we
	   seek over it to make sure everything we need is in the buffer.  Since
	   a length-limited stream is used by the enveloping routines, we return
	   an underflow error if the object isn't entirely present */
	if( cryptStatusOK( status ) && \
		length > stell( stream ) - startPos && \
		sSkip( stream, length - ( stell( stream ) - startPos ) ) != CRYPT_OK )
		status = CRYPT_ERROR_UNDERFLOW;

	/* Return to the start of the object in case the caller wants to read it
	   from the stream following the query */
	sseek( stream, startPos );

	return( status );
	}

⌨️ 快捷键说明

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