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

📄 cryptcrt.c

📁 老外写的加密库cryptlib(版本3.1)
💻 C
📖 第 1 页 / 共 3 页
字号:
/****************************************************************************
*																			*
*					cryptlib Certificate Management Routines				*
*						Copyright Peter Gutmann 1996-2003					*
*																			*
****************************************************************************/

/* "By the power vested in me, I now declare this text string and this bit
	string 'name' and 'key'.  What RSA has joined, let no man put asunder".
											-- Bob Blakley */
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "crypt.h"
#ifdef INC_ALL
  #include "cert.h"
  #include "asn1_rw.h"
  #include "asn1s_rw.h"
#else
  #include "cert/cert.h"
  #include "misc/asn1_rw.h"
  #include "misc/asn1s_rw.h"
#endif /* Compiler-specific includes */

/* The minimum size for an OBJECT IDENTIFIER expressed as ASCII characters */

#define MIN_ASCII_OIDSIZE	7

/* Prototypes for functions in certext.c */

BOOLEAN isValidField( const CRYPT_ATTRIBUTE_TYPE fieldID,
					  const CRYPT_CERTTYPE_TYPE certType );

/****************************************************************************
*																			*
*								Utility Functions							*
*																			*
****************************************************************************/

/* Convert an ASCII OID arc sequence into an encoded OID and back.  We allow
   dots as well as whitespace for arc separators, these are an IETF-ism but
   are in common use */

static long scanValue( char **string, int *length )
	{
	char *strPtr = *string;
	long retVal = -1;
	int count = *length;

	if( count && isDigit( *strPtr ) )
		{
		retVal = *strPtr++ - '0';
		count--;
		}
	while( count && isDigit( *strPtr ) )
		{
		retVal = ( retVal * 10 ) + ( *strPtr++ - '0' );
		count--;
		}
	while( count && ( *strPtr == ' ' || *strPtr == '.' || *strPtr == '\t' ) )
		{
		strPtr++;
		count--;
		}
	if( count && !isDigit( *strPtr ) )
		retVal = -1;
	*string = strPtr;
	*length = count;
	return( retVal );
	}

int textToOID( const char *oid, const int oidLength, BYTE *binaryOID )
	{
	char *oidPtr = ( char * ) oid;
	long value, val2;
	int length = 3, count = oidLength;

	/* Perform some basic checks and make sure that the first two arcs are in
	   order */
	if( oidLength < MIN_ASCII_OIDSIZE || oidLength > CRYPT_MAX_TEXTSIZE )
		return( 0 );
	while( count && ( *oidPtr == ' ' || *oidPtr == '.' || *oidPtr == '\t' ) )
		{
		oidPtr++;	/* Skip leading whitespace */
		count--;
		}
	value = scanValue( &oidPtr, &count );
	val2 = scanValue( &oidPtr, &count );
	if( value < 0 || value > 2 || val2 < 1 || \
		( ( value < 2 && val2 > 39 ) || ( value == 2 && val2 > 175 ) ) )
		return( 0 );
	binaryOID[ 0 ] = 0x06;	/* OBJECT IDENTIFIER tag */
	binaryOID[ 2 ] = ( BYTE )( ( value * 40 ) + val2 );

	/* Convert the remaining arcs */
	while( count )
		{
		BOOLEAN hasHighBits = FALSE;

		/* Scan the next value and write the high octets (if necessary) with
		   flag bits set, followed by the final octet */
		value = scanValue( &oidPtr, &count );
		if( value < 0 )
			break;
		if( value >= 16384 )
			{
			binaryOID[ length++ ] = ( BYTE ) ( 0x80 | ( value >> 14 ) );
			value %= 16384;
			hasHighBits = TRUE;
			}
		if( ( value > 128 ) || hasHighBits )
			{
			binaryOID[ length++ ] = ( BYTE ) ( 0x80 | ( value >> 7 ) );
			value %= 128;
			}
		binaryOID[ length++ ] = ( BYTE ) value;
		if( length >= MAX_OID_SIZE - 2 )
			return( 0 );
		}
	binaryOID[ 1 ] = length - 2;

	return( value == -1 ? 0 : length );
	}

/* Compare a serial number in canonical form to a generic serial number, 
   with special handling for leading-zero truncation.  This one can get a 
   bit tricky because Microsoft fairly consistently encode the serial 
   numbers incorrectly, so we normalise the values to have no leading zero, 
   which is the lowest common denominator */

int compareSerialNumber( const void *canonSerialNumber, 
						 const int canonSerialNumberLength,
						 const void *serialNumber, 
						 const int serialNumberLength )
	{
	const BYTE *canonSerialNumberPtr = canonSerialNumber;
	const BYTE *serialNumberPtr = serialNumber;
	int canonSerialLength = canonSerialNumberLength;
	int serialLength = serialNumberLength;

	/* Internal serial numbers are canonicalised, so all we need to do is
	   strip a possible leading zero */
	if( !canonSerialNumberPtr[ 0 ] )
		{
		canonSerialNumberPtr++;
		canonSerialLength--;
		}
	assert( canonSerialLength == 0 || canonSerialNumberPtr[ 0 ] );

	/* Serial numbers from external sources can be arbitarily strangely 
	   encoded, so we strip leading zeroes until we get to actual data */
	while( serialLength > 0 && !serialNumberPtr[ 0 ] )
		{
		serialNumberPtr++;
		serialLength--;
		}

	/* Finally we've got them in a form where we can compare them */
	if( canonSerialLength != serialLength || \
		memcmp( canonSerialNumberPtr, serialNumberPtr, serialLength ) )
		return( 1 );

	return( 0 );
	}

/* Compare values to data in a certificate */

static int compareCertInfo( CERT_INFO *certInfoPtr, const int compareType,
							const void *messageDataPtr )
	{
	const RESOURCE_DATA *msgData = ( RESOURCE_DATA * ) messageDataPtr;
	int status;

	switch( compareType )
		{
		case MESSAGE_COMPARE_SUBJECT:
			if( msgData->length != certInfoPtr->subjectDNsize || \
				memcmp( msgData->data, certInfoPtr->subjectDNptr,
						certInfoPtr->subjectDNsize ) )
				return( CRYPT_ERROR );
			return( CRYPT_OK );

		case MESSAGE_COMPARE_ISSUERANDSERIALNUMBER:
			{
			STREAM stream;
			const BYTE *dataStart;
			int serialNoLength, length;

			/* Comparing an iAndS can get quite tricky because of assorted 
			   braindamage in encoding methods, so that two dissimilar 
			   iAndSs aren't necessarily supposed to be regarded as non-
			   equal.  First we try a trivial reject check, if that passes 
			   we compare the issuerName and serialNumber with corrections 
			   for common encoding braindamage.  Note that even this 
			   comparison can fail since older versions of the Entegrity 
			   toolkit rewrote T61Strings in certs as PrintableStrings in 
			   recipientInfo, which means that any kind of straight 
			   comparison fails.  We don't bother handling this sort of 
			   thing, and it's likely that most other software won't either 
			   (this situation only occurs when a cert issuerName contains 
			   PrintableString text incorrectly encoded as T61String, which 
			   is rare enough that it required artifically-created certs 
			   just to reproduce the problem).  In addition the trivial 
			   reject check can also fail since in an extreme encoding 
			   braindamage case a BMPString rewritten as a PrintableString 
			   would experience a large enough change in length to fail the 
			   check, but as with the Entegrity problem this is a level of 
			   brokenness up with which we will not put */
			length = ( int ) sizeofObject( \
									certInfoPtr->issuerDNsize + \
									sizeofObject( certInfoPtr->serialNumberLength ) );
			if( length < msgData->length - 2 || \
				length > msgData->length + 2 )
				/* Trivial reject, the lengths are too dissimilar for any 
				   fixup attempts to work */
				return( CRYPT_ERROR );

			/* We got past the trivial reject check, try a more detailed check, 
			   first the issuerName */
			sMemConnect( &stream, msgData->data, msgData->length );
			readSequence( &stream, NULL );
			dataStart = sMemBufPtr( &stream );
			length = getObjectLength( dataStart, msgData->length - 2 );
			status = readUniversal( &stream );
			if( cryptStatusError( status ) || \
				length != certInfoPtr->issuerDNsize || \
				memcmp( dataStart, certInfoPtr->issuerDNptr,
						certInfoPtr->issuerDNsize ) )
				{
				sMemDisconnect( &stream );
				return( CRYPT_ERROR );
				}

			/* Compare the serialNumber */
			readGenericHole( &stream, &serialNoLength, BER_INTEGER );
			dataStart = sMemBufPtr( &stream );
			status = sSkip( &stream, serialNoLength );
			sMemDisconnect( &stream );
			if( cryptStatusError( status ) )
				return( CRYPT_ERROR );
			if( compareSerialNumber( certInfoPtr->serialNumber,
									 certInfoPtr->serialNumberLength,
									 dataStart, serialNoLength ) )
				return( CRYPT_ERROR );

			return( CRYPT_OK );
			}

		case MESSAGE_COMPARE_FINGERPRINT:
			{
			BYTE fingerPrint[ CRYPT_MAX_HASHSIZE ];
			int fingerPrintLength = CRYPT_MAX_HASHSIZE;

			/* If the cert hasn't been signed yet, we can't compare the 
			   fingerprint */
			if( certInfoPtr->certificate == NULL )
				return( CRYPT_ERROR_NOTINITED );
			
			/* Get the cert fingerprint and compare it to what we've been 
			   given */
			status = getCertComponent( certInfoPtr, 
									   CRYPT_CERTINFO_FINGERPRINT_SHA,
									   fingerPrint, &fingerPrintLength );
			if( cryptStatusOK( status ) && \
				( msgData->length != fingerPrintLength || \
				  memcmp( msgData->data, fingerPrint, fingerPrintLength ) ) )
				status = CRYPT_ERROR;
			return( status );
			}

		case MESSAGE_COMPARE_CERTOBJ:
			{
			CERT_INFO *certInfoPtr2;

			status = krnlGetObject( *( ( CRYPT_CERTIFICATE * ) messageDataPtr ), 
									OBJECT_TYPE_CERTIFICATE, 
									( void ** ) &certInfoPtr2,
									CRYPT_ERROR_SIGNALLED );
			if( cryptStatusError( status ) )
				return( status );
			if( certInfoPtr->certificate == NULL || \
				certInfoPtr2->certificate == NULL )
				{
				/* If the cert objects haven't been signed yet, we can't 
				   compare them */
				krnlReleaseObject( certInfoPtr2->objectHandle );
				return( CRYPT_ERROR_NOTINITED );
				}

			/* Compare the encoded certificate data.  This is the same as
			   comparing the fingerprint without requiring any hashing */
			status = ( certInfoPtr->certificateSize == \
								certInfoPtr2->certificateSize && \
					   !memcmp( certInfoPtr->certificate, certInfoPtr2->certificate,
								certInfoPtr->certificateSize ) ) ? \
					 CRYPT_OK : CRYPT_ERROR;
			krnlReleaseObject( certInfoPtr2->objectHandle );
			return( status );
			}
		}

	assert( NOTREACHED );
	return( CRYPT_ERROR );	/* Get rid of compiler warning */
	}

/****************************************************************************
*																			*
*					Internal Certificate/Key Management Functions			*
*																			*
****************************************************************************/

/* Import a certificate blob or cert chain by sending get_next_cert messages 
   to the source object to obtain all the certs in a chain.  Returns the 
   length of the certificate.
   
   This isn't really a direct certificate function since the control flow 
   sequence is:

	import indirect: 
		GETNEXTCERT -> source object
			source object: 
				CREATEOBJECT_INDIRECT -> system device
					system device: createCertificate() 
		GETNEXTCERT -> source object
			source object: 
				CREATEOBJECT_INDIRECT -> system device
					system device: createCertificate() 
		[...]					

   however this seems to be the best place to put the code */

int iCryptImportCertIndirect( CRYPT_CERTIFICATE *iCertificate,
							  const CRYPT_HANDLE iCertSource, 
							  const CRYPT_KEYID_TYPE keyIDtype,
							  const void *keyID, const int keyIDlength,
							  const int options )
	{
	assert( iCertificate != NULL );
	assert( keyIDtype > CRYPT_KEYID_NONE && keyIDtype < CRYPT_KEYID_LAST );
	assert( keyID != NULL && keyIDlength >= 1 );
	assert( ( options & ~KEYMGMT_MASK_CERTOPTIONS ) == 0 );

	/* We're importing a sequence of certs as a chain from a source object, 
	   assemble the collection via the object */
	return( assembleCertChain( iCertificate, iCertSource, keyIDtype, 
							   keyID, keyIDlength, options ) );
	}

/* Read a public key from an X.509 SubjectPublicKeyInfo record, creating the
   context necessary to contain it in the process.  Like the cert import 
   function above, this is another function of no fixed abode that exists
   here because it's the least inappropriate location.
   
   The use of the void * instead of STREAM * is necessary because the STREAM
   type isn't visible at the global level */

int iCryptReadSubjectPublicKey( void *streamPtr, 
								CRYPT_CONTEXT *iPubkeyContext,
								const BOOLEAN deferredLoad )
	{
	CRYPT_ALGO_TYPE cryptAlgo;
	MESSAGE_CREATEOBJECT_INFO createInfo;
	RESOURCE_DATA msgData;
	STREAM *stream = streamPtr;
	void *spkiPtr = sMemBufPtr( stream );
	int length, spkiLength, status;

	assert( isReadPtr( stream, sizeof( STREAM ) ) );
	assert( isWritePtr( iPubkeyContext, sizeof( CRYPT_CONTEXT ) ) );

	/* Read the SubjectPublicKeyInfo header field and create a context to
	   read the public key information into.  Because all sorts of bizarre
	   tagging exists due to things like CRMF, we read the wrapper as a
	   generic hole rather than the more obvious sequence.  The length
	   values (which are also checked in the kernel, we perform the check
	   here to avoid unnecessarily creating a cert object) are only 
	   approximate because there's wrapper data involved, and (for the 
	   maximum length) several of the DLP PKC values are only a fraction 
	   of CRYPT_MAX_PKCSIZE, the rest of the space requirement being 
	   allocated to the wrapper */
	status = readGenericHole( stream, &length, DEFAULT_TAG );
	if( cryptStatusError( status ) )
		return( status );
	spkiLength = ( int ) sizeofObject( length );
	if( spkiLength < 8 + bitsToBytes( MIN_PKCSIZE_BITS ) || \
		spkiLength > CRYPT_MAX_PKCSIZE * 4 || \
		length > sMemDataLeft( stream ) )
		return( CRYPT_ERROR_BADDATA );
	readAlgoID( stream, &cryptAlgo );
	status = readUniversal( stream );
	if( cryptStatusOK( status ) )
		{
		setMessageCreateObjectInfo( &createInfo, cryptAlgo );
		status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
								  IMESSAGE_DEV_CREATEOBJECT, &createInfo, 
								  OBJECT_TYPE_CONTEXT );
		}
	if( cryptStatusError( status ) )
		return( status );

	/* Send the public-key data to the context */
	setMessageData( &msgData, spkiPtr, spkiLength );
	status = krnlSendMessage( createInfo.cryptHandle, 
							  IMESSAGE_SETATTRIBUTE_S, &msgData, 
							  deferredLoad ? \
								CRYPT_IATTRIBUTE_KEY_SPKI_PARTIAL : \
								CRYPT_IATTRIBUTE_KEY_SPKI );

⌨️ 快捷键说明

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