📄 imp_exp.c
字号:
*offset = stell( stream );
status = readSequence( stream, NULL );
return( cryptStatusError( status ) ? \
status : CRYPT_CERTTYPE_NONE );
}
else
{
if( memcmp( oid, OID_NS_CERTSEQ, oidLength ) )
return( CRYPT_ERROR_BADDATA );
}
}
readConstructedI( stream, NULL, 0 );
status = readSequenceI( stream, NULL );
if( cryptStatusError( status ) )
return( status );
/* If it's a PKCS #7 certificate chain, burrow into the inner PKCS #7
content */
if( isCertChain )
{
long integer;
int value = DUMMY_INIT, innerLength;
/* Read the version number (1 = PKCS #7 v1.5, 2 = PKCS #7 v1.6,
3 = S/MIME with attribute certificate(s)) and SET OF
DigestAlgorithmIdentifier (this is empty for a pure certificate
chain, nonempty for signed data) */
status = readShortInteger( stream, &integer );
if( cryptStatusOK( status ) && ( integer < 1 || integer > 3 ) )
status = CRYPT_ERROR_BADDATA;
if( cryptStatusOK( status ) )
status = readSet( stream, &value );
if( cryptStatusError( status ) )
return( status );
if( value > 0 )
sSkip( stream, value );
/* Read the ContentInfo header, contentType OID (ignored) and the
inner content encapsulation. Sometimes we may (incorrectly) get
passed actual signed data (rather than degenerate zero-length
data signifying a pure certificate chain) so if there's data
present we skip it */
readSequenceI( stream, &innerLength );
status = readEncodedOID( stream, oid, MAX_OID_SIZE, &oidLength,
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
certificate chain */
if( innerLength > sizeofObject( oidLength ) )
readUniversal( stream );
}
status = readConstructedI( stream, NULL, 0 );
if( cryptStatusError( status ) )
return( status );
}
/* 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 );
}
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3, 4, 5 ) ) \
static int getCertObjectInfo( IN_BUFFER( objectTotalLength ) const void *object,
IN_LENGTH const int objectTotalLength,
OUT_LENGTH_SHORT_Z int *objectOffset,
OUT_LENGTH_Z int *objectLength,
OUT_ENUM_OPT( CRYPT_CERTTYPE ) \
CRYPT_CERTTYPE_TYPE *objectType,
IN_ENUM( CRYPT_CERTTYPE ) \
const CRYPT_CERTTYPE_TYPE formatHint )
{
STREAM stream;
BOOLEAN isContextTagged = FALSE, isLongData = FALSE;
int tag, length, status;
assert( isReadPtr( object, objectTotalLength ) );
assert( isWritePtr( objectOffset, sizeof( int ) ) );
assert( isWritePtr( objectLength, sizeof( int ) ) );
assert( isWritePtr( objectType, sizeof( CRYPT_CERTTYPE_TYPE ) ) );
REQUIRES( formatHint >= CRYPT_CERTTYPE_NONE && \
formatHint < CRYPT_CERTTYPE_LAST );
/* Clear return values */
*objectOffset = *objectLength = 0;
*objectType = CRYPT_CERTTYPE_NONE;
/* If it's an SSL certificate chain there's no recognisable tagging,
however the caller will have told us what it is */
if( formatHint == 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 ) || \
formatHint == CRYPT_ICERTTYPE_CMS_CERTSET )
isContextTagged = TRUE;
status = readConstructedI( &stream, &length, \
isContextTagged ? 0 : DEFAULT_TAG );
if( cryptStatusError( status ) )
{
long longLength;
#if INT_MAX > 32767
if( status != CRYPT_ERROR_OVERFLOW )
#endif /* Non-16-bit systems */
{
sMemDisconnect( &stream );
return( status );
}
#if INT_MAX > 32767
ENSURES( status == CRYPT_ERROR_OVERFLOW );
/* CRLs can grow without bounds as more and more certificates 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;
}
#endif /* Non-16-bit systems */
}
ENSURES( cryptStatusOK( status ) );
if( length != CRYPT_UNUSED )
{
/* It's a definite-length object, adjust the length for the size of
the header that we read */
length += stell( &stream );
}
else
{
/* It's a indefinite-length object, burrow into it to find it's
actual length */
status = getObjectLength( object, objectTotalLength, &length );
#if INT_MAX > 32767
if( status == CRYPT_ERROR_OVERFLOW )
{
long longLength;
status = getLongObjectLength( object, objectTotalLength,
&longLength );
if( cryptStatusOK( status ) )
length = longLength;
}
#endif /* Non-16-bit systems */
}
if( cryptStatusOK( status ) && \
( length < 1 || length > objectTotalLength ) )
{
assert( DEBUG_WARN );
status = CRYPT_ERROR_BADDATA;
}
if( cryptStatusError( status ) )
{
sMemDisconnect( &stream );
return( status );
}
*objectLength = length;
/* 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( formatHint != CRYPT_CERTTYPE_NONE )
{
sMemDisconnect( &stream );
switch( formatHint )
{
case CRYPT_ICERTTYPE_DATAONLY:
/* Standard certificate but created without creating a
context for the accompanying public key */
*objectType = CRYPT_CERTTYPE_CERTIFICATE;
break;
case CRYPT_ICERTTYPE_CTL:
/* Certificate chain used as a container for trusted
certificates, effectively a chain of
CRYPT_ICERTTYPE_DATAONLY certificates */
*objectType = CRYPT_CERTTYPE_CERTCHAIN;
break;
case CRYPT_ICERTTYPE_REVINFO:
/* Single CRL entry, treated as standard CRL with portions
missing */
*objectType = CRYPT_CERTTYPE_CRL;
break;
default:
*objectType = formatHint;
}
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 certificate sequence,
there'll be an object identifier present. Some sources also wrap
certificates 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 certificates in a PKCS #12 file,
the following is the one that (eventually) ends up in a
certificate that we can read */
status = readShortInteger( &stream, &value );
if( cryptStatusError( status ) || value != 3 )
{
sMemDisconnect( &stream );
return( CRYPT_ERROR_BADDATA );
}
readSequence( &stream, NULL );
readFixedOID( &stream, OID_CMS_DATA, sizeofOID( OID_CMS_DATA ) );
readConstructed( &stream, NULL, 0 );
readOctetStringHole( &stream, NULL, 8, DEFAULT_TAG );
readSequence( &stream, NULL );
readSequence( &stream, NULL );
readFixedOID( &stream, OID_CMS_DATA, sizeofOID( OID_CMS_DATA ) );
readConstructed( &stream, NULL, 0 );
readOctetStringHole( &stream, NULL, 8, DEFAULT_TAG );
readSequence( &stream, NULL );
readSequence( &stream, NULL );
readFixedOID( &stream,
MKOID( "\x06\x0B\x2A\x86\x48\x86\xF7\x0D\x01\x0C\x0A\x01\x03" ),
13 );
readConstructed( &stream, NULL, 0 );
readSequence( &stream, NULL );
readFixedOID( &stream,
MKOID( "\x06\x0A\x2A\x86\x48\x86\xF7\x0D\x01\x09\x16\x01" ),
12 );
readConstructed( &stream, NULL, 0 );
readOctetStringHole( &stream, &length, 8, 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 certificate, record its offset and
length */
*objectOffset = offset;
*objectLength = length;
*objectType = CRYPT_CERTTYPE_CERTIFICATE;
return( isLongData ? CRYPT_ERROR_OVERFLOW : CRYPT_OK );
}
/* Read the inner sequence */
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( cryptStatusError( status ) )
{
sMemDisconnect( &stream );
return( status );
}
/* Skip optional tagged fields and the INTEGER value */
if( peekTag( &stream ) == MAKE_CTAG( 0 ) )
status = readUniversal( &stream );
if( peekTag( &stream ) == MAKE_CTAG( 1 ) )
status = readUniversal( &stream );
if( peekTag( &stream ) == MAKE_CTAG( 2 ) )
status = readUniversal( &stream );
if( peekTag( &stream ) == BER_INTEGER )
status = readUniversal( &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 );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -