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

📄 read.c

📁 cryptlib是功能强大的安全工具集。允许开发人员快速在自己的软件中集成加密和认证服务。
💻 C
📖 第 1 页 / 共 3 页
字号:
/****************************************************************************
*																			*
*							Certificate Read Routines						*
*						Copyright Peter Gutmann 1996-2003					*
*																			*
****************************************************************************/

#include <stdlib.h>
#include <string.h>
#if defined( INC_ALL )
  #include "cert.h"
  #include "asn1.h"
  #include "asn1_ext.h"
#elif defined( INC_CHILD )
  #include "cert.h"
  #include "../misc/asn1.h"
  #include "../misc/asn1_ext.h"
#else
  #include "cert/cert.h"
  #include "misc/asn1.h"
  #include "misc/asn1_ext.h"
#endif /* Compiler-specific includes */

/* Prototypes for functions in certext.c */

int fixAttributes( CERT_INFO *certInfoPtr );

/****************************************************************************
*																			*
*							Read Certificate Components						*
*																			*
****************************************************************************/

/* Return from a cert info read after encountering an error, setting the 
   extended error information if the error was caused by invalid data.  
   Although this isn't actually returned to the caller because the cert
   object isn't created, it allows more precise error diagnosis for other 
   routines */

static int certErrorReturn( CERT_INFO *certInfoPtr,
							const CRYPT_ATTRIBUTE_TYPE errorLocus,
							const int status )
	{
	if( status == CRYPT_ERROR_BADDATA || status == CRYPT_ERROR_UNDERFLOW )
		setErrorInfo( certInfoPtr, errorLocus, CRYPT_ERRTYPE_ATTR_VALUE );
	return( status );
	}

/* Read a certificate serial number */

static int readSerialNumber( STREAM *stream, CERT_INFO *certInfoPtr, 
							 const int tag )
	{
	BYTE integer[ MAX_SERIALNO_SIZE ];
	int integerLength, status;

	/* Read the integer component of the serial number */
	status = readIntegerTag( stream, integer, &integerLength, 
							 MAX_SERIALNO_SIZE, tag );
	if( cryptStatusError( status ) )
		return( certErrorReturn( certInfoPtr, CRYPT_CERTINFO_SERIALNUMBER,
								 status ) );

	/* Some certs may have a serial number of zero, which is turned into a
	   zero-length integer by the ASN.1 read code which truncates leading
	   zeroes that are added due to ASN.1 encoding requirements.  If we get 
	   a zero-length integer, we turn it into a single zero byte */
	if( !integerLength )
		{
		integerLength++;
		integer[ 0 ] = 0;
		}

	/* Copy the data across for the caller */
	return( setSerialNumber( certInfoPtr, integer, integerLength ) );
	}

/* Read validity information.  We allow for GeneralizedTime encodings as
   well since these are used in some broken certs */

static int readValidity( STREAM *stream, CERT_INFO *certInfoPtr )
	{
	int status;

	readSequence( stream, NULL );
	if( peekTag( stream ) == BER_TIME_UTC )
		status = readUTCTime( stream, &certInfoPtr->startTime );
	else
		status = readGeneralizedTime( stream, &certInfoPtr->startTime );
	if( cryptStatusError( status ) )
		return( certErrorReturn( certInfoPtr, CRYPT_CERTINFO_VALIDFROM,
								 status ) );
	if( peekTag( stream ) == BER_TIME_UTC )
		status = readUTCTime( stream, &certInfoPtr->endTime );
	else
		status = readGeneralizedTime( stream, &certInfoPtr->endTime );
	if( cryptStatusError( status ) )
		return( certErrorReturn( certInfoPtr, CRYPT_CERTINFO_VALIDTO,
								 status ) );
	return( CRYPT_OK );
	}

static int readCrmfValidity( STREAM *stream, CERT_INFO *certInfoPtr )
	{
	int tag, status;

	status = readConstructed( stream, NULL, CTAG_CF_VALIDITY );
	tag = peekTag( stream );
	if( tag == MAKE_CTAG( 0 ) )
		{
		readConstructed( stream, NULL, 0 );
		if( peekTag( stream ) == BER_TIME_UTC )
			status = readUTCTime( stream, &certInfoPtr->startTime );
		else
			status = readGeneralizedTime( stream, &certInfoPtr->startTime );
		if( cryptStatusError( status ) )
			return( certErrorReturn( certInfoPtr, CRYPT_CERTINFO_VALIDFROM,
									 status ) );
		tag = peekTag( stream );
		}
	if( tag == MAKE_CTAG( 1 ) )
		{
		readConstructed( stream, NULL, 1 );
		if( peekTag( stream ) == BER_TIME_UTC )
			status = readUTCTime( stream, &certInfoPtr->endTime );
		else
			status = readGeneralizedTime( stream, &certInfoPtr->endTime );
		if( cryptStatusError( status ) )
			return( certErrorReturn( certInfoPtr, CRYPT_CERTINFO_VALIDTO,
									 status ) );
		}
	return( status );
	}

/* Read a uniqueID */

static int readUniqueID( STREAM *stream, CERT_INFO *certInfoPtr,
						 const CRYPT_ATTRIBUTE_TYPE type )
	{
	int length, status;

	/* Read the length of the unique ID, allocate room for it, and read it
	   into the cert.  We ignore the tag since we've already checked it via
	   peekTag() before we got here */
	status = readBitStringHole( stream, &length, ANY_TAG );
	if( cryptStatusOK( status ) && ( length < 1 || length > 1024 ) )
		status = CRYPT_ERROR_BADDATA;
	if( cryptStatusOK( status ) )
		{
		void *bufPtr;

		if( ( bufPtr = clDynAlloc( "readUniqueID", length ) ) == NULL )
			return( CRYPT_ERROR_MEMORY );
		if( type == CRYPT_CERTINFO_SUBJECTUNIQUEID )
			{
			certInfoPtr->cCertCert->subjectUniqueID = bufPtr;
			certInfoPtr->cCertCert->subjectUniqueIDlength = length;
			}
		else
			{
			certInfoPtr->cCertCert->issuerUniqueID = bufPtr;
			certInfoPtr->cCertCert->issuerUniqueIDlength = length;
			}
		status = sread( stream, bufPtr, length );
		}
	if( cryptStatusError( status ) )
		return( certErrorReturn( certInfoPtr, type, status ) );
	return( CRYPT_OK );
	}

/* Read DN information and remember the encoded DN data so we can copy it 
   (complete with any encoding errors) to the issuer DN field of anything
   we sign */

static int readSubjectDN( STREAM *stream, CERT_INFO *certInfoPtr )
	{
	int status;

	certInfoPtr->subjectDNptr = sMemBufPtr( stream );
	certInfoPtr->subjectDNsize = stell( stream );
	status = readDN( stream, &certInfoPtr->subjectName );
	certInfoPtr->subjectDNsize = stell( stream ) - certInfoPtr->subjectDNsize;
	if( cryptStatusError( status ) )
		return( certErrorReturn( certInfoPtr, CRYPT_CERTINFO_SUBJECTNAME,
								 status ) );
	return( CRYPT_OK );
	}

static int readIssuerDN( STREAM *stream, CERT_INFO *certInfoPtr )
	{
	int status;

	certInfoPtr->issuerDNptr = sMemBufPtr( stream );
	certInfoPtr->issuerDNsize = stell( stream );
	status = readDN( stream, &certInfoPtr->issuerName );
	certInfoPtr->issuerDNsize = stell( stream ) - certInfoPtr->issuerDNsize;
	if( cryptStatusError( status ) )
		return( certErrorReturn( certInfoPtr, CRYPT_CERTINFO_ISSUERNAME,
								 status ) );
	return( CRYPT_OK );
	}

/* Read public-key information */

static int readPublicKeyInfo( STREAM *stream, CERT_INFO *certInfoPtr )
	{
	int status;

	certInfoPtr->publicKeyInfo = sMemBufPtr( stream );
	certInfoPtr->publicKeyInfoSize = getStreamObjectLength( stream );
	if( certInfoPtr->flags & CERT_FLAG_DATAONLY )
		{
		/* We're doing deferred handling of the public key, skip it for now.
		   Because of weird tagging in things like CRMF objects we have to
		   read the information as a generic hole rather than a normal
		   SEQUENCE.  In addition because readAlgoID() can return non-stream
		   errors (for example an algorithm not-available status) we have to
		   explicitly check the return status rather than relying on it to 
		   be carried along in the stream state */
		readGenericHole( stream, NULL, DEFAULT_TAG );
		status = readAlgoID( stream, &certInfoPtr->publicKeyAlgo );
		if( cryptStatusOK( status ) )
			status = readUniversal( stream );
		}
	else
		{
		status = iCryptReadSubjectPublicKey( stream, 
									&certInfoPtr->iPubkeyContext, FALSE );
		if( cryptStatusOK( status ) )
			status = krnlSendMessage( certInfoPtr->iPubkeyContext, 
									  IMESSAGE_GETATTRIBUTE, 
									  &certInfoPtr->publicKeyAlgo, 
									  CRYPT_CTXINFO_ALGO );
		}
	if( cryptStatusError( status ) )
		return( certErrorReturn( certInfoPtr, 
								 CRYPT_CERTINFO_SUBJECTPUBLICKEYINFO, 
								 status ) );

	return( CRYPT_OK );
	}

/****************************************************************************
*																			*
*							Read a Certificate Object						*
*																			*
****************************************************************************/

/* Read the information in a certificate */

static int readCertInfo( STREAM *stream, CERT_INFO *certInfoPtr )
	{
	int length, endPos, status;

	/* Read the outer SEQUENCE and version number if it's present */
	readSequence( stream, &length );
	endPos = stell( stream ) + length;
	if( peekTag( stream ) == MAKE_CTAG( CTAG_CE_VERSION ) )
		{
		long version;

		readConstructed( stream, NULL, CTAG_CE_VERSION );
		readShortInteger( stream, &version );
		certInfoPtr->version = version + 1;	/* Zero-based */
		}
	else
		certInfoPtr->version = 1;

	/* Read the serial number and signature algorithm information.  The
	   algorithm information was included to avert a somewhat obscure attack 
	   that isn't possible anyway because of the way the signature data is 
	   encoded in PKCS #1 sigs (although it's still possible for some of the 
	   ISO sig.types) so there's no need to record it, however we record it
	   because some higher-level protocols use the hash algorithm in the cert
	   as an implicit indicator of the hash algorithm they'll use */
	status = readSerialNumber( stream, certInfoPtr, DEFAULT_TAG );
	if( cryptStatusOK( status ) )
		status = readAlgoIDex( stream, NULL, 
							   &certInfoPtr->cCertCert->hashAlgo, NULL );
	if( cryptStatusError( status ) )
		return( status );

	/* Read the issuer name, validity information, and subject name */
	status = readIssuerDN( stream, certInfoPtr );
	if( cryptStatusOK( status ) )
		status = readValidity( stream, certInfoPtr );
	if( cryptStatusOK( status ) )
		status = readSubjectDN( stream, certInfoPtr );
	if( cryptStatusError( status ) )
		return( status );

	/* Check to see whether it's a self-signed cert */
	if( certInfoPtr->issuerDNsize == certInfoPtr->subjectDNsize && \
		!memcmp( certInfoPtr->issuerDNptr, certInfoPtr->subjectDNptr,
				 certInfoPtr->subjectDNsize ) )
		certInfoPtr->flags |= CERT_FLAG_SELFSIGNED;

	/* Read the public key information */
	status = readPublicKeyInfo( stream, certInfoPtr );
	if( cryptStatusError( status ) )
		return( status );

	/* Read the issuer and subject unique ID's if there are any present */
	if( peekTag( stream ) == MAKE_CTAG_PRIMITIVE( CTAG_CE_ISSUERUNIQUEID ) )
		{
		status = readUniqueID( stream, certInfoPtr, 
							   CRYPT_CERTINFO_ISSUERUNIQUEID );
		if( cryptStatusError( status ) )
			return( status );
		}
	if( peekTag( stream ) == MAKE_CTAG_PRIMITIVE( CTAG_CE_SUBJECTUNIQUEID ) )
		{
		status = readUniqueID( stream, certInfoPtr, 
							   CRYPT_CERTINFO_SUBJECTUNIQUEID );
		if( cryptStatusError( status ) )
			return( status );
		}

	/* Read the extensions if there are any present.  Because some certs will
	   have broken encoding of lengths, we allow for a bit of slop for
	   software that gets the length encoding wrong by a few bytes */
	if( stell( stream ) <= endPos - MIN_ATTRIBUTE_SIZE )
		{
		status = readAttributes( stream, &certInfoPtr->attributes,
						CRYPT_CERTTYPE_CERTIFICATE, endPos - stell( stream ),
						&certInfoPtr->errorLocus, &certInfoPtr->errorType );
		if( cryptStatusError( status ) )
			return( status );
		}

	/* Fix up any problems in attributes */
	return( fixAttributes( certInfoPtr ) );
	}

/* Read the information in an attribute certificate */

static int readAttributeCertInfo( STREAM *stream, CERT_INFO *certInfoPtr )
	{
	int length, endPos, status;

	/* Read the outer SEQUENCE and version number */
	readSequence( stream, &length );
	endPos = stell( stream ) + length;
	if( peekTag( stream ) == BER_INTEGER )
		{
		long version;

		readShortInteger( stream, &version );
		certInfoPtr->version = version + 1;	/* Zero-based */
		}
	else

⌨️ 快捷键说明

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