X.509v3 ASN.1到C数据结构

我正在尝试在C(OpenSSL)中创建X509代理证书请求(ProxyCertInfo扩展RFC3820 ),但我无法弄清楚应该如何定义ProxyCertInfo的数据结构。 RFC定义ASN.1语言如下:

PKIXproxy88 { iso(1) identified-organization(3) dod(6) internet(1) security(5) mechanisms(5) pkix(7) id-mod(0) proxy-cert-extns(25) } DEFINITIONS EXPLICIT TAGS ::= BEGIN -- EXPORTS ALL -- -- IMPORTS NONE -- -- PKIX specific OIDs id-pkix OBJECT IDENTIFIER ::= { iso(1) identified-organization(3) dod(6) internet(1) security(5) mechanisms(5) pkix(7) } -- private certificate extensions id-pe OBJECT IDENTIFIER ::= { id-pkix 1 } -- Locally defined OIDs -- The proxy certificate extension id-pe-proxyCertInfo OBJECT IDENTIFIER ::= { id-pe 14 } -- Proxy certificate policy languages id-ppl OBJECT IDENTIFIER ::= { id-pkix 21 } -- Proxy certificate policies languages defined in id-ppl-anyLanguage OBJECT IDENTIFIER ::= { id-ppl 0 } id-ppl-inheritAll OBJECT IDENTIFIER ::= { id-ppl 1 } id-ppl-independent OBJECT IDENTIFIER ::= { id-ppl 2 } -- The ProxyCertInfo Extension ProxyCertInfoExtension ::= SEQUENCE { pCPathLenConstraint ProxyCertPathLengthConstraint OPTIONAL, proxyPolicy ProxyPolicy } ProxyCertPathLengthConstraint ::= INTEGER ProxyPolicy ::= SEQUENCE { policyLanguage OBJECT IDENTIFIER, policy OCTET STRING OPTIONAL } END 

我查看了OpenSSL的非常有限的文档,但无法找到如何将其解析为C数据结构。 我还阅读了http://www.openssl.org/docs/apps/asn1parse.html#,因为它解释了如何将解析器用于命令行工具,而不是如何将它包含在您自己的源代码中。

我已经设法包含X509请求的其他扩展,所以我相对确定我唯一的问题是这个特定扩展的数据结构的格式。

我认为您的问题是“我如何将数据格式化为ProxyCertInfoExtension?” 如果这不正确请告诉我。

如果你想了解一些理论,我发现的最好的参考是A Layman的ASN.1,BER和DER子集指南 。

您问题中的代码部分是对ProxyCertInfoExtension的数据如何编码的描述。 将编码描述看作可以由解析器生成器处理的语法,就像yacc将语法作为输入并输出C代码一样。 实际上至少有一个ASN.1解析器生成器存在于ASN1C中

ASN.1编码可以是可变大小的。 数据以outtermost或顶级ASN.1编码开头。 每个ASN.1编码本身可以包含一个或多个ASN.1编码。 这样ASN.1就是递归的。

ASN.1编码由标头,长度,可选内容和可选端组成。

 ASN.1 encoding { Header length [content] [end] } 

标题由Class类型,Primitive / Constructed位和Tag-Number组成。 如果Tag-Number大于63,则Tag-Number将跨越多个字节。 这意味着标头可以是一个字节长或多个字节长,具体取决于Tag-Number的值。 标头是字节对齐的,这意味着总是长度为一些字节。

 ASN.1 header { ClassType Primitive/Constructed Tag-number } 

长度也可以是一个字节到多个字节长,具体取决于长度的值。 同样,长度是字节对齐的。

Class类型和Tag-Number告诉您内容中编码的内容。

outtermost编码通常是序列或集合,它们是复合基本类型。 在您的编码中,outtermost编码是ProxyCertInfoExtension,它是可选的ProxyCertPathLengthConstraint和ProxyPolicy的序列。 您的编码如下所示:

 ProxyCertInfoExtension { [ProxyCertPathLengthConstraint] ProxyPolicy } 

回顾编码规则,ProxyCertPathLengthConstraint只是一个整数,所以你的编码实际上是:

 ProxyCertInfoExtension { [Integer] ProxyPolicy } 

编码规则将ProxyPolicy定义为policyLanguage和可选策略的序列。 所以我们可以更新编码表示,如下所示:

 ProxyCertInfoExtension { [Integer] { policyLanguage [policy] } } 

编码规则将策略指定为Octet字符串(只是一些字节数)。 因此进一步简化会产生:

 ProxyCertInfoExtension { [Integer] { policyLanguage [Octet String] } } 

根据对象标识符,编码是以下之一:

 ProxyCertInfoExtension { [Integer] { id-ppl-anyLanguage [Octet String] } } ProxyCertInfoExtension { [Integer] { id-ppl-inheritAll [Octet String] } } ProxyCertInfoExtension { [Integer] { id-ppl-independent [Octet String] } } 

我将尝试一个未经测试的示例ProxyCertPathLengthConstraint = 64 policyLanguage = id-ppl-anyLanguage policy =“test”我将在内部工作,从策略长度开始是04这是一个可打印的字符串,所以class = 00(universal)primitive / construct = 0(原始)和tag-number = 0x13头字节是0x13长度= 4,所以长度字节是0x04“测试”ascii是0x74 0x65 0x73 0x74策略的编码是0x13 0x04 0x74 0x65 0x73 0x74

id-ppl-anyLanguage是一个对象标识符,所以class = 00(通用)原语/构造= 0(原始)和tag-number = 0x06,标题字节是0x06,id-ppl-anyLanguage的值是“1.3.6.1.5.5 .7.21.0“长度= 18,所以长度字节为0x12”1.3.6.1.5.5.7.21.0“= 0x11 0x0E 0x03 0x0E 0x16 0x0E 0x11 0x0E 0x15 0x0E 0x15 0x0E 0x17 0x0E 0x12 0x11 0x0E 0x10 policyLanguage的编码为0x06 0x12 0x11 0x0E 0x03 0x0E 0x16 0x0E 0x11 0x0E 0x15 0x0E 0x15 0x0E 0x17 0x0E 0x12 0x11 0x0E 0x10

proxyPolicy是一个序列,所以class = 00(通用)原语/构造= 0(原始)和tag-number = 0x10头字节是0x10长度= lengthof(policyLanguage)+ lengthof(策略)=(lengthof(policyLanguage headers)+ lengthof(policyLanguage content))+(lengthof(policyheaders)+ lengthof(策略内容))=(2 + 4)+(2 + 18)= 6 + 20 = 26 length = 26,所以长度字节为0x1A,内容为policyLanguage其次是policy = 0x06 0x12 0x11 0x0E 0x03 0x0E 0x16 0x0E 0x11 0x0E 0x15 0x0E 0x15 0x0E 0x17 0x0E 0x12 0x11 0x0E 0x10 0x13 0x04 0x74 0x65 0x73 0x74 proxyPolicy的编码是0x10 0x1A 0x06 0x12 0x11 0x0E 0x03 0x0E 0x16 0x0E 0x11 0x0E 0x15 0x0E 0x15 0x0E 0x17 0x0E 0x12 0x11 0x0E 0x10 0x13 0x04 0x74 0x65 0x73 0x74

ProxyCertPathLengthConstraint是一个整数,所以class = 00(通用)原语/构造= 0(原始)和tag-number = 0x02,头字节是0x02长度= 0x01内容= 0x40编码是0x02 0x01 0x40

ProxyCertInfoExtension是一个SEQUENCE,所以class = 00(通用)原语/ construct = 0(原始)和tag-number = 0x10,头字节是0x10,length = lengthof(pCPathLenConstraint)+ lengthof(proxyPolicy)= lengthof(pCPathLenConstraint headers)+ lengthof (pCPathLenConstraint内容))+(lengthof(proxyPolicy headers)+ lengthof(proxyPolicy content))=(2 + 1)+(2 + 26)= 3 + 28 = 31 = 0x1F content = pCPathLenConstraint后跟proxyPolicy = 0x02 0x01 0x40 0x10 0x1A 0x06 0x12 0x11 0x0E 0x03 0x0E 0x16 0x0E 0x11 0x0E 0x15 0x0E 0x15 0x0E 0x17 0x0E 0x12 0x11 0x0E 0x10 0x13 0x04 0x74 0x65 0x73 0x74编码为0x10 0x1F 0x02 0x01 0x40 0x10 0x1A 0x06 0x12 0x11 0x0E 0x03 0x0E 0x16 0x0E 0x11 0x0E 0x15 0x0E 0x15 0x0E 0x17 0x0E 0x12 0x11 0x0E 0x10 0x13 0x04 0x74 0x65 0x73 0x74