📄 certrev.c
字号:
newElement->attributes = NULL;
newElement->next = NULL;
/* Set the status to 'unknown' by default, this means that any
entries that we can't do anything with automatically get the
correct status associated with them */
newElement->status = CRYPT_OCSPSTATUS_UNKNOWN;
/* Link the new element into the list */
if( *destListHeadPtrPtr == NULL )
*destListHeadPtrPtr = destListCursor = newElement;
else
{
destListCursor->next = newElement;
destListCursor = newElement;
}
}
ENSURES( iterationCount < FAILSAFE_ITERATIONS_MAX );
return( CRYPT_OK );
}
/* Prepare the entries in a revocation list prior to encoding them */
CHECK_RETVAL STDC_NONNULL_ARG( ( 3, 5, 6 ) ) \
int prepareRevocationEntries( INOUT_OPT REVOCATION_INFO *listPtr,
const time_t defaultTime,
OUT_PTR REVOCATION_INFO **errorEntry,
const BOOLEAN isSingleEntry,
OUT_ENUM_OPT( CRYPT_ATTRIBUTE ) \
CRYPT_ATTRIBUTE_TYPE *errorLocus,
OUT_ENUM_OPT( CRYPT_ERRTYPE ) \
CRYPT_ERRTYPE_TYPE *errorType )
{
REVOCATION_INFO *revocationEntry;
const time_t currentTime = ( defaultTime > MIN_TIME_VALUE ) ? \
defaultTime : getApproxTime();
int iterationCount, status;
assert( listPtr == NULL || \
isReadPtr( listPtr, sizeof( REVOCATION_INFO ) ) );
assert( isWritePtr( errorEntry, sizeof( REVOCATION_INFO * ) ) );
assert( isWritePtr( errorLocus, sizeof( CRYPT_ATTRIBUTE_TYPE ) ) );
assert( isWritePtr( errorType, sizeof( CRYPT_ERRTYPE_TYPE ) ) );
/* Clear return value */
*errorEntry = NULL;
/* If the revocation list is empty there's nothing to do */
if( listPtr == NULL )
return( CRYPT_OK );
/* Set the revocation time if this hasn't already been set. If there's a
default time set we use that otherwise we use the current time */
for( revocationEntry = listPtr, iterationCount = 0;
revocationEntry != NULL && iterationCount < FAILSAFE_ITERATIONS_LARGE;
revocationEntry = revocationEntry->next, iterationCount++ )
{
const ATTRIBUTE_LIST *attributeListPtr;
if( revocationEntry->revocationTime <= MIN_TIME_VALUE )
revocationEntry->revocationTime = currentTime;
/* Check whether the certificate was revoked with a reason of
neverValid, which requires special handling of dates because
X.509 doesn't formally define a neverValid reason, assuming that
all CAs are perfect and never issue certificates in error. The
general idea is to set the two to the same value with the
invalidity date (which should be earlier than the revocation date,
at least in a sanely-run CA) taking precedence. A revocation
with this reason code will in general only be issued by the
cryptlib CA (where it's required to handle problems in the CMP
protocol) and this always sets the invalidity date so in almost
all cases we'll be setting the revocation date to the
(CA-specified) invalidity date which is the date of issue of the
certificate being revoked */
attributeListPtr = findAttributeField( revocationEntry->attributes,
CRYPT_CERTINFO_CRLREASON,
CRYPT_ATTRIBUTE_NONE );
if( attributeListPtr != NULL && \
attributeListPtr->intValue == CRYPT_CRLREASON_NEVERVALID )
{
/* The certificate was revoked with the neverValid code, see if
there's an invalidity date present */
attributeListPtr = \
findAttributeField( revocationEntry->attributes,
CRYPT_CERTINFO_INVALIDITYDATE,
CRYPT_ATTRIBUTE_NONE );
if( attributeListPtr == NULL )
{
/* There's no invalidity date present, set it to the same as
the revocation date */
status = addAttributeField( &revocationEntry->attributes,
CRYPT_CERTINFO_INVALIDITYDATE,
CRYPT_ATTRIBUTE_NONE,
&revocationEntry->revocationTime,
sizeof( time_t ), ATTR_FLAG_NONE,
errorLocus, errorType );
if( cryptStatusError( status ) )
{
/* Remember the entry that caused the problem */
*errorEntry = revocationEntry;
return( status );
}
}
else
{
/* There's an invalidity date present, make sure the
revocation date is the same as the invalidity date */
revocationEntry->revocationTime = \
*( time_t * ) attributeListPtr->value;
}
}
/* If we're only processing a single CRL entry rather than an
entire revocation list we're done */
if( isSingleEntry )
break;
}
ENSURES( iterationCount < FAILSAFE_ITERATIONS_MAX );
/* Check the attributes for each entry in a revocation list */
for( revocationEntry = listPtr, iterationCount = 0;
revocationEntry != NULL && iterationCount < FAILSAFE_ITERATIONS_MAX;
revocationEntry = revocationEntry->next, iterationCount++ )
{
if( revocationEntry->attributes != NULL )
{
status = checkAttributes( ATTRIBUTE_CERTIFICATE,
revocationEntry->attributes,
errorLocus, errorType );
if( cryptStatusError( status ) )
{
/* Remember the entry that caused the problem */
*errorEntry = revocationEntry;
return( status );
}
}
/* If we're only processing a single CRL entry rather than an
entire revocation list we're done */
if( isSingleEntry )
break;
}
ENSURES( iterationCount < FAILSAFE_ITERATIONS_MAX );
return( CRYPT_OK );
}
/****************************************************************************
* *
* Read/write CRL Information *
* *
****************************************************************************/
/* Read/write CRL entries:
RevokedCert ::= SEQUENCE {
userCertificate CertificalSerialNumber,
revocationDate UTCTime
extensions Extensions OPTIONAL,
} */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
int sizeofCRLentry( INOUT REVOCATION_INFO *crlEntry )
{
assert( isWritePtr( crlEntry, sizeof( REVOCATION_INFO ) ) );
/* Remember the encoded attribute size for later when we write the
attributes */
crlEntry->attributeSize = sizeofAttributes( crlEntry->attributes );
return( ( int ) sizeofObject( \
sizeofInteger( crlEntry->id, crlEntry->idLength ) + \
sizeofUTCTime() + \
( ( crlEntry->attributeSize > 0 ) ? \
( int ) sizeofObject( crlEntry->attributeSize ) : 0 ) ) );
}
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 3, 4 ) ) \
int readCRLentry( INOUT STREAM *stream,
INOUT_PTR REVOCATION_INFO **listHeadPtrPtr,
OUT_ENUM_OPT( CRYPT_ATTRIBUTE ) \
CRYPT_ATTRIBUTE_TYPE *errorLocus,
OUT_ENUM_OPT( CRYPT_ERRTYPE ) \
CRYPT_ERRTYPE_TYPE *errorType )
{
REVOCATION_INFO *currentEntry;
BYTE serialNumber[ MAX_SERIALNO_SIZE + 8 ];
int serialNumberLength, endPos, length, status;
time_t revocationTime;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( isWritePtr( listHeadPtrPtr, sizeof( REVOCATION_INFO * ) ) );
assert( isWritePtr( errorLocus, sizeof( CRYPT_ATTRIBUTE_TYPE ) ) );
assert( isWritePtr( errorType, sizeof( CRYPT_ERRTYPE_TYPE ) ) );
/* Determine the overall size of the entry */
status = readSequence( stream, &length );
if( cryptStatusError( status ) )
return( status );
endPos = stell( stream ) + length;
/* Read the integer component of the serial number (limited to a sane
length) and the revocation time */
readInteger( stream, serialNumber, MAX_SERIALNO_SIZE,
&serialNumberLength );
status = readUTCTime( stream, &revocationTime );
if( cryptStatusError( status ) )
return( status );
/* Add the entry to the revocation information list. The ID type isn't
quite an issueAndSerialNumber but the checking code eventually
converts it into this form using the supplied issuer certificate DN */
status = addRevocationEntry( listHeadPtrPtr, ¤tEntry,
CRYPT_IKEYID_ISSUERANDSERIALNUMBER,
serialNumber, serialNumberLength,
( endPos > CRL_SORT_LIMIT ) ? TRUE : FALSE );
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
that they're processed as required */
if( stell( stream ) <= endPos - MIN_ATTRIBUTE_SIZE )
{
status = readAttributes( stream, ¤tEntry->attributes,
CRYPT_CERTTYPE_NONE, length,
errorLocus, errorType );
}
return( status );
}
STDC_NONNULL_ARG( ( 1, 2 ) ) \
int writeCRLentry( INOUT STREAM *stream,
const REVOCATION_INFO *crlEntry )
{
const int revocationLength = \
sizeofInteger( crlEntry->id, crlEntry->idLength ) + \
sizeofUTCTime() + \
( ( crlEntry->attributeSize > 0 ) ? \
( int ) sizeofObject( crlEntry->attributeSize ) : 0 );
int status;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( isReadPtr( crlEntry, sizeof( REVOCATION_INFO ) ) );
/* Write the CRL entry */
writeSequence( stream, revocationLength );
writeInteger( stream, crlEntry->id, crlEntry->idLength, DEFAULT_TAG );
status = writeUTCTime( stream, crlEntry->revocationTime, DEFAULT_TAG );
if( cryptStatusError( status ) || crlEntry->attributeSize <= 0 )
return( status );
/* Write the per-entry extensions. Since these are per-entry extensions
we write them as CRYPT_CERTTYPE_NONE rather than CRYPT_CERTTYPE_CRL to
make sure that they're processed as required */
return( writeAttributes( stream, crlEntry->attributes,
CRYPT_CERTTYPE_NONE, crlEntry->attributeSize ) );
}
/****************************************************************************
* *
* Read/write OCSP Information *
* *
****************************************************************************/
/* Read/write an OCSP certificate ID:
CertID ::= CHOICE {
certID SEQUENCE {
hashAlgo AlgorithmIdentifier,
iNameHash OCTET STRING, -- Hash of issuerName
iKeyHash OCTET STRING, -- Hash of issuer SPKI w/o tag+len
serialNo INTEGER
},
certificate [0] EXPLICIT [0] EXPLICIT Certificate,
certIdWithSignature
[1] EXPLICIT SEQUENCE {
iAndS IssuerAndSerialNumber,
tbsCertHash BIT STRING,
certSig SEQUENCE {
sigAlgo AlgorithmIdentifier,
sigVal BIT STRING
}
}
} */
CHECK_RETVAL_RANGE( MAX_ERROR, 1024 ) STDC_NONNULL_ARG( ( 1 ) ) \
static int sizeofOcspID( const REVOCATION_INFO *ocspEntry )
{
assert( isReadPtr( ocspEntry, sizeof( REVOCATION_INFO ) ) );
REQUIRES( ocspEntry->idType == CRYPT_KEYID_NONE );
/* For now we don't try and handle anything except the v1 ID since the
status of v2 is uncertain (it doesn't add anything to v1 except even
more broken IDs) */
return( ocspEntry->idLength );
}
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 3, 5 ) ) \
static int readOcspID( INOUT STREAM *stream,
OUT_ENUM_OPT( CRYPT_KEYID ) CRYPT_KEYID_TYPE *idType,
OUT_BUFFER( idMaxLen, *idLen ) BYTE *id,
IN_LENGTH_SHORT_MIN( 16 ) const int idMaxLen,
OUT_LENGTH_SHORT_Z int *idLen )
{
HASHFUNCTION_ATOMIC hashFunctionAtomic;
void *dataPtr = DUMMY_INIT_PTR;
int length, tag, status;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( isWritePtr( idType, sizeof( CRYPT_KEYID_TYPE ) ) );
assert( isWritePtr( id, idMaxLen ) );
assert( isWritePtr( idLen, sizeof( int ) ) );
REQUIRES( idMaxLen >= 16 && idMaxLen < MAX_INTLENGTH_SHORT );
getHashAtomicParameters( CRYPT_ALGO_SHA1, &hashFunctionAtomic, NULL );
/* Clear return values */
*idType = CRYPT_KEYID_NONE;
memset( id, 0, min( 16, idMaxLen ) );
*idLen = 0;
/* Read the ID */
tag = peekTag( stream );
if( cryptStatusError( tag ) )
return( tag );
switch( tag )
{
case BER_SEQUENCE:
/* We can't really do anything with v1 IDs since the one-way
hashing process destroys any chance of being able to work
with them and the fact that no useful certificate info is
hashed means that we can't use them to identify a cert. As
a result the following ID type will always produce a result
of "unknown" */
*idType = CRYPT_KEYID_NONE;
status = getStreamObjectLength( stream, &length );
if( cryptStatusError( status ) )
return( status );
if( length < 8 )
return( CRYPT_ERROR_UNDERFLOW );
if( length > idMaxLen )
return( CRYPT_ERROR_OVERFLOW );
*idLen = length;
return( sread( stream, id, length ) );
case MAKE_CTAG( CTAG_OI_CERTIFICATE ):
/* Convert the certificate to a certID */
*idType = CRYPT_IKEYID_CERTID;
*idLen = KEYID_SIZE;
readConstructed( stream, NULL, CTAG_OI_CERTIFICATE );
status = readConstructed( stream, &length, 0 );
if( cryptStatusOK( status ) )
status = sMemGetDataBlock( stream, &dataPtr, length );
if( cryptStatusError( status ) )
return( status );
hashFunctionAtomic( id, KEYID_SIZE, dataPtr, length );
return( readUniversal( stream ) );
case MAKE_CTAG( CTAG_OI_CERTIDWITHSIG ):
/* A bizarro ID dreamed up by Denis Pinkas that manages to carry
over all the problems of the v1 ID without being compatible
with it. It's almost as unworkable as the v1 original but we
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -