openssl源码之ASN1从找不到X509_new的定义说起

本文解析了OpenSSL中X509证书的内部实现原理,介绍了ASN1模块的基本概念及其与证书的关系,并详细阐述了X509_it、X509_CINF_it等对象的定义及作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

       使用si查看openssl源码,找不X509_new的定义。想要知道该函数的定义,还得从ASN1相关部分说起。

       ASN1是规定了一种数字对象的描述方法和标准,定义了诸多的基础类型(INTEGER和BIT STRING),并可以通过这些基础类型构建用户自定义类型,后面讨论的证书类型就是由这些基础类型构建的。DER是一种编码方法,描述了如何将这些类型的对象转换成为二进制,这样这些定义的数据就可以进行传输和存储。

       由于后面的分析中有的宏定义存在不同的分支,这里面暂且假设在编译宏没有定义OPENSSL_EXPORT_VAR_AS_FUNCTION
,后面均以此为准,分析如下:

       首先要提到asn1模块中重要的两个结构体,这两个结构体相当于所有自定义对象的类,如下所示:

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) */
const char *sname; /* Structure name */
};
struct ASN1_TEMPLATE_st {
unsigned long flags; /* Various flags */
long tag; /* tag, not used if no tagging */
unsigned long offset; /* Offset of this field in structure */
const char *field_name; /* Field name */
ASN1_ITEM_EXP *item; /* Relevant ASN1_ITEM or ASN1_ADB */
};

       ASN1_ITEM_st相当于定义了一个抽象的类,对于每一个具体的用户数据,比如证书相关结构,都是属于这种类型类的具体对象,例如X509_it,该对象后面会详细介绍。同时在 ASN1_ITEM_st结构中包含了 ASN1_TEMPLATE_st结构指针,可以理解为一个数组。而ASN1_TEMPLATE_st结构包含了ASN1_ITEM_st 结构(通过宏定义知道typedef const ASN1_ITEM ASN1_ITEM_EXP; ASN1_ITEM_EXP就是ASN1_ITEM 类型,也就是说 ASN1_TEMPLATE_st中的item是一个ASN1_ITEM_st类型)。其本质相当于 ASN1_ITEM_st结构中包含了 ASN1_ITEM_st这种类型的数组。这是一种递归结构,保证了一个大的对象里面可以包含同样类的较小的对象。

       以数字证书为例,x509_it是一个大的 ASN1_ITEM_st结构类型,我们知道证书由证书体,算法以及签名部分组成,因此在其中还包含了X509_CINF_it,X509_ALGOR_it,ASN1_BIT_STRING_it(因为签名是加密的,相当于BIT STRING类型)变量,而这些次一级的对象都存在于ASN1_ITEM x509_itconst ASN1_TEMPLATE *templates;中的。下面具体的详细说明一下:

       在crypto/X509/x_x509.c文件中存在如下的宏定义(这种结构一共有几种,搜索一下)

ASN1_SEQUENCE_ref(X509, x509_cb) = {
ASN1_EMBED(X509, cert_info, X509_CINF),
ASN1_EMBED(X509, sig_alg, X509_ALGOR),
ASN1_EMBED(X509, signature, ASN1_BIT_STRING)
} ASN1_SEQUENCE_END_ref(X509, X509)

展开后如下:

static const ASN1_AUX X509_aux = {NULL, ASN1_AFLG_REFCOUNT, offsetof(X509, references), offsetof(X509, lock), x509_cb, 0};
static const ASN1_TEMPLATE X509_seq_tt[] ={
{ASN1_TFLG_EMBED,0,offsetof(X509,cert_info),”cert_info”, &X509_CINF_it},
{ASN1_TFLG_EMBED,0,offsetof(X509,sig_alg),”sig_alg”, &X509_ALGOR_it},
{ASN1_TFLG_EMBED,0,offsetof(X509,signature),”signature”, &ASN1_BIT_STRING_it},
};
static const ASN1_ITEM X509 _it = {
ASN1_ITYPE_SEQUENCE,
V_ASN1_SEQUENCE,
X509_seq_tt,
sizeof(X509_seq_tt) / sizeof(ASN1_TEMPLATE),
X509_aux,
sizeof(X509),
X509
};

       可以看到上述的宏定义其实定义了三个变量。 X509 _it一个 ASN1_ITEM类型的对象;X509_seq_tt[]表示一个 ASN1_TEMPLATE类型的数组,根据上面的分析,该数组的作用相当于一个容器,用来承载更低一级的ASN1_ITEM对象,例如X509_CINF_it以及 X509_ALGOR_it等。

       当然存在这样一个疑问X509_CINF_it这个对象在哪里?在crypto/X509/x_x509.c文件的开始,有如下的宏:

ASN1_SEQUENCE_enc(X509_CINF, enc, 0) = {
ASN1_EXP_OPT(X509_CINF, version, ASN1_INTEGER, 0),
ASN1_EMBED(X509_CINF, serialNumber, ASN1_INTEGER),
ASN1_EMBED(X509_CINF, signature, X509_ALGOR),
ASN1_SIMPLE(X509_CINF, issuer, X509_NAME),
ASN1_EMBED(X509_CINF, validity, X509_VAL),
ASN1_SIMPLE(X509_CINF, subject, X509_NAME),
ASN1_SIMPLE(X509_CINF, key, X509_PUBKEY),
ASN1_IMP_OPT(X509_CINF, issuerUID, ASN1_BIT_STRING, 1),
ASN1_IMP_OPT(X509_CINF, subjectUID, ASN1_BIT_STRING, 2),
ASN1_EXP_SEQUENCE_OF_OPT(X509_CINF, extensions, X509_EXTENSION, 3)
} ASN1_SEQUENCE_END_enc(X509_CINF, X509_CINF)

       该宏即定义了 X509_CINF_it,同理像 X509_ALGOR_it在crypto/asn1/x_algor.c中有对应宏声明。

ASN1_SEQUENCE(X509_ALGOR) = {
ASN1_SIMPLE(X509_ALGOR, algorithm, ASN1_OBJECT),
ASN1_OPT(X509_ALGOR, parameter, ASN1_ANY)
} ASN1_SEQUENCE_END(X509_ALGOR)

       而最终会第归到ASN1模块定义的最基础的ASN1_BIT_STRING_it 。同样的在crypto/asn1/tasn_typ.c中定义了有如下宏:
IMPLEMENT_ASN1_STRING_FUNCTIONS(ASN1_BIT_STRING),该宏不仅实现了ASN1_BIT_STRING_it对象的定义,同时还实现了操作该对象的四个函数包括d2i_ASN1_BIT_STRING,i2d_ASN1_BIT_STRING,X509_ASN1_BIT_STRING,X509_ASN1_BIT_STRING。当然像ASN1_INTEGER在同样的文件中也是有定义的。

       前面只是说明了X509_it对象的定义,这些对象的意义是ASN1规范所描述的数据类型。asn1模块的意义在于将der编码的数据流转换为C 语言内部定义的结构,或者相反的过程,而上述定义的变量如X509_it正是用来辅助这种转换的过程。例如将经过der编码的数据转化为内部的结构体X509_st,因此需要一些转换的函数。
crypto/X509/x_x509.c中分别定义了IMPLEMENT_ASN1_FUNCTIONS(X509)以及IMPLEMENT_ASN1_FUNCTIONS(X509_CINF)宏表示对应的函数,这个宏展开还是比较简单,其实就是d2i_X509,i2d_X509,X509_new,X509_free四个函数的定义。

       因此可以看到对于复杂的结构如证书,变量的定义和对变量的操作是分开来的。而对于基础的结构ASN1_BIT_STRING则是使用一个宏同时实现了变量的定义和相关函数的操作。

       从X509_new的命名可以看出,这里面从命名方面已经开始向面向对象的C++靠拢了。事实上我也是一直说X509_it是一个对象,C语言确实一种面向过程的语言,但是这里面却有面向对象的思想在其中。

       本文为优快云村中少年原创文章,转载记得加上小尾巴偶,博主链接这里

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

村中少年

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值