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

时间:2011-04-07 14:03:46

标签: c parsing openssl x509 asn.1

我正在尝试在C(OpenSSL)中创建X509代理证书请求(ProxyCertInfo Extension 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请求中了,所以我相对肯定我唯一的问题是这个特定扩展的数据结构的格式化。

1 个答案:

答案 0 :(得分:5)

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

如果您想了解一些理论,我发现的最佳参考是A Layman's Guide to a Subset of ASN.1, BER, and 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 政策=“测试” 从政策长度开始,我将从内到外工作是04 这是一个可打印的字符串,因此class = 00(universal)primitive / construct = 0(primitive)和tag-number = 0x13 头字节是0x13 length = 4,所以长度字节是0x04 ascii中的“test”是0x74 0x65 0x73 0x74 策略的编码是0x13 0x04 0x74 0x65 0x73 0x74

id-ppl-anyLanguage是一个对象标识符,所以class = 00(通用)primitive / construct = 0(primitive)和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 length = lengthof(policyLanguage)+ lengthof(策略) =(lengthof(policyLanguage headers)+ lengthof(policyLanguage content))+(lengthof(policyheaders)+ lengthof(policy content)) =(2 + 4)+(2 + 18) = 6 + 20 = 26 长度= 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(通用)原语/ construct = 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 content))+(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