certrd.c

来自「提供了很多种加密算法和CA认证及相关服务如CMP、OCSP等的开发」· C语言 代码 · 共 1,383 行 · 第 1/4 页

C
1,383
字号

	/* Read the integer component of the serial number and the revocation
	   time.  This makes the assumption that the serial number will have
	   a sane length */
	readInteger( stream, serialNumber, &serialNumberLength, 256 );
	status = readUTCTime( stream, &revocationTime );
	if( cryptStatusError( status ) )
		return( status );

	/* Add the entry to the revocation information list */
	status = addRevocationEntry( listHeadPtr, &currentEntry, 
								 CRYPT_CERTINFO_SERIALNUMBER,
								 serialNumber, serialNumberLength );
	if( cryptStatusError( status ) )
		return( status );
	currentEntry->revocationTime = revocationTime;

	/* Read the extensions if there are any present.  Since these are per-
	   entry extensions we read the extensions themselves as 
	   CRYPT_CERTTYPE_NONE rather than CRYPT_CERTTYPE_CRL to make sure 
	   they're processed as required */
	if( stell( stream ) <= endPos - MIN_ATTRIBUTE_SIZE )
		status = readAttributes( stream, &currentEntry->attributes,
						CRYPT_CERTTYPE_NONE, length,
						&certInfoPtr->errorLocus, &certInfoPtr->errorType );

	return( status );
	}

/* Read an OCSP entry, either a request or a response:

	Entry ::= SEQUENCE {				-- Request
		certID			CertID,
		extensions	[0]	EXPLICIT Extensions OPTIONAL
		}

	Entry ::= SEQUENCE {				-- Response
		certID			CertID,
		certStatus		CHOICE { [0] ..., [1] ..., [2] ... }, 
		thisUpdate		GeneralizedTime, 
		nextUpdate	[0]	EXPLICIT GeneralizedTime OPTIONAL, 
		extensions	[1]	EXPLICIT Extensions OPTIONAL 
		} 

	CertID ::=	SEQUENCE {
		hashAlgo		AlgorithmIdentifier,
		iNameHash		OCTET STRING,	-- Hash of issuerName
		iKeyHash		OCTET STRING,	-- Hash of issuer SPKI w/o tag+len
		serialNo		INTEGER
					}
	or	iAndSerial	[0]	EXPLICIT IssuerAndSerialNumber
	or	certificate	[1]	EXPLICIT Certificate
	or	certHash	[2]	EXPLICIT OCTET STRING */

static int readOCSPentry( STREAM *stream, REVOCATION_INFO **listHeadPtr,
						  CERT_INFO *certInfoPtr, const BOOLEAN isRequest )
	{
	HASHFUNCTION hashFunction;
	REVOCATION_INFO *currentEntry;
	BYTE buffer[ CRYPT_MAX_HASHSIZE ];
	int hashSize, endPos, tag, length, crlReason = 0, status;

	getHashParameters( CRYPT_ALGO_SHA, &hashFunction, &hashSize );

	/* Determine the overall size of the entry */
	readSequence( stream, &length );
	endPos = ( int ) stell( stream ) + length;

	/* Read the revocation information */
	tag = status = peekTag( stream );
	if( !cryptStatusError( status ) && tag != BER_SEQUENCE )
		/* v2 certIDs are explicitly tagged */
		status = readGenericHole( stream, &length );
	if( cryptStatusError( status ) )
		return( status );
	switch( tag )
		{
		case BER_SEQUENCE:
			/* We can't really do anything with v1 IDs since the hashing
			   process destroys any chance of being able to work with them
			   and the fact that no useful cert info is hashed means we 
			   can't use them to identify a cert.  There isn't really any 
			   way to indicate that the request version was incorrect so 
			   what we do is generate a fake hash value (which produces an 
			   appropriate response of "unknown") and return it as a v2 
			   response */
			readUniversal( stream );
			getNonce( buffer, KEYID_SIZE );
			break;

		case MAKE_CTAG( OCSP_IDTYPE_ISSUERANDSERIALNUMBER ):
			/* Convert the iAndS to an issuerID */
			hashFunction( NULL, buffer, sMemBufPtr( stream ), length, HASH_ALL );
			status = readUniversal( stream );
			break;
		
		case MAKE_CTAG( OCSP_IDTYPE_CERTIFICATE ):
			/* Convert the cert to a certID */
			hashFunction( NULL, buffer, sMemBufPtr( stream ), length, HASH_ALL );
			status = readUniversal( stream );
			break;
		
		case MAKE_CTAG( OCSP_IDTYPE_CERTHASH ):
			status = readOctetString( stream, buffer, &length, KEYID_SIZE );
			if( cryptStatusOK( status ) && length != KEYID_SIZE )
				status = CRYPT_ERROR_BADDATA;
			break;

		default:
			status = CRYPT_ERROR_BADDATA;
		}
	if( cryptStatusError( status ) )
		return( status );

	/* Add the entry to the revocation information list */
	status = addRevocationEntry( listHeadPtr, &currentEntry, 
								 CRYPT_CERTINFO_FINGERPRINT, 
								 buffer, KEYID_SIZE );
	if( cryptStatusError( status ) )
		return( status );

	/* If it's a response, read the response status information */
	if( !isRequest )
		{
		switch( peekTag( stream ) )
			{
			case MAKE_CTAG_PRIMITIVE( OCSP_STATUS_NOTREVOKED ):
				currentEntry->status = CRYPT_OCSPSTATUS_NOTREVOKED;
				readUniversal( stream );
				break;

			case MAKE_CTAG( OCSP_STATUS_REVOKED ):
				currentEntry->status = CRYPT_OCSPSTATUS_REVOKED;
				readConstructed( stream, NULL, OCSP_STATUS_REVOKED );
				readGeneralizedTime( stream, &currentEntry->revocationTime );
				if( peekTag( stream ) == MAKE_CTAG( 0 ) )
					{
					/* Remember the crlReason for later */
					readConstructed( stream, NULL, 0 );
					readEnumerated( stream, &crlReason );
					}
				break;

			case MAKE_CTAG_PRIMITIVE( OCSP_STATUS_UNKNOWN ):
				currentEntry->status = CRYPT_OCSPSTATUS_UNKNOWN;
				readUniversal( stream );
				break;

			default:
				return( CRYPT_ERROR_BADDATA );
			}
		status = readGeneralizedTime( stream, &certInfoPtr->startTime );
		if( !cryptStatusError( status ) && peekTag( stream ) == MAKE_CTAG( 0 ) )
			{
			readConstructed( stream, NULL, 0 );
			status = readGeneralizedTime( stream, &certInfoPtr->endTime );
			}
		if( cryptStatusError( status ) )
			return( status );
		}

	/* Read the extensions if there are any present.  Since these are per-
	   entry extensions we read the wrapper here and read the extensions
	   themselves as CRYPT_CERTTYPE_NONE rather than CRYPT_CERTTYPE_OCSP to 
	   make sure they're processed as required */
	if( stell( stream ) <= endPos - MIN_ATTRIBUTE_SIZE )
		{
		readConstructed( stream, &length, isRequest ? \
						 CTAG_RQ_EXTENSIONS : CTAG_RP_EXTENSIONS );
		status = readAttributes( stream, &currentEntry->attributes,
						CRYPT_CERTTYPE_NONE, length,
						&certInfoPtr->errorLocus, &certInfoPtr->errorType );
		}

	/* If it's an OCSP response and there's a crlReason present in the 
	   response and none as an extension, add it as an extension (OCSP
	   allows the same information to be specified in two different places,
	   to make it easier we always return it as a crlReason extension,
	   however some implementations return it in both places so we have to
	   make sure we don't try and add it a second time) */
	if( cryptStatusOK( status ) && !isRequest && \
		findAttributeField( currentEntry->attributes, 
				CRYPT_CERTINFO_CRLREASON, CRYPT_ATTRIBUTE_NONE ) == NULL )
		status = addAttributeField( &currentEntry->attributes,
						CRYPT_CERTINFO_CRLREASON, CRYPT_ATTRIBUTE_NONE, 
						&crlReason, CRYPT_UNUSED, ATTR_FLAG_NONE, 
						&certInfoPtr->errorLocus, &certInfoPtr->errorType );

	return( status );
	}

/****************************************************************************
*																			*
*							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, void **serialNumber,
							 int *serialNumberLength, const int tag )
	{
	BYTE integer[ 256 ];
	int integerLength, status;

	/* Read the integer component of the serial number.  This makes the
	   assumption that the serial number will have a sane length, because of
	   ASN.1 integer encoding issues trying to determine the data length
	   before we read it is somewhat complex */
	status = readIntegerTag( stream, integer, &integerLength, 256, tag );
	if( cryptStatusError( status ) )
		return( 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 which are added by the aforementioned ASN.1 encoding
	   constraints.  If we get a zero-length integer, we turn it into a
	   single zero byte */
	if( !integerLength )
		{
		integerLength++;
		*integer = 0;
		}

	/* Copy the data across for the caller */
	if( ( *serialNumber = malloc( integerLength ) ) == NULL )
		return( CRYPT_ERROR_MEMORY );
	memcpy( *serialNumber, integer, integerLength );
	*serialNumberLength = integerLength;
	return( CRYPT_OK );
	}

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

static int readValidity( STREAM *stream, time_t *validityNotBefore,
						 time_t *validityNotAfter,
						 CRYPT_ATTRIBUTE_TYPE *errorLocus )
	{
	int status;

	readSequence( stream, NULL );
	if( peekTag( stream ) == BER_TIME_UTC )
		status = readUTCTime( stream, validityNotBefore );
	else
		status = readGeneralizedTime( stream, validityNotBefore );
	if( cryptStatusError( status ) )
		{
		*errorLocus = CRYPT_CERTINFO_VALIDFROM;
		return( status );
		}
	if( peekTag( stream ) == BER_TIME_UTC )
		status = readUTCTime( stream, validityNotAfter );
	else
		status = readGeneralizedTime( stream, validityNotAfter );
	if( cryptStatusError( status ) )
		{
		*errorLocus = CRYPT_CERTINFO_VALIDTO;
		return( status );
		}
	return( CRYPT_OK );
	}

static int readCRMFValidity( STREAM *stream, time_t *validityNotBefore,
							 time_t *validityNotAfter,
							 CRYPT_ATTRIBUTE_TYPE *errorLocus )
	{
	int tag, 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, validityNotBefore );
		else
			status = readGeneralizedTime( stream, validityNotBefore );
		if( cryptStatusError( status ) )
			{
			*errorLocus = CRYPT_CERTINFO_VALIDFROM;
			return( status );
			}
		tag = peekTag( stream );
		}
	if( tag == MAKE_CTAG( 1 ) )
		{
		readConstructed( stream, NULL, 1 );
		if( peekTag( stream ) == BER_TIME_UTC )
			status = readUTCTime( stream, validityNotAfter );
		else
			status = readGeneralizedTime( stream, validityNotAfter );
		if( cryptStatusError( status ) )
			{
			*errorLocus = CRYPT_CERTINFO_VALIDFROM;
			return( status );
			}
		}
	return( sGetStatus( stream ) );
	}

/* Read a uniqueID */

static int readUniqueID( STREAM *stream, void **buffer, int *bufferSize )
	{
	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( cryptStatusError( status ) )
		return( status );
	if( length < 1 || length > 1024 )
		return( CRYPT_ERROR_BADDATA );
	if( ( *buffer = malloc( length ) ) == NULL )
		return( CRYPT_ERROR_MEMORY );
	*bufferSize = length;
	return( sread( stream, *buffer, length ) );
	}

/* Read DN information and remember the encoded DN data */

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

	certInfoPtr->subjectDNptr = sMemBufPtr( stream );
	certInfoPtr->subjectDNsize = ( int ) stell( stream );
	status = readDN( stream, &certInfoPtr->subjectName );
	certInfoPtr->subjectDNsize = ( int ) stell( stream ) - \

⌨️ 快捷键说明

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