openssl源码解读——i2d和d2i系列函数

来源:互联网 发布:expect for windows 编辑:程序博客网 时间:2024/06/09 14:14

i2d和d2i系列函数

首先查看man文档(比如 man i2d_x509),可知:

SYNOPSIS

TYPE *d2i_TYPE(TYPE **a, unsigned char **pp, long length);TYPE *d2i_TYPE_bio(BIO *bp, TYPE **a);TYPE *d2i_TYPE_fp(FILE *bp, TYPE **a);int i2d_TYPE(TYPE **a, unsigned char **pp);int i2d_TYPE_bio(BIO *bp, TYPE **a);int i2d_TYPE_fp(FILE *bp, TYPE **a);

DESCRIPTION

TYPE is used a placeholder for any of the OpenSSL datatypes, such as X509_CRL.

These functions convert OpenSSL objects to and from their ASN.1/DER encoding.  Unlike the C structures which can have pointers to sub-objects within, the DER is a serialized encoding, suitable for sending over the network, writing to a file, and so on.

d2i_TYPE() attempts to decode len bytes at *in.If successful a pointer to the TYPE structure is returned and *in is incremented to the byte following the parsed data.  If a is not NULL then a pointer to the returned structure is also written to *a.  If an error occurred then NULL is returned.

On a successful return, if *a is not NULL then it is assumed that *a contains a valid TYPE structure and an attempt is made to reuse it. This "reuse" capability is present for historical compatibility but its use is strongly discouraged (see BUGS below,and the discussion in the RETURN VALUES section).

d2i_TYPE_bio() is similar to d2i_TYPE() except it attempts to parse data from BIO bp.

d2i_TYPE_fp() is similar to d2i_TYPE() except it attempts to parse data from FILE pointer fp.


i2d_TYPE() encodes the structure pointed to by a into DER format. If out is not NULL, it writes the DER encoded data to the buffer at *out, and increments it to point after the data just written.  If the return value is negative an error occurred, otherwise it returns the length of the encoded data.

If *out is NULL memory will be allocated for a buffer and the encoded data written to it. In this case *out is not incremented and it points to the start of the data just written.

i2d_TYPE_bio() is similar to i2d_TYPE() except it writes the encoding of the structure a to BIO bp and it returns 1 for success and 0 for failure.

i2d_TYPE_fp() is similar to i2d_TYPE() except it writes the encoding of the structure a to BIO bp and it returns 1 for success and 0 for failure.

These routines do not encrypt private keys and therefore offer no security; use PEM_write_PrivateKey(3) or similar for writing to files.

NOTES

The letters i and d in i2d_TYPE stand for"internal" (that is, an internal C structure) and"DER" respectively.  So i2d_TYPE converts from internal to DER.

The following points about the data types might be useful:

        ASN1_OBJECT
                Represents an ASN1 OBJECT IDENTIFIER.

        DHparams
                Represents a PKCS#3 DH parameters structure.

        DHparamx
                Represents a ANSI X9.42 DH parameters structure.

        DSA_PUBKEY
                Represents a DSA public key using a SubjectPublicKeyInfo structure.

        DSAPublicKey, DSAPrivateKey
                Use a non-standard OpenSSL format and should be avoided; use DSA_PUBKEY, PEM_write_PrivateKey(3), or similar instead.

        RSAPublicKey
                Represents a PKCS#1 RSA public key structure.

        X509_ALGOR
                Represents an AlogrithmIdentifier structure as used in IETF RFC 6960 and elsewhere.

        X509_Name
                Represents a Name type as used for subject and issuer names in IETF RFC 6960 and elsewhere.

        X509_REQ
                Represents a PKCS#10 certificate request.

        X509_SIG
                Represents the DigestInfo structure defined in PKCS#1 and PKCS#7.

——————————————————————————————————————————————————————————————————————


下面查看openssl源码:

在asn1.h文件中发现如下一系列宏定义
/* Declare ASN1 functions: the implement macro in in asn1t.h */# define DECLARE_ASN1_FUNCTIONS(type) DECLARE_ASN1_FUNCTIONS_name(type, type)# define DECLARE_ASN1_ALLOC_FUNCTIONS(type) \        DECLARE_ASN1_ALLOC_FUNCTIONS_name(type, type)# define DECLARE_ASN1_FUNCTIONS_name(type, name) \        DECLARE_ASN1_ALLOC_FUNCTIONS_name(type, name) \        DECLARE_ASN1_ENCODE_FUNCTIONS(type, name, name)# define DECLARE_ASN1_FUNCTIONS_fname(type, itname, name) \        DECLARE_ASN1_ALLOC_FUNCTIONS_name(type, name) \        DECLARE_ASN1_ENCODE_FUNCTIONS(type, itname, name)# define DECLARE_ASN1_ENCODE_FUNCTIONS(type, itname, name) \        type *d2i_##name(type **a, const unsigned char **in, long len); \        int i2d_##name(type *a, unsigned char **out); \        DECLARE_ASN1_ITEM(itname)# define DECLARE_ASN1_ENCODE_FUNCTIONS_const(type, name) \        type *d2i_##name(type **a, const unsigned char **in, long len); \        int i2d_##name(const type *a, unsigned char **out); \        DECLARE_ASN1_ITEM(name)# define DECLARE_ASN1_FUNCTIONS_const(name) \        DECLARE_ASN1_ALLOC_FUNCTIONS(name) \        DECLARE_ASN1_ENCODE_FUNCTIONS_const(name, name)# define DECLARE_ASN1_ALLOC_FUNCTIONS_name(type, name) \        type *name##_new(void); \        void name##_free(type *a);

/* * Platforms that can't easily handle shared global variables are declared as * functions returning ASN1_ITEM pointers. *//* ASN1_ITEM pointer exported type */typedef const ASN1_ITEM *ASN1_ITEM_EXP (void);/* Macro to obtain ASN1_ITEM pointer from exported type */#  define ASN1_ITEM_ptr(iptr) (iptr())/* Macro to include ASN1_ITEM pointer from base type */#  define ASN1_ITEM_ref(iptr) (iptr##_it)#  define ASN1_ITEM_rptr(ref) (ref##_it())#  define DECLARE_ASN1_ITEM(name) \        const ASN1_ITEM * name##_it(void);

然后在asn1.h、cms.h、pkcs12.h、pkcs7.h、x509.h中发现很多关于DECLARE_ASN1_FUNCTIONS的调用,例如:
DECLARE_ASN1_FUNCTIONS(ASN1_BIT_STRING)DECLARE_ASN1_FUNCTIONS(ASN1_INTEGER)...DECLARE_ASN1_FUNCTIONS(CMS_ContentInfo)DECLARE_ASN1_FUNCTIONS(CMS_ReceiptRequest)...DECLARE_ASN1_FUNCTIONS(PKCS12)DECLARE_ASN1_FUNCTIONS(PKCS12_MAC_DATA)...DECLARE_ASN1_FUNCTIONS(PKCS7_ENCRYPT)DECLARE_ASN1_FUNCTIONS(PKCS7)...DECLARE_ASN1_FUNCTIONS(X509_NAME)DECLARE_ASN1_FUNCTIONS(X509_CINF)DECLARE_ASN1_FUNCTIONS(X509)...

对于DECLARE_ASN1_FUNCTIONS(X509),经过宏扩展后,变成如下:
X509 *d2i_X509(X509 **a, const unsigned char **in, long len);int i2d_X509(X509 *a, unsigned char **out);const ASN1_ITEM * X509_it(void);X509 *X509_new(void); \void X509_free(X509 *a);


定义结束后,下面说函数实现。其次,在asn1t.h中发现如下定义:
/* Macro to implement standard functions in terms of ASN1_ITEM structures */# define IMPLEMENT_ASN1_FUNCTIONS(stname) IMPLEMENT_ASN1_FUNCTIONS_fname(stname, stname, stname)# define IMPLEMENT_ASN1_FUNCTIONS_name(stname, itname) IMPLEMENT_ASN1_FUNCTIONS_fname(stname, itname, itname)# define IMPLEMENT_ASN1_ALLOC_FUNCTIONS(stname) \                IMPLEMENT_ASN1_ALLOC_FUNCTIONS_fname(stname, stname, stname)}# define IMPLEMENT_ASN1_ALLOC_FUNCTIONS_fname(stname, itname, fname) \        stname *fname##_new(void) \        { \                return (stname *)ASN1_item_new(ASN1_ITEM_rptr(itname)); \        } \        void fname##_free(stname *a) \        { \                ASN1_item_free((ASN1_VALUE *)a, ASN1_ITEM_rptr(itname)); \        }# define IMPLEMENT_ASN1_FUNCTIONS_fname(stname, itname, fname) \        IMPLEMENT_ASN1_ENCODE_FUNCTIONS_fname(stname, itname, fname) \        IMPLEMENT_ASN1_ALLOC_FUNCTIONS_fname(stname, itname, fname)# define IMPLEMENT_ASN1_ENCODE_FUNCTIONS_fname(stname, itname, fname) \        stname *d2i_##fname(stname **a, const unsigned char **in, long len) \        { \                return (stname *)ASN1_item_d2i((ASN1_VALUE **)a, in, len, ASN1_ITEM_rptr(itname));\        } \        int i2d_##fname(stname *a, unsigned char **out) \        { \                return ASN1_item_i2d((ASN1_VALUE *)a, out, ASN1_ITEM_rptr(itname));\        }

然后在tasn_typ.c、p12_asn1.c、pk7_asn1.c、x_x509.c中发现很多关于IMPLEMENT_ASN1_FUNCTIONS的调用,例如:
IMPLEMENT_ASN1_FUNCTIONS(ASN1_INTEGER)IMPLEMENT_ASN1_FUNCTIONS(ASN1_ENUMERATED)...IMPLEMENT_ASN1_FUNCTIONS(PKCS12)IMPLEMENT_ASN1_FUNCTIONS(PKCS12_MAC_DATA)...IMPLEMENT_ASN1_FUNCTIONS(PKCS7)IMPLEMENT_ASN1_FUNCTIONS(PKCS7_SIGNED)...IMPLEMENT_ASN1_FUNCTIONS(X509_CINF)IMPLEMENT_ASN1_FUNCTIONS(X509)...


对于IMPLEMENT_ASN1_FUNCTIONS(X509),经过宏扩展后,变成如下:
X509 *X509_new(void){    return (X509 *)ASN1_item_new(X509_it);}void X509_free(X509 *a){    ASN1_item_free((ASN1_VALUE *)a, X509_it);}X509 *d2i_X509(X509 **a, const unsigned char **in, long len){        return (X509 *)ASN1_item_d2i((ASN1_VALUE **)a, in, len, X509_it);}int i2d_X509(X509 *a, unsigned char **out){        return ASN1_item_i2d((ASN1_VALUE *)a, out, X509_it);}

经过上面的分析,我们已经很清楚了i2d和d2i系列的函数的定义和实现过程。但对const ASN1_ITEM * name##_it(void)的实现还清楚。下面说其实现过程:
首先,我们在asn1t.h中找到:
/* Macros for start and end of ASN1_ITEM definition */#  define ASN1_ITEM_start(itname) \        const ASN1_ITEM * itname##_it(void) \        { \                static const ASN1_ITEM local_it = {#  define ASN1_ITEM_end(itname) \                }; \        return &local_it; \        }
然后去寻找local_it。再asn1t.h中找到,
# define ASN1_SEQUENCE_END_ref(stname, tname) \        ;\        ASN1_ITEM_start(tname) \                ASN1_ITYPE_SEQUENCE,\                V_ASN1_SEQUENCE,\                tname##_seq_tt,\                sizeof(tname##_seq_tt) / sizeof(ASN1_TEMPLATE),\                &tname##_aux,\                sizeof(stname),\                #stname \        ASN1_ITEM_end(tname)
然后在x_x509.c中发现了ASN1_SEQUENCE_END_ref的使用,
ASN1_SEQUENCE_ref(X509, x509_cb, CRYPTO_LOCK_X509) = {        ASN1_SIMPLE(X509, cert_info, X509_CINF),        ASN1_SIMPLE(X509, sig_alg, X509_ALGOR),        ASN1_SIMPLE(X509, signature, ASN1_BIT_STRING)} ASN1_SEQUENCE_END_ref(X509, X509)
查看ASN1_ITEM结构体定义:
/* This is the actual ASN1 item itself */struct ASN1_ITEM_st {    char itype;                 /* The item type, primitive, SEQUENCE, CHOICE                                 * or extern */    long utype;                 /* underlying type */    const ASN1_TEMPLATE *templates; /* If SEQUENCE or CHOICE this contains                                     * the contents */    long tcount;                /* Number of templates if SEQUENCE or CHOICE */    const void *funcs;          /* functions that handle this type */    long size;                  /* Structure size (usually) */# ifndef NO_ASN1_FIELD_NAMES    const char *sname;          /* Structure name */# endif};

所以:
const ASN1_ITEM *X509_it(void){    static const ASN1_ITEM local_it = {        ASN1_ITYPE_SEQUENCE,        V_ASN1_SEQUENCE,        X509_seq_tt,        sizeof(X509_seq_tt) / sizeof(ASN1_TEMPLATE),        &X509_aux,        sizeof(X509),        "X509"    };    return &local_it;}




1 0
原创粉丝点击