📄 certrev.c
字号:
can convert the iAndS to an issuerID and use that */
*idType = CRYPT_IKEYID_ISSUERID;
*idLen = KEYID_SIZE;
readConstructed( stream, NULL, CTAG_OI_CERTIDWITHSIG );
readSequence( stream, NULL );
status = getStreamObjectLength( stream, &length );
if( cryptStatusOK( status ) )
status = sMemGetDataBlock( stream, &dataPtr, length );
if( cryptStatusError( status ) )
return( status );
hashFunctionAtomic( id, KEYID_SIZE, dataPtr, length );
sSkip( stream, length ); /* issuerAndSerialNumber */
readUniversal( stream ); /* tbsCertificateHash */
return( readUniversal( stream ) ); /* certSignature */
}
return( CRYPT_ERROR_BADDATA );
}
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
static int writeOcspID( INOUT STREAM *stream,
const REVOCATION_INFO *ocspEntry )
{
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( isReadPtr( ocspEntry, sizeof( REVOCATION_INFO ) ) );
return( swrite( stream, ocspEntry->id, ocspEntry->idLength ) );
}
/* Read/write an OCSP request entry:
Entry ::= SEQUENCE { -- Request
certID CertID,
extensions [0] EXPLICIT Extensions OPTIONAL
} */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
int sizeofOcspRequestEntry( INOUT REVOCATION_INFO *ocspEntry )
{
assert( isWritePtr( ocspEntry, sizeof( REVOCATION_INFO ) ) );
REQUIRES( ocspEntry->idType == CRYPT_KEYID_NONE );
/* Remember the encoded attribute size for later when we write the
attributes */
ocspEntry->attributeSize = sizeofAttributes( ocspEntry->attributes );
return( ( int ) \
sizeofObject( sizeofOcspID( ocspEntry ) + \
( ( ocspEntry->attributeSize > 0 ) ? \
( int ) \
sizeofObject( \
sizeofObject( ocspEntry->attributeSize ) ) : 0 ) ) );
}
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 3 ) ) \
int readOcspRequestEntry( INOUT STREAM *stream,
INOUT_PTR REVOCATION_INFO **listHeadPtrPtr,
INOUT CERT_INFO *certInfoPtr )
{
const ATTRIBUTE_LIST *attributeListPtr;
REVOCATION_INFO *currentEntry;
STREAM certIdStream;
BYTE idBuffer[ MAX_ID_SIZE + 8 ];
CRYPT_KEYID_TYPE idType;
int endPos, length, status;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( isWritePtr( listHeadPtrPtr, sizeof( REVOCATION_INFO * ) ) );
assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
/* Determine the overall size of the entry */
status = readSequence( stream, &length );
if( cryptStatusError( status ) )
return( status );
endPos = stell( stream ) + length;
/* Read the ID information */
status = readOcspID( stream, &idType, idBuffer, MAX_ID_SIZE, &length );
if( cryptStatusError( status ) )
return( status );
/* Add the entry to the revocation information list */
status = addRevocationEntry( listHeadPtrPtr, ¤tEntry, idType,
idBuffer, length, FALSE );
if( cryptStatusError( status ) || \
stell( stream ) > endPos - MIN_ATTRIBUTE_SIZE )
return( status );
/* Read the extensions. 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 that
they're processed as required. Note that these are per-request-entry
extensions rather than overall per-request extensions so the tag
is CTAG_OR_SR_EXTENSIONS rather than CTAG_OR_EXTENSIONS */
status = readConstructed( stream, &length, CTAG_OR_SR_EXTENSIONS );
if( cryptStatusOK( status ) )
{
status = readAttributes( stream, ¤tEntry->attributes,
CRYPT_CERTTYPE_NONE, length,
&certInfoPtr->errorLocus,
&certInfoPtr->errorType );
}
if( cryptStatusError( status ) )
return( status );
/* OCSPv1 uses a braindamaged certificate identification method that
breaks the certificate information up into bits and hashes some while
leaving others intact, making it impossible to identify the
certificate from it. To try and fix this, if the request includes an
ESSCertID we use that to make it look like there was a proper ID
present */
if( currentEntry->idType != CRYPT_KEYID_NONE )
return( CRYPT_OK ); /* Proper ID present, we're done */
attributeListPtr = findAttribute( currentEntry->attributes,
CRYPT_CERTINFO_CMS_SIGNINGCERT_ESSCERTID,
TRUE );
if( attributeListPtr == NULL )
return( CRYPT_OK ); /* No ESSCertID present, can't continue */
/* Extract the ID information from the ESSCertID and save it alongside
the OCSP ID which we need to retain for use in the response */
sMemConnect( &certIdStream, attributeListPtr->value,
attributeListPtr->valueLength );
readSequence( &certIdStream, NULL );
status = readOctetString( &certIdStream, idBuffer, &length, KEYID_SIZE,
KEYID_SIZE );
if( cryptStatusOK( status ) )
{
currentEntry->altIdType = CRYPT_IKEYID_CERTID;
memcpy( currentEntry->altID, idBuffer, length );
}
sMemDisconnect( &certIdStream );
return( CRYPT_OK );
}
STDC_NONNULL_ARG( ( 1, 2 ) ) \
int writeOcspRequestEntry( INOUT STREAM *stream,
const REVOCATION_INFO *ocspEntry )
{
const int attributeSize = ( ocspEntry->attributeSize > 0 ) ? \
( int ) sizeofObject( \
sizeofObject( ocspEntry->attributeSize ) ) : 0;
int status;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( isReadPtr( ocspEntry, sizeof( REVOCATION_INFO ) ) );
/* Write the header and ID information */
writeSequence( stream, sizeofOcspID( ocspEntry ) + attributeSize );
status = writeOcspID( stream, ocspEntry );
if( cryptStatusError( status ) || ocspEntry->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_OCSP
to make sure that they're processed as required. Note that these are
per-request-entry extensions rather than overall per-request
extensions so the tag is CTAG_OR_SR_EXTENSIONS rather than
CTAG_OR_EXTENSIONS */
writeConstructed( stream, sizeofObject( ocspEntry->attributeSize ),
CTAG_OR_SR_EXTENSIONS );
return( writeAttributes( stream, ocspEntry->attributes,
CRYPT_CERTTYPE_NONE, ocspEntry->attributeSize ) );
}
/* Read/write an OCSP response entry:
Entry ::= SEQUENCE {
certID CertID,
certStatus CHOICE {
notRevd [0] IMPLICIT NULL,
revd [1] SEQUENCE {
revTime GeneralizedTime,
revReas [0] EXPLICIT CRLReason Optional
},
unknown [2] IMPLICIT NULL
},
thisUpdate GeneralizedTime,
extensions [1] EXPLICIT Extensions OPTIONAL
} */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
int sizeofOcspResponseEntry( INOUT REVOCATION_INFO *ocspEntry )
{
int certStatusSize = 0;
assert( isWritePtr( ocspEntry, sizeof( REVOCATION_INFO ) ) );
/* Remember the encoded attribute size for later when we write the
attributes */
ocspEntry->attributeSize = sizeofAttributes( ocspEntry->attributes );
/* Determine the size of the certificate status field */
certStatusSize = ( ocspEntry->status != CRYPT_OCSPSTATUS_REVOKED ) ? \
sizeofNull() : ( int ) sizeofObject( sizeofGeneralizedTime() );
return( ( int ) \
sizeofObject( sizeofOcspID( ocspEntry ) + \
certStatusSize + sizeofGeneralizedTime() ) + \
( ( ocspEntry->attributeSize > 0 ) ? \
( int ) sizeofObject( ocspEntry->attributeSize ) : 0 ) );
}
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 3 ) ) \
int readOcspResponseEntry( INOUT STREAM *stream,
INOUT_PTR REVOCATION_INFO **listHeadPtrPtr,
INOUT CERT_INFO *certInfoPtr )
{
REVOCATION_INFO *currentEntry;
BYTE idBuffer[ MAX_ID_SIZE + 8 ];
CRYPT_KEYID_TYPE idType;
int endPos, length, crlReason = 0, tag, status;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( isWritePtr( listHeadPtrPtr, sizeof( REVOCATION_INFO * ) ) );
assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
/* Determine the overall size of the entry */
status = readSequence( stream, &length );
if( cryptStatusError( status ) )
return( status );
endPos = stell( stream ) + length;
/* Read the ID information */
status = readOcspID( stream, &idType, idBuffer, MAX_ID_SIZE, &length );
if( cryptStatusError( status ) )
return( status );
/* Add the entry to the revocation information list */
status = addRevocationEntry( listHeadPtrPtr, ¤tEntry, idType,
idBuffer, length, FALSE );
if( cryptStatusError( status ) )
return( status );
/* Read the status information */
status = tag = peekTag( stream );
if( cryptStatusError( status ) )
return( status );
switch( tag )
{
case MAKE_CTAG_PRIMITIVE( OCSP_STATUS_NOTREVOKED ):
currentEntry->status = CRYPT_OCSPSTATUS_NOTREVOKED;
status = readUniversal( stream );
break;
case MAKE_CTAG( OCSP_STATUS_REVOKED ):
currentEntry->status = CRYPT_OCSPSTATUS_REVOKED;
readConstructed( stream, NULL, OCSP_STATUS_REVOKED );
status = readGeneralizedTime( stream,
¤tEntry->revocationTime );
if( cryptStatusOK( status ) && \
peekTag( stream ) == MAKE_CTAG( 0 ) )
{
/* Remember the crlReason for later */
readConstructed( stream, NULL, 0 );
status = readEnumerated( stream, &crlReason );
}
break;
case MAKE_CTAG_PRIMITIVE( OCSP_STATUS_UNKNOWN ):
currentEntry->status = CRYPT_OCSPSTATUS_UNKNOWN;
status = readUniversal( stream );
break;
default:
return( CRYPT_ERROR_BADDATA );
}
if( cryptStatusError( status ) )
return( status );
status = readGeneralizedTime( stream, &certInfoPtr->startTime );
if( cryptStatusOK( 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 that they're processed as required */
if( stell( stream ) <= endPos - MIN_ATTRIBUTE_SIZE )
{
status = readConstructed( stream, &length, CTAG_OP_EXTENSIONS );
if( cryptStatusOK( status ) )
{
status = readAttributes( stream, ¤tEntry->attributes,
CRYPT_CERTTYPE_NONE, length,
&certInfoPtr->errorLocus, &certInfoPtr->errorType );
}
if( cryptStatusError( status ) )
return( status );
}
/* If 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 that we don't try and
add it a second time) */
if( 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 );
}
STDC_NONNULL_ARG( ( 1, 2 ) ) \
int writeOcspResponseEntry( INOUT STREAM *stream,
const REVOCATION_INFO *ocspEntry,
const time_t entryTime )
{
int certStatusSize, status;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( isReadPtr( ocspEntry, sizeof( REVOCATION_INFO ) ) );
/* Determine the size of the certificate status field */
certStatusSize = ( ocspEntry->status != CRYPT_OCSPSTATUS_REVOKED ) ? \
sizeofNull() : ( int ) sizeofObject( sizeofGeneralizedTime() );
/* Write the header and ID information */
writeSequence( stream, sizeofOcspID( ocspEntry ) + \
certStatusSize + sizeofGeneralizedTime() + \
( ( ocspEntry->attributeSize > 0 ) ? \
( int ) sizeofObject( ocspEntry->attributeSize ) : 0 ) );
writeOcspID( stream, ocspEntry );
/* Write the certificate status */
if( ocspEntry->status == CRYPT_OCSPSTATUS_REVOKED )
{
writeConstructed( stream, sizeofGeneralizedTime(),
CRYPT_OCSPSTATUS_REVOKED );
writeGeneralizedTime( stream, ocspEntry->revocationTime,
DEFAULT_TAG );
}
else
{
/* An other-than-revoked status is communicated as a tagged NULL
value. For no known reason this portion of OCSP uses implicit
tagging, since it's the one part of the PDU in which an
explicit tag would actually make sense */
writeNull( stream, ocspEntry->status );
}
/* Write the current update time, which should be the current time.
Since new status information is always available we don't write a
nextUpdate time (in fact there is some disagreement over whether these
times are based on CRL info, responder info, the response dispatch
time, or a mixture of the above, implementations can be found that
return all manner of peculiar values here) */
status = writeGeneralizedTime( stream, entryTime, DEFAULT_TAG );
if( cryptStatusError( status ) || ocspEntry->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_OCSP
to make sure that they're processed as required */
return( writeAttributes( stream, ocspEntry->attributes,
CRYPT_CERTTYPE_NONE, ocspEntry->attributeSize ) );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -