延续很久之前的研究。
例如static int TS_RESP_sign ()中调用的
i2d_TS_TST_INFO_bio()
这个函数。我们已经知道是通过在
crypto/ts/ts_asn1.c
中定义的
IMPLEMENT_ASN1_FUNCTIONS_const(TS_TST_INFO)
这个宏进行的实现,其过程如下:
crypto/asn1/asn1t.h
中定义:
#define IMPLEMENT_ASN1_FUNCTIONS ( stname) IMPLEMENT_ASN1_FUNCTIONS_fname(stname, stname, stname)
#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));\ }
这样就达到了目的。 那么,那个ASN1_ITEM_rptr()又是在哪里实现的呢?且看crypto/ts/ts_asn1.c
中还有一个定义:
ASN1_SEQUENCE(TS_TST_INFO) = { ASN1_SIMPLE(TS_TST_INFO, version, ASN1_INTEGER), ASN1_SIMPLE(TS_TST_INFO, policy_id, ASN1_OBJECT), ASN1_SIMPLE(TS_TST_INFO, msg_imprint, TS_MSG_IMPRINT), ASN1_SIMPLE(TS_TST_INFO, serial, ASN1_INTEGER), ASN1_SIMPLE(TS_TST_INFO, time, ASN1_GENERALIZEDTIME), ASN1_OPT(TS_TST_INFO, accuracy, TS_ACCURACY), ASN1_OPT(TS_TST_INFO, ordering, ASN1_FBOOLEAN), ASN1_OPT(TS_TST_INFO, nonce, ASN1_INTEGER), ASN1_EXP_OPT(TS_TST_INFO, tsa, GENERAL_NAME, 0), ASN1_IMP_SEQUENCE_OF_OPT(TS_TST_INFO, extensions, X509_EXTENSION, 1) } ASN1_SEQUENCE_END(TS_TST_INFO)
crypto/asn1/asn1t.h
中定义:
#define ASN1_SEQUENCE(tname) \
static const ASN1_TEMPLATE tname##_seq_tt[]
#define ASN1_SEQUENCE_END(stname) ASN1_SEQUENCE_END_name(stname, stname)
#define ASN1_SEQUENCE_END_name(stname, tname) \
;\
ASN1_ITEM_start(tname) \
ASN1_ITYPE_SEQUENCE,\
V_ASN1_SEQUENCE,\
tname##_seq_tt,\
sizeof(tname##_seq_tt) / sizeof(ASN1_TEMPLATE),\
NULL,\
sizeof(stname),\
#stname \
ASN1_ITEM_end(tname)
#define ASN1_ITEM_start(itname) \
OPENSSL_GLOBAL const ASN1_ITEM itname##_it = {
#define ASN1_ITEM_end(itname) \
};
这样宏展开后的内容是:
const ASN1_ITEM TS_TST_INFO_it = {
1,
16
TS_TST_INFO_seq_tt,
sizeof( TS_TST_INFO_seq_tt) / sizeof(ASN1_TEMPLATE_st),
NULL,
sizeof(TS_TST_INFO),
TS_TST_INFO
};
而
asn1t.h
中还定义了:
#define ASN1_ITEM_ref ( iptr) (&(iptr##_it))
这样这个宏的意思就很清楚了。
当然,对于宏
ASN1_SIMPLE
等,我并没有进行解释,就留给未来的我了。
--------------------------
继续看。
i2d_TS_TST_INFO_bio()
函数的定义是这样的:
int i2d_TS_TST_INFO_bio(BIO *bp, TS_TST_INFO *a)
{
return ASN1_i2d_bio_of_const(TS_TST_INFO, i2d_TS_TST_INFO, bp, a);
}
crypto/asn1/asn1.h
中:
#define ASN1_i2d_bio_of_const(type,i2d,out,x) \
(ASN1_i2d_bio(CHECKED_I2D_OF(const type, i2d), \
out, \
CHECKED_PTR_OF(const type, x)))
到此可以先不继续展开。可以看见,函数
ASN1_i2d_bio_of_const()
中有一个参数
i2d_TS_TST_INFO
,这是一个函数指针,声明如下:
int i2d_TS_TST_INFO ( const TS_TST_INFO *
a, unsigned char **
pp )
而定义就在刚才
IMPLEMENT_ASN1_ENCODE_FUNCTIONS_fname()
宏中。
--------------------
回过头来,继续尝试展开宏
ASN1_SEQUENCE(TS_TST_INFO)
。
#define ASN1_SIMPLE(stname, field, type) ASN1_EX_TYPE(0,0, stname, field, type)
#define ASN1_EX_TYPE(flags, tag, stname, field, type) { \
(flags), (tag), offsetof(stname, field),\
#field, ASN1_ITEM_ref(type) }
#define ASN1_OPT(stname, field, type) ASN1_EX_TYPE(ASN1_TFLG_OPTIONAL, 0, stname, field, type)
#define ASN1_EXP_OPT(stname, field, type, tag) ASN1_EXP_EX(stname, field, type, tag, ASN1_TFLG_OPTIONAL)
#define ASN1_EXP_EX(stname, field, type, tag, ex) \
ASN1_EX_TYPE(ASN1_TFLG_EXPLICIT | ex, tag, stname, field, type)
#define ASN1_IMP_SEQUENCE_OF_OPT(stname, field, type, tag) \
ASN1_IMP_EX(stname, field, type, tag, ASN1_TFLG_SEQUENCE_OF|ASN1_TFLG_OPTIONAL)
#define ASN1_IMP_EX(stname, field, type, tag, ex) \
ASN1_EX_TYPE(ASN1_TFLG_IMPLICIT | ex, tag, stname, field, type)
#ifndef offsetof
# define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#endif
#define ASN1_ITEM_ref(iptr) (&(iptr##_it))
想象一下展开后的情形:
static const ASN1_TEMPLATE TS_TST_INFO_seq_tt[] = {
{ 0, 0, offsetof(TS_TST_INFO, version), “version”, ASN1_ITEM_ref(ASN1_INTEGER) },
{ 0, 0, offsetof(TS_TST_INFO, policy_id), “policy_id”, ASN1_ITEM_ref(ASN1_OBJECT) },
..............
};
PS.
要注意一个宏技巧:
AB##CD
结果是
ABCD
,而
#AB
的结果是”
AB”
。
再展开
IMPLEMENT_ASN1_ENCODE_FUNCTIONS_fname( TS_TST_INFO, TS_TST_INFO, TS_TST_INFO)
:
TS_TST_INFO *d2i_ TS_TST_INFO( TS_TST_INFO **a, const unsigned char **in, long len)
{ return ( TS_TST_INFO
*)ASN1_item_d2i((ASN1_VALUE **)a, in, len, ASN1_ITEM_rptr( TS_TST_INFO
)); } int i2d_ TS_TST_INFO
(stname *a, unsigned char **out) \ { \ return ASN1_item_i2d((ASN1_VALUE *)a, out, ASN1_ITEM_rptr( TS_TST_INFO
));\
}
关于这个ASN1_VALUE,crypto/asn1/asn1.h中的声明是: /* This is just an opaque pointer */ typedef struct ASN1_VALUE_st ASN1_VALUE; 而没有关于
ASN1_VALUE_st
的定义。注释的意思是,这是一个“不透明的指针”。那这是什么意思呢?
带着这个疑问,我驾起谷歌百度,搜寻了一番。在这里找到了答案: opaque直译的意思是不透明的,
C
语言中允许通过
typedef
申明一个抽象的结构体类型,如上例所示,你无需定义
struct __opaque
的具体实现,就能在其他函数的声明中使用该数据类型的
指针
。注意,只能是指针,如果是
void foo(ASN1_VALUE *dir)
,系统就会提示
error: dir has incomplete type
。
也就是说,
ASN1_VALUE*
这个指针只是一个空架子,为的是让
TS_TST_INFO*
、
X509*
、
PKCS7*
等任意类型的指针都能够装进去。而子程序中是根据
ASN1_ITEM TS_TST_INFO_it
里面所装的”建筑施工图“来识别出
struct TS_TST_INFO
的结构和各个部分的特点,并进行
ASN1
编码的施工的。
参与”建筑施工图“的宏还有下面几个:
#define IMPLEMENT_ASN1_TYPE ( stname) IMPLEMENT_ASN1_TYPE_ex(stname, stname, 0)
#define IMPLEMENT_ASN1_TYPE_ex(itname, vname, ex) \
ASN1_ITEM_start(itname) \
ASN1_ITYPE_PRIMITIVE, V_##vname, NULL, 0, NULL, ex, #itname \
ASN1_ITEM_end(itname)
例如
ASN1_INTEGER
、
ASN1_UTC
等就是使用这个宏。这个宏声明的是所有底层结构,制造出来的是砖和瓦。所有的砖和瓦组合起来,才会形成类似
TS_TST_INFO
这样的高楼大厦。
除了
IMPLEMENT_ASN1_TYPE()
宏,还有
DECLARE_ASN1_ITEM
宏,
IMPLEMENT_COMPAT_ASN1
宏,都定义在
crypto/asn1/asn1t.h
中。
----------------------
OpenSSL
的作者在制作
i2d_xxx
和
d2i_xxx
部分的设计时还是很苦心孤诣的。使用上述的宏可以使
asn1
代码与结构体之间的转换函数的声明与实现全部模板化,像
openssl ts
的作者就没有花多少时间。
C
语言尽管没有对象的继承、封装、模板等特性,但依靠编写者的智慧和语言的精巧,同样能够达到类似的效果。