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);
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.
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.
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.
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);
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);
/* 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;
}