📄 read.c
字号:
/****************************************************************************
* *
* Certificate Read Routines *
* Copyright Peter Gutmann 1996-2007 *
* *
****************************************************************************/
#if defined( INC_ALL )
#include "cert.h"
#include "asn1.h"
#include "asn1_ext.h"
#else
#include "cert/cert.h"
#include "misc/asn1.h"
#include "misc/asn1_ext.h"
#endif /* Compiler-specific includes */
/****************************************************************************
* *
* Read Certificate Components *
* *
****************************************************************************/
/* Return from a certificate 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
certificate object isn't created, it allows more precise error diagnosis
for other routines */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
static int certErrorReturn( INOUT CERT_INFO *certInfoPtr,
IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE errorLocus,
IN_ERROR const int status )
{
assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
REQUIRES( errorLocus > CRYPT_ATTRIBUTE_NONE && \
errorLocus < CRYPT_IATTRIBUTE_LAST );
REQUIRES( cryptStatusError( status ) );
/* Catch any attempts to set the error locus to internal attributes */
if( errorLocus > CRYPT_ATTRIBUTE_LAST )
{
assert( DEBUG_WARN );
return( status );
}
if( status == CRYPT_ERROR_BADDATA || status == CRYPT_ERROR_UNDERFLOW )
setErrorInfo( certInfoPtr, errorLocus, CRYPT_ERRTYPE_ATTR_VALUE );
return( status );
}
/* Read a certificate serial number */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
static int readSerialNumber( INOUT STREAM *stream,
INOUT CERT_INFO *certInfoPtr,
IN_TAG const int tag )
{
BYTE integer[ MAX_SERIALNO_SIZE + 8 ];
int integerLength, status;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
REQUIRES_S( tag == DEFAULT_TAG || ( tag >= 0 && tag < MAX_TAG_VALUE ) );
/* Read the integer component of the serial number */
status = readIntegerTag( stream, integer, MAX_SERIALNO_SIZE,
&integerLength, tag );
if( cryptStatusError( status ) )
return( certErrorReturn( certInfoPtr, CRYPT_CERTINFO_SERIALNUMBER,
status ) );
/* Some certificates may have a serial number of zero, which is turned
into a zero-length integer by the ASN.1 read code since it truncates
leading zeroes that are added due to ASN.1 encoding requirements. If
we get a zero-length integer we turn it into a single zero byte */
if( integerLength <= 0 )
{
integer[ 0 ] = 0;
integerLength = 1;
}
/* Copy the data across for the caller */
return( setSerialNumber( certInfoPtr, integer, integerLength ) );
}
/* Read validity information. We allow for GeneralizedTime encodings as
well since these are used in some broken certificates */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
static int readValidity( INOUT STREAM *stream,
INOUT CERT_INFO *certInfoPtr )
{
int status;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
readSequence( stream, NULL );
if( peekTag( stream ) == BER_TIME_UTC )
status = readUTCTime( stream, &certInfoPtr->startTime );
else
status = readGeneralizedTime( stream, &certInfoPtr->startTime );
if( cryptStatusError( status ) )
{
return( certErrorReturn( certInfoPtr, CRYPT_CERTINFO_VALIDFROM,
status ) );
}
if( peekTag( stream ) == BER_TIME_UTC )
status = readUTCTime( stream, &certInfoPtr->endTime );
else
status = readGeneralizedTime( stream, &certInfoPtr->endTime );
if( cryptStatusError( status ) )
{
return( certErrorReturn( certInfoPtr, CRYPT_CERTINFO_VALIDTO,
status ) );
}
return( CRYPT_OK );
}
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
static int readCrmfValidity( INOUT STREAM *stream,
INOUT CERT_INFO *certInfoPtr )
{
int tag, status;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
status = readConstructed( stream, NULL, CTAG_CF_VALIDITY );
tag = peekTag( stream );
if( cryptStatusError( tag ) )
return( tag );
if( tag == MAKE_CTAG( 0 ) )
{
readConstructed( stream, NULL, 0 );
if( peekTag( stream ) == BER_TIME_UTC )
status = readUTCTime( stream, &certInfoPtr->startTime );
else
status = readGeneralizedTime( stream, &certInfoPtr->startTime );
if( cryptStatusError( status ) )
{
return( certErrorReturn( certInfoPtr, CRYPT_CERTINFO_VALIDFROM,
status ) );
}
tag = peekTag( stream );
if( cryptStatusError( tag ) )
return( tag );
}
if( tag == MAKE_CTAG( 1 ) )
{
readConstructed( stream, NULL, 1 );
if( peekTag( stream ) == BER_TIME_UTC )
status = readUTCTime( stream, &certInfoPtr->endTime );
else
status = readGeneralizedTime( stream, &certInfoPtr->endTime );
if( cryptStatusError( status ) )
{
return( certErrorReturn( certInfoPtr, CRYPT_CERTINFO_VALIDTO,
status ) );
}
}
return( status );
}
/* Read a uniqueID */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
static int readUniqueID( INOUT STREAM *stream,
INOUT CERT_INFO *certInfoPtr,
IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE type )
{
int length, status;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
REQUIRES( type == CRYPT_CERTINFO_ISSUERUNIQUEID || \
type == CRYPT_CERTINFO_SUBJECTUNIQUEID );
/* Read the length of the unique ID, allocate room for it, and read it
into the certificate. We ignore the tag since we've already checked
it via peekTag() before we got here */
status = readBitStringHole( stream, &length, 1,
( type == CRYPT_CERTINFO_ISSUERUNIQUEID ) ? \
CTAG_CE_ISSUERUNIQUEID : \
CTAG_CE_SUBJECTUNIQUEID );
if( cryptStatusOK( status ) && ( length < 1 || length > 1024 ) )
status = CRYPT_ERROR_BADDATA;
if( cryptStatusOK( status ) )
{
void *bufPtr;
if( ( bufPtr = clDynAlloc( "readUniqueID", length ) ) == NULL )
return( CRYPT_ERROR_MEMORY );
if( type == CRYPT_CERTINFO_SUBJECTUNIQUEID )
{
certInfoPtr->cCertCert->subjectUniqueID = bufPtr;
certInfoPtr->cCertCert->subjectUniqueIDlength = length;
}
else
{
certInfoPtr->cCertCert->issuerUniqueID = bufPtr;
certInfoPtr->cCertCert->issuerUniqueIDlength = length;
}
status = sread( stream, bufPtr, length );
}
if( cryptStatusError( status ) )
return( certErrorReturn( certInfoPtr, type, status ) );
return( CRYPT_OK );
}
/* Read DN information and remember the encoded DN data so we can copy it
(complete with any encoding errors) to the issuer DN field of anything
we sign */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
static int readSubjectDN( INOUT STREAM *stream,
INOUT CERT_INFO *certInfoPtr )
{
int length, status;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
status = getStreamObjectLength( stream, &length );
if( cryptStatusOK( status ) )
{
certInfoPtr->subjectDNsize = length;
status = sMemGetDataBlock( stream, &certInfoPtr->subjectDNptr,
length );
}
if( cryptStatusOK( status ) )
status = readDN( stream, &certInfoPtr->subjectName );
if( cryptStatusError( status ) )
{
return( certErrorReturn( certInfoPtr, CRYPT_CERTINFO_SUBJECTNAME,
status ) );
}
return( CRYPT_OK );
}
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
static int readIssuerDN( INOUT STREAM *stream,
INOUT CERT_INFO *certInfoPtr )
{
int length, status;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
status = getStreamObjectLength( stream, &length );
if( cryptStatusOK( status ) )
{
certInfoPtr->issuerDNsize = length;
status = sMemGetDataBlock( stream, &certInfoPtr->issuerDNptr,
length );
}
if( cryptStatusOK( status ) )
status = readDN( stream, &certInfoPtr->issuerName );
if( cryptStatusError( status ) )
{
return( certErrorReturn( certInfoPtr, CRYPT_CERTINFO_ISSUERNAME,
status ) );
}
return( CRYPT_OK );
}
/* Read public-key information */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
static int readPublicKeyInfo( INOUT STREAM *stream,
INOUT CERT_INFO *certInfoPtr )
{
int length, status;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
/* Record a reference to the public-key data */
status = getStreamObjectLength( stream, &length );
if( cryptStatusOK( status ) )
{
certInfoPtr->publicKeyInfoSize = length;
status = sMemGetDataBlock( stream, &certInfoPtr->publicKeyInfo,
length );
}
if( cryptStatusError( status ) )
{
return( certErrorReturn( certInfoPtr,
CRYPT_CERTINFO_SUBJECTPUBLICKEYINFO,
status ) );
}
/* Import or at least read the public key information */
if( certInfoPtr->flags & CERT_FLAG_DATAONLY )
{
/* We're doing deferred handling of the public key, skip it for now.
Because of weird tagging in things like CRMF objects we have to
read the information as a generic hole rather than a normal
SEQUENCE. In addition because readAlgoID() can return non-stream
errors (for example an algorithm not-available status) we have to
explicitly check the return status rather than relying on it to
be carried along in the stream state */
readGenericHole( stream, NULL, 4, DEFAULT_TAG );
status = readAlgoID( stream, &certInfoPtr->publicKeyAlgo );
if( cryptStatusOK( status ) )
status = readUniversal( stream );
}
else
{
status = iCryptReadSubjectPublicKey( stream,
&certInfoPtr->iPubkeyContext, FALSE );
if( cryptStatusOK( status ) )
status = krnlSendMessage( certInfoPtr->iPubkeyContext,
IMESSAGE_GETATTRIBUTE,
&certInfoPtr->publicKeyAlgo,
CRYPT_CTXINFO_ALGO );
}
if( cryptStatusError( status ) )
{
return( certErrorReturn( certInfoPtr,
CRYPT_CERTINFO_SUBJECTPUBLICKEYINFO,
status ) );
}
return( CRYPT_OK );
}
/****************************************************************************
* *
* Read a Certificate Object *
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -