📄 certio.c
字号:
/****************************************************************************
* *
* Certificate Import/Export Routines *
* Copyright Peter Gutmann 1997-2003 *
* *
****************************************************************************/
#include <stdlib.h>
#include <string.h>
#if defined( INC_ALL ) || defined( INC_CHILD )
#include "cert.h"
#include "../misc/asn1_rw.h"
#include "../misc/asn1s_rw.h"
#else
#include "cert/cert.h"
#include "misc/asn1_rw.h"
#include "misc/asn1s_rw.h"
#endif /* Compiler-specific includes */
/* Oddball OIDs that may be used to wrap certs */
#define OID_X509_USERCERTIFICATE "\x06\x03\x55\x04\x24"
/****************************************************************************
* *
* Utility Functions *
* *
****************************************************************************/
/* Determine the object type and how long the total object is. If fed an
unknown object from the external source we can (with some difficulty)
determine its type at runtime (although it's hardly LL(1)) and import it
as appropriate. If fed an object by a cryptlib-internal function, the
exact type will always be known.
If the data starts with a [0], it's CMS attributes. If it starts with a
sequence followed by an OID it's a cert chain/sequence or (rarely) a cert
wrapped up in some weird packaging. If it starts with a sequence followed
by an integer (version = 3), it's a PKCS #12 mess. Otherwise, it follows
the general pattern SEQUENCE { tbsSomething, signature }, it's at this
point that distinguishing the different types gets tricky.
Cert: SEQUENCE { SEQUENCE {
[0] EXPLICIT ... OPTIONAL,
INTEGER,
AlgorithmID,
Name,
SEQUENCE { -- Validity
{ UTCTime | GeneralizedTime }
Attribute cert: SEQUENCE { SEQUENCE {
INTEGER OPTIONAL,
[1] Name,
Name,
AlgorithmID,
INTEGER
CRL: SEQUENCE { SEQUENCE {
INTEGER OPTIONAL,
AlgorithmID,
Name,
{ UTCTime | GeneralizedTime }
Cert request: SEQUENCE { SEQUENCE {
INTEGER,
Name,
SEQUENCE { -- SubjectPublicKeyInfo
AlgorithmID
CRMF request: SEQUENCE { SEQUENCE {
INTEGER,
SEQUENCE {
{ [0] ... [9] } -- cert request should have
-- [6] SubjectPublicKeyInfo
CRMF rev.req: SEQUENCE { SEQUENCE {
{ [0] ... [9] } -- Should have [1] INTEGER
-- (serialNo),
OCSP request: SEQUENCE { SEQUENCE {
[0] EXPLICIT ... OPTIONAL,
[1] EXPLICIT ... OPTIONAL,
SEQUENCE { SEQUENCE {
{ SEQUENCE | [0] | [1] | [2] | [3] }
OCSP resp: SEQUENCE { SEQUENCE {
[0] EXPLICIT ... OPTIONAL,
{ [1] | [2] } ...,
GeneralizedTime
OCSP resp (cl): SEQUENCE { SEQUENCE
{ SEQUENCE { SEQUENCE {
OCTET STRING
PKI user: SEQUENCE { SEQUENCE { -- Name
{ SET ... | empty } -- RDN or zero-length DN
The first step is to strip out the SEQUENCE { SEQUENCE, which is shared
by all objects. In addition we can remove the [0] ... OPTIONAL and
[1] ... OPTIONAL, which isn't useful in distinguishing anything. Since
the standard OCSP response can also have [2] in place of the [1] and
leaving it in isn't notably useful, we strip this as well. Note that
attribute certs can be left in one of two states depending on whether
the initial INTEGER is present or not and PKI user info is also left in
one of two states depending on whether there's a DN present. Rather than
parse down into the rest of the PKI user object (the next element is an
AlgorithmID that clashes with a cert and CRL), we use the presence of
a zero-length sequence to identify a PKI user object with an absent DN.
This leaves the following,
Cert: INTEGER,
AlgorithmID,
Name,
SEQUENCE { -- Validity
{ UTCTime | GeneralizedTime }
Attribute cert: INTEGER OPTIONAL,
[1] Name,
Name, Name,
AlgorithmID, AlgorithmID,
INTEGER INTEGER
CRL: INTEGER OPTIONAL,
AlgorithmID,
Name,
{ UTCTime | GeneralizedTime }
Cert request: INTEGER,
Name,
SEQUENCE { -- SubjectPublicKeyInfo
AlgorithmID
CRMF request: INTEGER,
SEQUENCE {
{ [0] ... [1] | -- Implicitly tagged
[3] ... [9] } -- [2] stripped
CRMF rev.req: { [0] ... [1] | -- Implicitly tagged
[3] ... [9] } -- [2] stripped
OCSP request: SEQUENCE { SEQUENCE {
{ SEQUENCE | [0] | [1] | [2] | [3] }
OCSP resp: GeneralizedTime
OCSP resp (clib): SEQUENCE { SEQUENCE {
OCTET STRING
PKI user: SET ... -- RDN
Next we have the INTEGER, which also isn't notably useful. Stripping this
leaves:
Cert: AlgorithmID,
Name,
SEQUENCE { -- Validity
{ UTCTime | GeneralizedTime }
Attribute cert: [1] Name,
Name, Name,
AlgorithmID, AlgorithmID,
INTEGER INTEGER
CRL: AlgorithmID,
Name,
{ UTCTime | GeneralizedTime }
Cert request: Name,
SEQUENCE { -- SubjectPublicKeyInfo
AlgorithmID
CRMF request: SEQUENCE {
{ [0] | [1] | -- Primitive tag
[3] ... [9] } -- [2] stripped
CRMF rev.req: { [0] | [1] | -- Primitive tag
[3] ... [9] } -- [2] stripped
OCSP request: SEQUENCE { SEQUENCE {
{ SEQUENCE | [0] | [1] | [2] | [3] }
OCSP resp: GeneralizedTime
OCSP resp (clib): SEQUENCE { SEQUENCE {
OCTET STRING
PKI user: SET ... -- RDN
We can now immediately identify the first attribute cert variant by the
[1] ..., a CRMF revocation request by the not-stripped [0] or [1]
primitive tags (implicitly tagged INTEGER) or [3]...[9] ..., a standard
OCSP response by the GeneralizedTime, and the alternative PKI user
variant by the SET ..., leaving:
Cert: AlgorithmID,
Name,
SEQUENCE { -- Validity
{ UTCTime | GeneralizedTime }
CRL: AlgorithmID,
Name,
{ UTCTime | GeneralizedTime }
Attribute cert: Name,
AlgorithmID,
INTEGER
Cert request: Name,
SEQUENCE { -- SubjectPublicKeyInfo
AlgorithmID
CRMF request: SEQUENCE {
{ [3] ... [9] }
OCSP request: SEQUENCE { SEQUENCE {
{ SEQUENCE | [0] | [1] | [2] | [3] }
OCSP resp (clib): SEQUENCE { SEQUENCE {
OCTET STRING
Expanding the complex types for cert, attribute cert, CRL, and cert
request, we get:
Cert: SEQUENCE { -- AlgorithmID
OBJECT IDENTIFIER,
...
Name,
SEQUENCE { -- Validity
{ UTCTime | GeneralizedTime }
CRL: SEQUENCE { -- AlgorithmID
OBJECT IDENTIFIER,
...
Name,
{ UTCTime | GeneralizedTime }
Attribute cert: SEQUENCE { -- Name
SET {
...
...
SEQUENCE { -- AlgorithmID
OBJECT IDENTIFIER,
...
INTEGER
Cert request: SEQUENCE { -- Name
SET {
...
...
SEQUENCE { -- SubjectPublicKeyInfo
AlgorithmID
CRMF request: SEQUENCE {
{ [3] ... [9] }
OCSP request: SEQUENCE { SEQUENCE {
{ SEQUENCE | [0] | [1] | [2] | [3] }
OCSP resp (clib): SEQUENCE { SEQUENCE {
OCTET STRING
Stripping the first SEQUENCE { we get:
Cert: OBJECT IDENTIFIER,
...
Name,
SEQUENCE { -- Validity
{ UTCTime | GeneralizedTime }
CRL: OBJECT IDENTIFIER,
...
Name,
{ UTCTime | GeneralizedTime }
Attribute cert: SET {
...
...
SEQUENCE { -- AlgorithmID
OBJECT IDENTIFIER,
...
INTEGER
Cert request: SET {
...
...
SEQUENCE { -- SubjectPublicKeyInfo
AlgorithmID
CRMF request: { [3] ... [9] }
OCSP request: SEQUENCE {
{ SEQUENCE | [0] | [1] | [2] | [3] }
OCSP resp (clib): SEQUENCE {
OCTET STRING
which allows us to distinguish certs and CRLs (the two are themselves
distinguished by what follows the second Name) and cert requests and the
second attribute cert variant (the two are also distinguished by what
follows the Name). What's left now are the tricky ones, the other
request and response types:
CRMF request: { [3] ... [9] }
OCSP request: SEQUENCE {
{ SEQUENCE | [0] | [1] | [2] | [3] }
OCSP resp (clib): SEQUENCE {
OCTET STRING
which can themselves be distinguished by the remaining data */
static int decodeCertWrapper( STREAM *stream, int *offset )
{
BYTE oid[ MAX_OID_SIZE ];
BOOLEAN isCertChain = FALSE;
int oidLength, value, status;
/* Read the contentType OID, determine the content type based on it,
and read the content encapsulation and header. It can be either
a PKCS #7 cert chain, a Netscape cert sequence, or an X.509
userCertificate (which is just an oddball cert wrapper) */
status = readRawObject( stream, oid, &oidLength, MAX_OID_SIZE,
BER_OBJECT_IDENTIFIER );
if( cryptStatusError( status ) )
return( status );
if( !memcmp( oid, OID_CMS_SIGNEDDATA, oidLength ) )
isCertChain = TRUE;
else
if( !memcmp( oid, OID_X509_USERCERTIFICATE, oidLength ) )
{
/* Oddball wrapper type, set the payload offset to point to
the certificate and indicate no wrapper present */
*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 );
readConstructed( stream, NULL, 0 );
status = readSequence( 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 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 cert chain,
nonempty for signed data) */
status = readShortInteger( stream, &integer );
if( cryptStatusOK( status ) && ( integer < 1 || integer > 3 ) )
status = CRYPT_ERROR_BADDATA;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -