【问题标题】:X.509v3 ASN.1 to C datastructsX.509v3 ASN.1 到 C 数据结构
【发布时间】:2011-04-07 14:03:46
【问题描述】:

我正在尝试在 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 请求中包含其他扩展,所以我比较确定我唯一的问题是这个特定扩展的数据结构的格式。

【问题讨论】:

    标签: c parsing openssl x509 asn.1


    【解决方案1】:

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

    如果您想了解一些理论,我找到的最佳参考是A Layman's Guide to a Subset of ASN.1, BER, and DER

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

    ASN.1 编码可能具有可变大小。数据以最外层或顶级 ASN.1 编码开始。每个 ASN.1 编码可能在其内部包含一个或多个 ASN.1 编码。这样 ASN.1 是递归的。

    ASN.1 编码由标头、长度、可选内容和可选结尾组成。

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

    标头由一个类类型、一个原始/构造位和一个标记号组成。如果标记号大于 63,则标记号将跨越多个字节。这意味着标题可能是一个字节长或多个字节长,具体取决于标记号的值。标头是字节对齐的,这意味着它总是一些字节长。

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

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

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

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

    ProxyCertInfoExtension { [ProxyCertPathLengthConstraint] ProxyPolicy }
    

    回头看编码规则,ProxyCertPathLengthConstraint只是一个整数,所以你的编码真的是:

    ProxyCertInfoExtension { [Integer] ProxyPolicy }
    

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

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

    编码规则将策略指定为八位字节字符串(只是一些字节数)。所以进一步简化产生:

    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/constructed=0(primitive) and tag-number=0x13 头字节为 0x13 长度=4,所以长度字节为0x04 ascii 中的“测试”是 0x74 0x65 0x73 0x74 策略的编码是 0x13 0x04 0x74 0x65 0x73 0x74

    id-ppl-anyLanguage 是一个对象标识符,所以 class=00(通用)primitive/constructed=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(universal)primitive/constructed=0(primitive) and tag-number=0x10 头字节为 0x10 长度=长度(策略语言)+长度(策略) = (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 7465 0x73 0 proxyPolicy 的编码是 0x10 0x1A 0x06 0x12 0x11 0x0E 0x03 0x0E 0x16 0x0E 0x11 0x0E 0x15 0x0E 0x15 0x0E 0x17 0x0E 0x12 0x11 0x0E 0x10 0x130370x4 0x740

    ProxyCertPathLengthConstraint 是一个整数,所以 class=00(universal) primitive/constructed=0(primitive) and tag-number=0x02 头字节为 0x02 长度=0x01 内容=0x40 编码为 0x02 0x01 0x40

    ProxyCertInfoExtension 是一个 SEQUENCE 所以 class=00(universal) primitive/constructed=0(primitive) and tag-number=0x10 头字节为 0x10 长度 = 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 0x12 0x11 0x0 x110 0x11 0x0 x15 0x11 0x0x12 0x12 0x11 0x0x10 0x12 0x11 0x0x10 0x12 0x11 0x0x10 0x12 0x11 0x0x0 0x12 0x11 0x0x0 0x12 0x11 0x0x0e 0x10 0x11 0x0x0 x10 0x11 0x0x0 0x10 0x11 0x0x0 0x10 0x11 0x0_04 0x10 0x11 0x0x04 0x10 0x11 0x0x04 0x10 0x11 0x04 0x10 0x11 0x04 0x74 0x65 0x73 0x74 编码为0x10 0x1f 0x02 0x01 0x06 0x12 0x11 0x0e 0x03 0x11 0x0e 0x12 0x11 0x0e 0x12 0x11 0x0e 0x12 0x11 0x0e 0x12 0x11 0x0e 0x12 0x11 0x04 0x10 0x11 0x04 0x74 0x11 0x04 0x74 0x11 0x04 0x74 0x65 0x73 0x74

    【讨论】:

    • 感谢您提供详尽的回答,并对迟到的反馈表示歉意(项目继续进行,现在才回到这部分)。正如我后来理解的那样,这里的问题可以以不同的方式看待,因为 OpenSSL 提供了从内部结构转换为 DER(i2d 函数)的函数,但是我现在的问题是 i2d 函数似乎只适用于 ProxyCertInfoExtension 之外的其他扩展.我稍后会修改问题以坚持这一点。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-09-16
    • 1970-01-01
    • 2022-01-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多