📄 certio.c
字号:
if( cryptStatusOK( status ) )
status = readSet( stream, &value );
if( cryptStatusError( status ) )
return( status );
if( value > 0 )
sSkip( stream, value );
/* Read the ContentInfo header, contentType OID and the inner content
encapsulation. Sometimes we may (incorrectly) get passed actual
signed data (rather than degenerate zero-length data signifying a
pure cert chain), if there's data present we skip it */
readSequenceI( stream, &innerLength );
status = readRawObject( stream, NULL, &oidLength, MAX_OID_SIZE,
BER_OBJECT_IDENTIFIER );
if( cryptStatusError( status ) )
return( status );
if( innerLength == CRYPT_UNUSED )
/* It's an indefinite-length ContentInfo, check for the EOC */
checkEOC( stream );
else
/* If we've been fed signed data (i.e. the ContentInfo has the
content field present), skip the content to get to the cert
chain */
if( innerLength > sizeofObject( oidLength ) )
readUniversal( stream );
readConstructed( stream, NULL, 0 );
}
/* We've finally reached the certificate(s), retry the read of the
certificate start */
status = readSequence( stream, NULL );
return( cryptStatusError( status ) ? status : CRYPT_CERTTYPE_CERTCHAIN );
}
static int getCertObjectInfo( const void *object, const int objectTotalLength,
int *objectOffset, int *objectLength,
CRYPT_CERTTYPE_TYPE *objectType,
const CERTFORMAT_TYPE formatType )
{
STREAM stream;
BOOLEAN isContextTagged = FALSE, isLongData = FALSE;
int tag, length, status;
/* Set initial default values */
*objectOffset = 0;
*objectLength = CRYPT_ERROR;
*objectType = CRYPT_CERTTYPE_NONE;
/* If it's an SSL cert chain there's no recognisable tagging, however the
caller will have told us what it is */
if( formatType == CRYPT_ICERTTYPE_SSL_CERTCHAIN )
{
*objectLength = objectTotalLength;
*objectType = CRYPT_ICERTTYPE_SSL_CERTCHAIN;
return( CRYPT_OK );
}
sMemConnect( &stream, object, objectTotalLength );
/* Check that the start of the object is in order and get its length */
if( peekTag( &stream ) == MAKE_CTAG( 0 ) || \
formatType == CRYPT_ICERTTYPE_CMS_CERTSET )
isContextTagged = TRUE;
status = readConstructedI( &stream, &length, \
isContextTagged ? 0 : DEFAULT_TAG );
#if INT_MAX > 32767
if( status == CRYPT_ERROR_OVERFLOW )
{
long longLength;
/* CRLs can grow without bounds as more and more certs are
accumulated, to handle these we have to fall back to an
unconstrained read if a standard constrained read fails */
sClearError( &stream );
sseek( &stream, 0 );
status = readLongSequence( &stream, &longLength );
if( cryptStatusOK( status ) )
{
/* We don't have to check for the CRYPT_UNUSED indefinite-length
return value in this case since we can only get here if the
length overflows a 16-bit int, so it can never be indefinite-
length */
length = ( int ) longLength;
isLongData = TRUE;
}
}
else
#endif /* Non-16-bit systems */
if( cryptStatusOK( status ) && length == CRYPT_UNUSED )
{
/* It's a indefinite-length object, burrow into it to find it's
actual length */
status = getObjectLength( object, objectTotalLength );
#if INT_MAX > 32767
if( status == CRYPT_ERROR_OVERFLOW )
status = getLongObjectLength( object, objectTotalLength );
#endif /* Non-16-bit systems */
}
if( cryptStatusError( status ) )
{
sMemDisconnect( &stream );
return( status );
}
*objectLength = ( length != CRYPT_UNUSED ) ? \
( int ) sizeofObject( length ) : status;
/* If the caller has specified that the data is in a fixed format, don't
try and recognise any other format. This prevents security holes of
the type common in Windows software where data purportedly of type A
is auto-recognised as harmful type B and processed as such after being
passed as type A by security-checking code */
if( formatType != CRYPT_CERTTYPE_NONE )
{
sMemDisconnect( &stream );
if( formatType > CRYPT_CERTTYPE_NONE && \
formatType < CRYPT_CERTTYPE_LAST )
*objectType = formatType;
else
switch( formatType )
{
case CERTFORMAT_DATAONLY:
/* Standard certificate but created without creating a
context for the accompanying public key */
*objectType = CRYPT_CERTTYPE_CERTIFICATE;
break;
case CERTFORMAT_CTL:
/* Cert chain used as a container for trusted certs,
effectively a chain of CERTFORMAT_DATAONLY certs */
*objectType = CRYPT_CERTTYPE_CERTCHAIN;
break;
case CERTFORMAT_REVINFO:
/* Single CRL entry, treated as standard CRL with
portions missing */
*objectType = CRYPT_CERTTYPE_CRL;
break;
default:
assert( NOTREACHED );
return( CRYPT_ERROR_BADDATA );
}
return( isLongData ? CRYPT_ERROR_OVERFLOW : CRYPT_OK );
}
/* First we check for the easy ones, CMS attributes, which begin with a
[0] IMPLICIT SET */
if( isContextTagged )
{
*objectType = CRYPT_CERTTYPE_CMS_ATTRIBUTES;
sMemDisconnect( &stream );
return( isLongData ? CRYPT_ERROR_OVERFLOW : CRYPT_OK );
}
/* If it's a PKCS #7 certificate chain or Netscape cert.sequence,
there'll be an object identifier present. Some sources also wrap
certs up in oddball OID's, so we check for these as well */
if( peekTag( &stream ) == BER_OBJECT_IDENTIFIER )
{
status = decodeCertWrapper( &stream, objectOffset );
sMemDisconnect( &stream );
if( cryptStatusError( status ) )
return( status );
*objectType = ( status != CRYPT_CERTTYPE_NONE ) ? \
status : CRYPT_CERTTYPE_CERTIFICATE;
return( isLongData ? CRYPT_ERROR_OVERFLOW : CRYPT_OK );
}
/* If it's a PKCS #12 mess, there'll be a version number, 3, present */
if( peekTag( &stream ) == BER_INTEGER )
{
long value;
int offset;
/* Strip off the amazing number of layers of bloat that PKCS #12
lards a certificate with. There are any number of different
interpretations of how to store certs in a PKCS #12 file, the
following is the one that (eventually) ends up in a cert that
we can read */
status = readShortInteger( &stream, &value );
if( cryptStatusError( status ) || value != 3 )
{
sMemDisconnect( &stream );
return( CRYPT_ERROR_BADDATA );
}
readSequence( &stream, NULL );
readOID( &stream, OID_CMS_DATA );
readConstructed( &stream, NULL, 0 );
readOctetStringHole( &stream, NULL, DEFAULT_TAG );
readSequence( &stream, NULL );
readSequence( &stream, NULL );
readOID( &stream, OID_CMS_DATA );
readConstructed( &stream, NULL, 0 );
readOctetStringHole( &stream, NULL, DEFAULT_TAG );
readSequence( &stream, NULL );
readSequence( &stream, NULL );
readOID( &stream,
MKOID( "\x06\x0B\x2A\x86\x48\x86\xF7\x0D\x01\x0C\x0A\x01\x03" ) );
readConstructed( &stream, NULL, 0 );
readSequence( &stream, NULL );
readOID( &stream,
MKOID( "\x06\x0A\x2A\x86\x48\x86\xF7\x0D\x01\x09\x16\x01" ) );
readConstructed( &stream, NULL, 0 );
readOctetStringHole( &stream, &length, DEFAULT_TAG );
offset = stell( &stream ); /* Certificate start */
readSequence( &stream, NULL );
status = readSequence( &stream, NULL );
sMemDisconnect( &stream );
if( cryptStatusError( status ) )
return( status );
/* We've finally reached the cert, record its offset and length */
*objectOffset = offset;
*objectLength = length;
*objectType = CRYPT_CERTTYPE_CERTIFICATE;
return( isLongData ? CRYPT_ERROR_OVERFLOW : CRYPT_OK );
}
/* Read the inner sequence and skip optional tagged fields and the
INTEGER value */
if( isLongData )
{
long longLength;
status = readLongSequence( &stream, &longLength );
if( cryptStatusOK( status ) )
{
/* If it's an (invalid) indefinite-length encoding we can't do
anything with it */
if( longLength == CRYPT_UNUSED )
status = CRYPT_ERROR_BADDATA;
else
length = ( int ) longLength;
}
}
else
status = readSequence( &stream, &length );
if( peekTag( &stream ) == MAKE_CTAG( 0 ) )
readUniversal( &stream );
if( peekTag( &stream ) == MAKE_CTAG( 1 ) )
readUniversal( &stream );
if( peekTag( &stream ) == MAKE_CTAG( 2 ) )
readUniversal( &stream );
if( peekTag( &stream ) == BER_INTEGER )
readUniversal( &stream );
if( cryptStatusOK( status ) )
status = sGetStatus( &stream );
if( cryptStatusError( status ) )
{
sMemDisconnect( &stream );
return( status );
}
if( length == 0 )
{
/* PKI user object with absent (non-specified) DN */
sMemDisconnect( &stream );
*objectType = CRYPT_CERTTYPE_PKIUSER;
return( isLongData ? CRYPT_ERROR_OVERFLOW : CRYPT_OK );
}
/* If we've hit a [1] it's an attribute cert, if we've hit a
GeneralizedTime it's an OCSP response, if we've hit a SET it's PKI
user info, and if we've hit a [0] or [1] primitive tag (implicitly
tagged INTEGER) or [3]...[9] it's a CRMF revocation request */
tag = peekTag( &stream );
if( tag == MAKE_CTAG( 1 ) || tag == BER_TIME_GENERALIZED || \
tag == BER_SET )
{
sMemDisconnect( &stream );
*objectType = \
( tag == MAKE_CTAG( 1 ) ) ? CRYPT_CERTTYPE_ATTRIBUTE_CERT : \
( tag == BER_TIME_GENERALIZED ) ? \
CRYPT_CERTTYPE_OCSP_RESPONSE : CRYPT_CERTTYPE_PKIUSER;
return( isLongData ? CRYPT_ERROR_OVERFLOW : CRYPT_OK );
}
if( tag == MAKE_CTAG_PRIMITIVE( 0 ) || \
tag == MAKE_CTAG_PRIMITIVE( 1 ) || \
( tag >= MAKE_CTAG( 3 ) && tag <= MAKE_CTAG( 9 ) ) )
{
sMemDisconnect( &stream );
*objectType = CRYPT_CERTTYPE_REQUEST_REVOCATION;
return( isLongData ? CRYPT_ERROR_OVERFLOW : CRYPT_OK );
}
/* Read the next SEQUENCE. If it's followed by an OID, it's the
AlgorithmIdentifier in a cert or CRL. If it's followed by a SET, it's
the Name in a cert request or attribute cert. If it's followed by a
tag in the range [0]...[9] it's a horror from CRMF */
status = readSequence( &stream, &length );
if( cryptStatusOK( status ) && length <= 0 )
status = CRYPT_ERROR_BADDATA;
if( cryptStatusError( status ) )
{
sMemDisconnect( &stream );
return( status );
}
tag = peekTag( &stream );
if( tag == BER_OBJECT_IDENTIFIER )
{
/* Skip the AlgorithmIdentifier data and the following Name. For a
cert we now have a SEQUENCE (from the Validity), for a CRL a
UTCTime or GeneralizedTime */
sSkip( &stream, length );
readUniversal( &stream );
tag = readTag( &stream );
sMemDisconnect( &stream );
if( tag == BER_SEQUENCE )
{
*objectType = CRYPT_CERTTYPE_CERTIFICATE;
return( isLongData ? CRYPT_ERROR_OVERFLOW : CRYPT_OK );
}
if( tag == BER_TIME_UTC || tag == BER_TIME_GENERALIZED )
{
*objectType = CRYPT_CERTTYPE_CRL;
return( CRYPT_OK );
}
return( CRYPT_ERROR_BADDATA );
}
if( isLongData )
/* Beyond this point we shouldn't be seeing long-length objects */
return( CRYPT_ERROR_OVERFLOW );
if( tag >= MAKE_CTAG( 0 ) && tag <= MAKE_CTAG( 9 ) )
{
/* Cert requests and revocation requests have the same format,
however revocation requests should have the cert serial number
present while cert requests shouldn't (at least in any normal
implementation), so we use this to distinguish the two. If
this ever fails in the future, we can also look for things like
[6] (the public key) as a clue that it's a cert request */
sMemDisconnect( &stream );
*objectType = ( tag == MAKE_CTAG( 1 ) ) ? \
CRYPT_CERTTYPE_REQUEST_REVOCATION : CRYPT_CERTTYPE_REQUEST_CERT;
return( CRYPT_OK );
}
if( tag == BER_SET )
{
sSkip( &stream, length );
readSequence( &stream, NULL );
tag = readTag( &stream );
sMemDisconnect( &stream );
if( tag == BER_OBJECT_IDENTIFIER )
{
*objectType = CRYPT_CERTTYPE_ATTRIBUTE_CERT;
return( CRYPT_OK );
}
if( tag == BER_SEQUENCE )
{
*objectType = CRYPT_CERTTYPE_CERTREQUEST;
return( CRYPT_OK );
}
return( CRYPT_ERROR_BADDATA );
}
/* Read the next SEQUENCE. If it's followed by a yet another SEQUENCE
or a tag from [0] ... [3] it's an OCSP request, if it's followed by
an OCTET STRING it's a cryptlib OCSP response */
readSequence( &stream, NULL );
tag = readTag( &stream );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -