📄 certrd.c
字号:
/****************************************************************************
* *
* Certificate Read Routines *
* Copyright Peter Gutmann 1996-2001 *
* *
****************************************************************************/
#include <stdlib.h>
#include <string.h>
#if defined( INC_ALL ) || defined( INC_CHILD )
#include "asn1.h"
#include "asn1objs.h"
#include "asn1oid.h"
#include "cert.h"
#else
#include "keymgmt/asn1.h"
#include "keymgmt/asn1objs.h"
#include "keymgmt/asn1oid.h"
#include "keymgmt/cert.h"
#endif /* Compiler-specific includes */
/* Context-specific tags for certificates */
enum { CTAG_CE_VERSION, CTAG_CE_ISSUERUNIQUEID, CTAG_CE_SUBJECTUNIQUEID,
CTAG_CE_EXTENSIONS };
/* Context-specific tags for attribute certificates */
enum { CTAG_AC_BASECERTIFICATEID, CTAG_AC_ENTITYNAME,
CTAG_AC_OBJECTDIGESTINFO };
/* Context-specific tags for certification requests */
enum { CTAG_CR_ATTRIBUTES };
/* Context-specific tags for CRMF certification requests */
enum { CTAG_CF_VERSION, CTAG_CF_SERIALNUMBER, CTAG_CF_SIGNINGALG,
CTAG_CF_ISSUER, CTAG_CF_VALIDITY, CTAG_CF_SUBJECT, CTAG_CF_PUBLICKEY,
CTAG_CF_ISSUERUID, CTAG_CF_SUBJECTUID, CTAG_CF_EXTENSIONS };
/* Context-specific tags for OCSP requests */
enum { CTAG_RQ_VERSION, CTAG_RQ_DUMMY, CTAG_RQ_EXTENSIONS };
/* Context-specific tags for OCSP responses */
enum { CTAG_RP_VERSION, CTAG_RP_EXTENSIONS };
/* Context-specific tags for OCSP certificate identifier types */
enum { OCSP_IDTYPE_ISSUERANDSERIALNUMBER, OCSP_IDTYPE_CERTIFICATE,
OCSP_IDTYPE_DUMMY, OCSP_IDTYPE_CERTHASH };
/* OCSP cert status values */
enum { OCSP_STATUS_NOTREVOKED, OCSP_STATUS_REVOKED, OCSP_STATUS_UNKNOWN };
/* Prototypes for functions in certstr.c */
int convertEmailAddress( CERT_INFO *certInfoPtr );
/****************************************************************************
* *
* Revocation Information Functions *
* *
****************************************************************************/
/* Find an entry in a revocation list */
static int findRevocationEntry( REVOCATION_INFO *listPtr,
REVOCATION_INFO **insertPoint,
const void *value, const int valueLength )
{
REVOCATION_INFO *prevElement = NULL;
*insertPoint = NULL;
/* Find the correct place in the list to insert the new element and check
for duplicates. We sort the entries by serial number (or, more
generally, data value) for no adequately explored reason (some
implementations can optimise the searching of CRLs based on this, but
since there's no agreement on whether to do it or not you can't tell
whether it's safe to rely on this) */
while( listPtr != NULL )
{
if( listPtr->dataLength == valueLength )
{
const int compareStatus = memcmp( listPtr->data,
value, valueLength );
if( !compareStatus )
{
/* We found a matching entry, tell the caller which one it
is */
*insertPoint = listPtr;
return( CRYPT_OK );
}
if( compareStatus > 0 )
break; /* Insert before this point */
}
else
if( listPtr->dataLength > valueLength )
break; /* Insert before this point */
prevElement = listPtr;
listPtr = listPtr->next;
}
/* We can't find a matching entry, return the revocation entry after
which we should insert the new value */
*insertPoint = prevElement;
return( CRYPT_ERROR_NOTFOUND );
}
/* Check whether a cert has been revoked */
int checkRevocation( const CERT_INFO *certInfoPtr,
CERT_INFO *revocationInfoPtr )
{
REVOCATION_INFO *revocationEntry;
int status;
/* If we're checking against a CRL and the issuers differ, the cert
can't be in this CRL */
if( revocationInfoPtr->type == CRYPT_CERTTYPE_CRL && \
( revocationInfoPtr->issuerDNsize != certInfoPtr->issuerDNsize || \
memcmp( revocationInfoPtr->issuerDNptr, certInfoPtr->issuerDNptr,
revocationInfoPtr->issuerDNsize ) ) )
return( CRYPT_OK );
/* Check whether the cert is present in the revocation list */
if( revocationInfoPtr->type == CRYPT_CERTTYPE_CRL )
{
status = findRevocationEntry( revocationInfoPtr->revocations,
&revocationEntry, certInfoPtr->serialNumber,
certInfoPtr->serialNumberLength );
if( status == CRYPT_ERROR_NOTFOUND )
/* No CRL entry, the certificate is OK */
return( CRYPT_OK );
}
else
{
BYTE certHash[ CRYPT_MAX_HASHSIZE ];
int certHashLength;
assert( revocationInfoPtr->type == CRYPT_CERTTYPE_OCSP_RESPONSE );
/* Get the cert hash and use it to check whether there's an entry
for this cert in the list. We read the cert hash indirectly
since it's computed on demand and may not have been evaluated
yet */
status = getCertComponent( ( CERT_INFO * ) certInfoPtr,
CRYPT_CERTINFO_FINGERPRINT_SHA,
certHash, &certHashLength );
if( cryptStatusOK( status ) )
status = findRevocationEntry( revocationInfoPtr->revocations,
&revocationEntry, certHash, certHashLength );
if( status == CRYPT_ERROR_NOTFOUND )
/* No entry, either good or bad, we can't report anything about
the cert */
return( CRYPT_ERROR_NOTFOUND );
}
/* Select the entry which contains the revocation and return the cert's
status. For CRLs the presence of an entry means the cert is invalid,
for OCSP the validity information is contained in the entry. The
unknown status is a bit difficult to report, the best we can do is
report notfound since, although the notfound occurred at the responder
rather than here */
revocationInfoPtr->currentRevocation = revocationEntry;
if( revocationInfoPtr->type == CRYPT_CERTTYPE_CRL )
return( CRYPT_ERROR_INVALID );
return( ( revocationInfoPtr->currentRevocation->status == \
CRYPT_OCSPSTATUS_NOTREVOKED ) ? CRYPT_OK : \
( revocationInfoPtr->currentRevocation->status == \
CRYPT_OCSPSTATUS_REVOKED ) ? CRYPT_ERROR_INVALID : \
CRYPT_ERROR_NOTFOUND );
}
/* Add an entry to a revocation list */
int addRevocationEntry( REVOCATION_INFO **listHeadPtr,
REVOCATION_INFO **newEntryPosition,
const CRYPT_ATTRIBUTE_TYPE valueType,
const void *value, const int valueLength )
{
REVOCATION_INFO *newElement, *insertPoint;
int status;
/* Find the insertion point for the new entry */
status = findRevocationEntry( *listHeadPtr, &insertPoint, value,
valueLength );
if( status == CRYPT_OK )
/* If get an OK status it means we've found an existing entry which
matches the one being added, we can't add it again */
return( CRYPT_ERROR_DUPLICATE );
/* Allocate memory for the new element and copy the information across */
if( ( newElement = ( REVOCATION_INFO * ) \
malloc( sizeof( REVOCATION_INFO ) ) ) == NULL )
return( CRYPT_ERROR_MEMORY );
memset( newElement, 0, sizeof( REVOCATION_INFO ) );
if( valueLength > 128 )
{
if( ( newElement->dataPtr = malloc( valueLength ) ) == NULL )
{
free( newElement );
return( CRYPT_ERROR_MEMORY );
}
}
else
newElement->dataPtr = newElement->data;
newElement->type = valueType;
memcpy( newElement->dataPtr, value, valueLength );
newElement->dataLength = valueLength;
/* Insert the new element into the list */
if( *listHeadPtr == NULL )
/* It's an empty list, make this the new list */
*listHeadPtr = newElement;
else
if( insertPoint == NULL )
{
/* We're inserting at the start of the list, make this the new
first element */
newElement->next = *listHeadPtr;
*listHeadPtr = newElement;
}
else
{
/* Insert the element in the middle or end of the list */
newElement->next = insertPoint->next;
insertPoint->next = newElement;
}
*newEntryPosition = newElement;
return( CRYPT_OK );
}
/* Delete a revocation list */
void deleteRevocationEntries( REVOCATION_INFO **listHeadPtr )
{
REVOCATION_INFO *entryListPtr = *listHeadPtr;
*listHeadPtr = NULL;
/* Destroy any remaining list items */
while( entryListPtr != NULL )
{
REVOCATION_INFO *itemToFree = entryListPtr;
entryListPtr = entryListPtr->next;
if( itemToFree->dataPtr != itemToFree->data )
{
zeroise( itemToFree->dataPtr, itemToFree->dataLength );
free( itemToFree->dataPtr );
}
if( itemToFree->attributes != NULL )
deleteAttributes( &itemToFree->attributes );
zeroise( itemToFree, sizeof( REVOCATION_INFO ) );
free( itemToFree );
}
}
/* Copy a revocation list */
int copyRevocationEntries( REVOCATION_INFO **destListHeadPtr,
const REVOCATION_INFO *srcListPtr,
CRYPT_ATTRIBUTE_TYPE *errorLocus,
CRYPT_ERRTYPE_TYPE *errorType )
{
const REVOCATION_INFO *srcListCursor;
REVOCATION_INFO *destListCursor;
assert( *destListHeadPtr == NULL ); /* Dest.should be empty */
/* Copy all revocation entries from source to destination */
for( srcListCursor = srcListPtr; srcListCursor != NULL;
srcListCursor = srcListCursor->next )
{
REVOCATION_INFO *newElement;
/* Allocate the new entry and copy the data from the existing one
across. We don't copy the attributes because there aren't any
which should be carried from request to response */
if( ( newElement = ( REVOCATION_INFO * ) \
malloc( sizeof( REVOCATION_INFO ) ) ) == NULL )
return( CRYPT_ERROR_MEMORY );
memcpy( newElement, srcListCursor, sizeof( REVOCATION_INFO ) );
if( srcListCursor->dataLength > 128 )
{
/* If the ID information doesn't fit into the fixed buffer,
allocate a variable-length one and copy it across */
if( ( newElement->dataPtr = \
malloc( srcListCursor->dataLength ) ) == NULL )
{
free( newElement );
return( CRYPT_ERROR_MEMORY );
}
memcpy( newElement->dataPtr, srcListCursor->data,
srcListCursor->dataLength );
}
else
newElement->dataPtr = newElement->data;
newElement->attributes = NULL;
newElement->next = NULL;
/* Set the status to 'unknown' by default, this means that any
entries which 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( *destListHeadPtr == NULL )
*destListHeadPtr = destListCursor = newElement;
else
{
destListCursor->next = newElement;
destListCursor = newElement;
}
}
return( CRYPT_OK );
}
/* Read a CRL entry:
RevokedCert ::= SEQUENCE {
userCertificate CertificalSerialNumber,
revocationDate UTCTime
extensions Extensions OPTIONAL,
} */
static int readCRLentry( STREAM *stream, REVOCATION_INFO **listHeadPtr,
CERT_INFO *certInfoPtr )
{
REVOCATION_INFO *currentEntry;
BYTE serialNumber[ 256 ];
int serialNumberLength, endPos, length, status;
time_t revocationTime;
/* Determine the overall size of the entry */
readSequence( stream, &length );
endPos = ( int ) stell( stream ) + length;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -