新闻  |   论坛  |   博客  |   在线研讨会
13.openssl编程——ASN1库
电子禅石 | 2024-06-19 09:27:30    阅读:7525   发布文章

13.1  ASN1简介
ANS.1(Abstract Syntax Notation One, X.208),是一套灵活的标记语言,他允许定义多种数据类型,从integer、bit string、一类的简单类型到结构化类型,如set和sequence,并且可以使用这些类型构建复杂类型。
DER编码是ANS.1定义的将对象描述数据编码成8位串值的编码规则,他给出了对ANS.1值(对象的类型和值)的唯一编码规则。
 
a  简单类型
                     BIT STRING  任意0、1位串;
                     IA5String      任意IA5(ASCII)字符串;
                     INTEGER   任意一个整数;
                     NULL      空值;
                     OBJECT IDENTIFIER 一个对象标识号(一串整数),标识算法或属性类型等对象;
                     OCTET STRING 8位串;
                     PrintableString       任意可打印字符串;
                     T61String       任意T.61(8位)字符串;
                     UTCTime       一个“协同世界时”或“格林威治标准时(G.M.T)”。
b    结构类型
                     结构类型由组件组成,ANS.1定义了四种结构类型:
                     SEQUENCE                  一个或多个类型的有序排列;
                     SEQUENCE OF            一个给定类型的0个或多个有序排列;
                     SET                             一个或多个类型的无序集合;
                     SET OF                     一个给定类型的0个或多个无序集合。
       c    带标记类型
在一个应用内部区分类型的有效方法是使用标记,标记也同样用于区分一个结构类型内部不同的组件。例如SET或SEQUENCE类型可选项通常使用上下文标记以避免混淆。有两种标记类型的方法:隐式和显式。隐式标记类型是将其它类型的标记改变,得到新的类型。隐式标记的关键字是IMPLICIT。显式标记类型是将其它类型加上一个外部标记,得到新的类型。显式标记的关键字是EXPLICIT。
为了进行编码,隐式标记类型除了标记不同以外,可以视为与其基础类型相同。显式标记类型可以视为只有一个组件的结构类型。
      d    其它类型
类型和值用符号::=表示,符号左边的是名字,右边是类型和值。名字又可以用于定义其它的类型和值。
除了CHOICE类型、ANY类型以外,所有ANS.1类型都有一个标记,标记由一个类和一个非负的标记码组成,当且仅当标记码相同时,ANS.1类型是相同的。也就是说,影响其抽象意义的不是ANS.1类型的名字,而是其标记。
 
13.2 DER编码
DER给出了一种将ASN.1值为8位串的方法。DER编码包含三个部分:
标识(一个或多个8位串):定义值的类和标记码,指出是原始编码还是结构化编码
长度(一个或多个8位串):对于定长编码,指出内容中8位串的个数;对于不定长编码
内容(一个或多个8位串):对于原始定长编码,给出真实值,对于结构化编码,给出个串联结果
内容结束(一个或多个8位串):对于结构化不定长编码,标识内容结束,对于其他编码,无此项。
 
13.3 ANS1基本类型示例
a.ANS1_BOOLEAN
表明ASN1语法中的true和flase。
其中0x01 (表示为BOOLEAN) 0x01(表示后面值的长度) 0x00(值)为本例BOOLEANDER编码。
 
b.ANS1_OBJECT
ANS1中OBJECT表明一个对象,每个对象有一个OID(object id)
其中0x06(表示为OBJECT类型) 0x03(值的长度) 0x55 0x04 0x0A
 
c.ASN1_INTEGER
ANS1中的INTEGER类型用于表示整数。
其内容为:0x30 0x03 0x02(整数) 0x01 (整数值长度)0x55 (整数值)
 
d.ASN1_ENUMERATED
 
e. ASN1_BIT_STRING
0x01 0x02的DER编码:0x03(BIT STRING 类型) 0x02(长度) 0x01 0x02(比特值)
 
f.ANS1_OCTET_STRING
0x04(OCTET STRING) 0x02(长度) 0x01 0x02(值)
 
g.ASN1_PRINGTABLESTRING
可打印字符
0x13(PRINTABLESTRING) 0x04(长度) 0x61 0x73 0x6E 0X31(即"asn1")
 
ASN1_UTCTIME:表示时间
ASN1_GENERALIZEDTIME:表示时间
ASN1_VISIBLESTRING:存放可见字符
ASN1_UTF8STRING:用于存放utf8字符串,存放汉子需要将汉子转换utf8字符串
ASN1_TYPE:用于存放任意类型
 
13.4 openssl的ASN.1库
typedef struct asn1_string_st ASN1_INTGER;
ASN1_INTEGER
ASN1_ENUMERATED
ASN1_BIT_STRING
ASN1_OCTET_STRING
ASN1_PRINTABLESTRING
ASN1_T61STRING
ASN1_IAS5STRING
ASN1_UTCTIME
ASN1_GENERALIZEDTIME
ASN1_TIME
ASN1_GENERALSTRING
ASN1_TIME
ASN1_GENERALSTRING
ASN1_UNIVERSALSTRING
ASN1_BMPSTRING
ASN1_VISIBLESTRING
ASN1_UTF8STRING
ASN1_BOOLEAN
ASN1_NULL
 
四种基本的函数
new:用于生成一个新的数据结构
free:用于释放该结构
i2d:用于将该内部数据结构转换成DER编码
d2i:用于将DER编码转换成内部数据结构
 
ASN1_INTEGER_ASN1_INTEGER_new(void);
void *ASN1_INTEGER_free(ASN1_INTEGER *a)
ASN1_INTEGER *d2i_ASN1_INTEGER(ASN1_INTEGER **a, unsigned char **in, long ,len)
int i2d_ASN1_INTEGER(ASN1_INTEGER *a, unsigned char **out);
long ASN1_INTEGER_get(ASN1_INTEGER *a)
int ASN1_INTEGER_set(ASN1_INTEGER *a, long v)
 
13.5 用openssl的ASN.1库DER编解码
当采用openssl的ASN.1库编码一个asn.1定义结构的时候,需要采用如下步骤
a.用ASN.1语法定义内部数据结构,并声明函数
所谓内部数据结构,指的是openssl中用基本的数据类型按照ASN.1语法数据结构
以x509v4中正数有效期为例,正数有效期定义如下:
AttCertValidityPeriod::= SEQUENCE
{
notBeforeTime GeneralizedTime,
notAfterTime GenerailizedTime,
}
 
我们定义相应内部数据结构
typedef struct X509V4_VALID_st
{
ASN1_GENERALIZEDTIME *notBefore;
ASN1_GENERALIZEDTIME *notAfter;
} X509V4_VALID;
DECLARE_ASN1_FUNCTIONS(X509V4_VALID)
其中最后一行用于定义四个函数
X509V4_VALID *X509V4_VALID_new(void);
void *X509V4_VALID_free(X509V4_VALID *a);
X509V4_VALID *d2i_ASN1_INTEGER(X509V4_VALID **a, unsgined char **in, long len);
 
b. 实现内部数据结构的四个基本函数
实现内部数据结构的基本函数,是通过一系列的红来实现的。定义的模式如下,定义的模式如下,以属性证书有效期为例,
/*X509V4_VALID*/
ASN1_SEQUENCE(X509V4_VALID) =
{
ASN1_SIMPLE(X509V4_VALID, notBefore, ASN1_GENERALIZEDTIME),
ASN1_SIMPLE(X509V4_VALID, notAfter, ASN1_GENERALIZEDTIME)
} ASN1_SEQUNCE_END(X509V4_VALID)
IMPLEMENT_ASN1_FUNCTIONS(X509V4_VALID)
这样通过宏实现了一个asn.1定义结构的最基本的四个函数
 
13.6 Openssl的ASN.1宏
openssl中ASN.1宏用来定义某种内部数据结构以及这种结构如何编码,部分宏定义说明如下
a.DECLARE_ASN1_FUNCTIONS
用于声明一个内部数据结构的四个基本函数,一般可以在头文件中定义。
b.IMPLEMENT_ASN1_FUNCTIONS
用于实现一个数据结构的四个基本函数
c.ASN1_SEQUENCE
用于SEQUENCE,表明下面的编码是一个SEQUENCE.
d.ASN1_CHOICE
表明下面的编码是选择其中一项,为CHOICE类型
e.ASN1_SIMPLE
用于简单类型或结构类型,并且是必须项。
f.ANS1_OPT
用于可选项,表明asn.1语法中,本项可选的。
g.ANS1_EXP_OPT
用于显示标记,表明asn.1语法中,本项是显示类型,并且是可选的。
h.ASN1_EXP
用于显示标记,表明asn.1语法中,本项是显示标记
i.ASN1_IMP_SEQUENCE_OF_OPT
用于隐示标记,表明asn.1语法中,本项是一个SEQUENCE序列,为隐的。
j.ASN1_IMP_OPT
用于隐示标记,表明asn.1语法中,本想是隐示类型,并且是可选的。
k.ASN1_SEQUENCE_END
用于SEQUENCE结束
l.ASN1_CHOICE_END
用于结束CHOICE类型。
 
13.7 ASN1常用函数
ANS1的基本数据类型如下函数:new, free, i2d, d2i, i2a a2i print set get cmp和dup。
new函数用于分配空间,生成ASN1数据结构
free用于释放空间
i2d函数用于ASN1数据结构转换为DER编码
d2i将DER编码转换为ASN1数据结构
i2a将内部结构转换为ASCII码
a2i将ASCII码转换为内部数据结构
set函数用于设置ASN1类型的值
get函数用于获取ASN1类型值
print将ASN1类型打印
cmp用于比较ASN1数据结构
dup函数进行数据结构的拷贝。
 
常用的函数有:
a.int a2d_ASN1_OBJECT(unsigned char *out, int olen, const char *buf, int num)
功能:计算OID的DER编码
b.int a2i_ASN1_INTEGER(BIO *bp, ASN1_INTEGER *bs, char *buf, int size)
功能:将bp中ASC码转换为ASN1_INTEGER,buf存放BIO中ASC码
c.int a2i_ASN1_STRING(BIO *bp, ASN1_STRING *bs, char *buf, int size)
功能:将ASCII码转换为ASN1_STRING
d.unsigned char *asc2uni(const char *asc, int asclen, usngined char **uni, int *unilen)
功能:将ASCII码转换为unicode
e.int ASN1_BIT_STRING_get_bit(ASN1_BIT_STRING *a, int n)
功能:本函数根据n获取比特位上的值
f.ASN1_BIT_STRING_set
设置ASN1_BIT_STRING的值,他调用ASN1_STRING_set函数
g.void *ASN1_d2i_bio(void *(xnew)(void), d2i_of_void *d2i, BIO *in, void **x)
对bio的数据DER解码,xnew无意义,d2i为DER解码函数,in为bio数据,x为数据类型,返回值为解码后的结果。
h.void *ANS1_d2i_fp(void *(*xnew)(void), d2i_of_void *d2i, FILE *in, void **x)
将in只想的文件进行DER解码,器内部调用了ASN1_d2i_b函数,用法与ASN1_d2i_b类似。
i.int ASN1_i2d_bio(i2d_of_void *i2d, BIO *out, unsigned char *x)
将ASN1数据结构DER编码,并将结果写入bio
j.int ASN1_i2d_fp(i2d_of_void *i2d, d2i_of_void *d2i, char *x)
ASN1数据复制。x为ASN1内部数据结构,本函数先将x通过i2d将他变成DER编码,然后用d2i在DERb编码结果
k.ASN1_ENUMERATED_set
设置ASN1_ENUMERATED的值
l.ASN1_ENUMERATED_get
获取ASN1_ENUMERTED的值。
m.BIGNUM * ANS1_ENUMERATED_to_BN(ASN1_ENUMERATED *ai, BIGNUM *bn)
将ASN1_ENUMERATED类型转换为BN大数类型。此函数调用BN_bin2bn函数获取bn,如果ai->type表明他在调用BN_set_negative设置bn成负数。
n.int ASN1_parse_dump(BIO *bp, const unsigned char *pp, long len; int indent, int dump)
本函数用于将pp和len指明的DER编码值写在BIO中,其中indent和dump用于设置打印的格式。
o.int ASN1_sign(i2d_of_void *i2d, X509_ALGOR *algor1, X509_LAGOR *algor2, ANS1_BIT_STRING *data, EVP_PKEY *pkey, const EVP_MD *type)
对ASN1数据类型签名。i2d为ASN1数据的DER方法,signature用于存放签名结果,data为ASN1数据指针,pkey指明签名密钥,type为摘要算法,algor1和algor2无用,可全为NULL.签名时,先将ASN1数据DER编码,然后摘要,最后签名运算
p.ASN1_STRING *ASN1_STRING_dup(ASN1_STRING *str)
ASN1_STRING类型拷贝。内部申请空间,需要用户调用ASN1_STRING_free释放该空间
q.int ASN1_STRING_cmp(ASN1_STRING *a, ASN1_STRING *b)
ASN1_STRING比较.ossl_typ.h中绝大多数ASN1基本类型都定义 ASN1_STRING,所以,此函数比较通用。
r.unsigned char *ASN1_STRING_data(ASN1_STRING *x)
获取ASN1_STRING数据存放地址,即ASN1_STRING数据结构中data地址。
s.int ASN1_STRING_set(ASN1_STRING *str, const void *_data, int len)
设置ASN1字符串类型的值。str为ASN1_STRING地址,_data为设置值的首地址,len为被设置值的长度。
t.ASN1_STRING_TABLE *ASN1_STRING_TABLE_get(int nid)
根据nid来查找ASN1_STRING_TABLE表。此函数先查找标准表tbl_standard,再查找扩展表stable。
u.ASN1_STRING *ASN1-STRING_set_by_NID(ASN1_STRING **out, const unsigned char *in , int inlen, int inform, int nid)
根据nid和输入值获取对应的ASN1_STIRNG类型
static const ASN1_STRING_TABLE tbl_standard[] = {
{NID_commonName, 1, ub_common_name, DIRSTRING_TYPE, 0},
{NID_countryName, 2, 2, B_ASN1_PRINTABLESTRING, STABLE_NO_MASK},
{NID_localityName, 1, ub_locality_name, DIRSTRING_TYPE, 0},
{NID_stateOrProvinceName, 1, ub_state_name, DIRSTRING_TYPE, 0},
{NID_organizationName, 1, ub_organization_name, DIRSTRING_TYPE, 0},
{NID_organizationalUnitName, 1, ub_organization_unit_name, DIRSTRING_TYPE,
0},
{NID_pkcs9_emailAddress, 1, ub_email_address, B_ASN1_IA5STRING,
STABLE_NO_MASK},
{NID_pkcs9_unstructuredName, 1, -1, PKCS9STRING_TYPE, 0},
{NID_pkcs9_challengePassword, 1, -1, PKCS9STRING_TYPE, 0},
{NID_pkcs9_unstructuredAddress, 1, -1, DIRSTRING_TYPE, 0},
{NID_givenName, 1, ub_name, DIRSTRING_TYPE, 0},
{NID_surname, 1, ub_name, DIRSTRING_TYPE, 0},
{NID_initials, 1, ub_name, DIRSTRING_TYPE, 0},
{NID_serialNumber, 1, ub_serial_number, B_ASN1_PRINTABLESTRING,
STABLE_NO_MASK},
{NID_friendlyName, -1, -1, B_ASN1_BMPSTRING, STABLE_NO_MASK},
{NID_name, 1, ub_name, DIRSTRING_TYPE, 0},
{NID_dnQualifier, -1, -1, B_ASN1_PRINTABLESTRING, STABLE_NO_MASK},
{NID_domainComponent, 1, -1, B_ASN1_IA5STRING, STABLE_NO_MASK},
{NID_ms_csp_name, -1, -1, B_ASN1_BMPSTRING, STABLE_NO_MASK},
{NID_rfc822Mailbox, 1, ub_rfc822_mailbox, B_ASN1_IA5STRING,
STABLE_NO_MASK},
{NID_jurisdictionCountryName, 2, 2, B_ASN1_PRINTABLESTRING, STABLE_NO_MASK},
{NID_INN, 1, 12, B_ASN1_NUMERICSTRING, STABLE_NO_MASK},
{NID_OGRN, 1, 13, B_ASN1_NUMERICSTRING, STABLE_NO_MASK},
{NID_SNILS, 1, 11, B_ASN1_NUMERICSTRING, STABLE_NO_MASK},
{NID_countryCode3c, 3, 3, B_ASN1_PRINTABLESTRING, STABLE_NO_MASK},
{NID_countryCode3n, 3, 3, B_ASN1_NUMERICSTRING, STABLE_NO_MASK},
{NID_dnsName, 0, -1, B_ASN1_UTF8STRING, STABLE_NO_MASK}
};
v.void ASN1_STRING_set_default_mask(unsigned long mask)
设置ASN1_STRING_set_by_NID函数返回的ASN1_STRING类型。
w.int ASN1_STRING_set_defualt_mask_asc(char *p)
设置ASN1_STRING_set_by_NID函数返回ASN1_STRING类型。字符串p可以的值由:nombstr, pkix\utf8only和defualt
x.int ASN1_STRING_TABLE_add(int nid, long minsize, long maxsize, usngiend long mask, unsigned long flags)
添加扩展ASN1_STRING_TABLE项
y.void ASN1_STRING_TABLE_cleanup(void)
清除用户自建的扩展ASN1_STRING_TBALE表
z.int i2a_ASN1_INTEGER(BIO *bp, ASN1_INTEGER *a)
将整数转换为ASCII码,放在BIO中。
 
a1.int i2a_ASN1_STRING(BIO *bp, ASN1_STRING *a, int type)
type不起作用,将ASN1_STRING转换为ASCII码
b1.OBJ_bsearch
用于从排序好的数据结构地址数组中用二分法查找数据。
c1.OBJ_create
根据oid以及名称信息生成一个你不的object
d1.OBJ_NAME_add
OBJ_NAME_cleanup
OBJ_NAME_get
OBJ_NAME_init
OBJ_NAME_remove
OBJ_NAME_new_index
OBJ_NAME_do_all
OBJ_NAME_do_all_sorted
OBJ_NAME函数用于根据名字获取对称算法或者摘要算法。
e1. int OBJ_new_nid(int num)
此函数将内部的new_nid加num,返回原nid
f1.const char *OBJ_nid2ln(int n)
根据nide得到对象的描述
g1.OBJ_nid2obj
根据nid得到对象
h1.const char *OBJ_nid2sn(int n)
根据nid得到的对象的sn(简称)
i1.OBJ_nid2obj
根据nid得到对象
j1.const char *OBJ_nid2sn(int n)
根据nid得到对象
k1.int OBJ_obj2nid(const ASN1_OBJECT *a)
根据对象获取其nid;
l1 int OBJ_obj2nid(const ASN1_OBJECT *a)
根据对象获取器nid;
m1 OBJ_obj2txt
根据对象获取对象说明或者nid
n1.OBJ_txt2obj
根据sn或者ln得到的对象
 
13.8 属性证书编码
对属性证书(x509v4)编码
typedef struct X509V4_VALID_st
{
ASN1_GENERALIZEDTIME *notBefor;
ASN1_GENERALIZEDTIME *notAfer;
}X509V4_VALID;
DECLARE_ASN1_FUNCTIONS(X509V4_VALID)
 
typedef struct ISSUERSERIAL_st
{
GENERAL_NBAMES *issuer;
ASN1_INTEGER *subjectSN;
ASN1_BIT_STRING *issuerUID;
} ISSUERSERIAL;
DECLARE_ASN1_FUNCTIONS(ISSUERSERIAL)
 
typedef struct OBJDIGEST_st
{
ASN1_ENUMERATE *digestType;
ASN1_OBJECT *otherType;
X509_ALGOR *digestAlg;
ASN1_BIT_STRING *digestBit;
} OBJDIGEST;
DECLARE_ASN1_FUNCTIONS(OBJDIGEST)
 
typedef struct ACHOLDER_st
{
ISSUERSERIAL *baseCertificateID;
GENERAL_NAMES *entiyName
OBJDIGEST *objDigest;
}ACHOLDER;
DECLARE_ASN1_FUNCTIONS(ACHOLDER)
 
typedef struct V2FORM_st
{
GENERAL_NAMES *entiyName;
issuerserial *baseCertificateID;
OBJDIGEST *objDigest;
}V2FORM;
DECLARE_ASN1_FUNCTIONS(V2FORM)
 
typedef struct ACISSUER_st
{
int type;
union
{
V2FORM *v2Form;
}form;
} ACISSUER;
DECLARE_ASN1_FUNCTIONS(ACISSUER)
 
 
ASN1_SEQUENCE(ISSUERSERIAL) = {
asn1_simple(issuerserial, ISSUER, GENERAL_NAMES),
ASN1_SIMPLE(ISSUERSERIAL, subjectSN, ASN1_INTEGER)
ASN1_OPT(ISSUERSERIAL, isserUID, ASN1_BIT_STIRNG)
}ASN1_SEQUENCE_END(ISSUERSERIAL)
IMPLEMENT_ASN1_FUNCTIONS(ISSUERSERIAL)
 
ASN1_SEQUENCE(OBJDIGEST) = {
ASN1_SIMPLE(OBJDIGEST, digestType, ASN1_ENUMERATED),
ASN1_OPT(OBJDIGEST, otherType, ASN1_OBJECT),
ASN1_SIMPLE(OBJDIGEST, digestAlg, X509_ALGOR)
ASN1_SIMPLE(OBJDIGEST, digestBit, ASN1_BIT_STRING)
} ASN1_SEQUENEC_END(OBJDIGEST)
IMPLEMENT_ASN1_FUNCTIONS(OBJDIGEST)
 
ASN1_SEQUENCE(X509V4_ALID) = {
ASN1_SIMPLE(X509V4_VALID, notBefore, ASN1_GENERALIZEDTIME)
ASN1_SIMPLE(X509V4_VALID, notAfer, ASN1_GENERALIZEDTIME)
}IMPLEMENT_ASN1_FUNCTIONS(X509V4_VALID)\
 
ASN1_SEQUENCE(X5409V4_CINF) = {
ASN1_SIMPLE(X509V4_CINF, version, ASN1_INTEGER)
ASN1_SIMPLE(X509V4_CINF, holder, ACHOLDER)
ASN1_SIMPLE(X509V4_CINF, issuer, ACISSUER)
ASN1_SIMPLE(X509V4_CINF, signature, ACISSUER)
ASN1_SIMPLE(X509V4_CINF, serialNumber, ASN1_INTEGER)
ASN1_SIMPLE(X509V4_CINF, X509V4_VALID)
ASN1_SIMPLE(X509V4_CINF,attributes, X509_ATTRIBUTE)
ASN1_SIMPLE(X509V4_CINF, issuerUID, ASN1_BIT_STRING)
ASN1_SIMPLE(X509V4_CINF, EXTENSIONS, x509_extension
}ASN1_SEQUENCE_END(X509V4_CINF)
IMPLEMENT_ASN1_FUNCTIONS(X509V4_CINF)
 
ASN1_SEQUENCE(X509V4) = {
ASN1_SIMPLE(X509V4, cert_info, X509V4_CINF)
ASN1_SIMPLE(X509V4, sig_alg, X509_ALGOR)
ASN1_SIMPLE(X509V4, signature, ASN1_BIT_STRING)
}ASN1_SEQUENCE_END(X5509V4)


*博客内容为网友个人发布,仅代表博主个人观点,如有侵权请联系工作人员删除。

参与讨论
登录后参与讨论
属于自己的技术积累分享,成为嵌入式系统研发高手。
推荐文章
最近访客