openssl研究-1

延续很久之前的研究。

例如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_INFOa, 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_VALUEcrypto/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_INTEGERASN1_UTC等就是使用这个宏。这个宏声明的是所有底层结构,制造出来的是砖和瓦。所有的砖和瓦组合起来,才会形成类似TS_TST_INFO这样的高楼大厦。 除了IMPLEMENT_ASN1_TYPE()宏,还有DECLARE_ASN1_ITEM宏,IMPLEMENT_COMPAT_ASN1宏,都定义在crypto/asn1/asn1t.h中。

----------------------

OpenSSL的作者在制作i2d_xxxd2i_xxx部分的设计时还是很苦心孤诣的。使用上述的宏可以使asn1代码与结构体之间的转换函数的声明与实现全部模板化,像openssl ts的作者就没有花多少时间。 C语言尽管没有对象的继承、封装、模板等特性,但依靠编写者的智慧和语言的精巧,同样能够达到类似的效果。

你可能感兴趣的:(软件研究)