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, ¤tEntry,
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, ¤tEntry->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, ¤tEntry,
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, ¤tEntry->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, ¤tEntry->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( ¤tEntry->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 + -
显示快捷键?