【问题标题】:retrieve full extension value from certificate从证书中检索完整的扩展值
【发布时间】:2013-04-18 07:33:18
【问题描述】:

我正在使用:java.security.cert.X509Certificate 包。和 java.security.cert.X509CRL;

当我得到扩展值时,例如当 OID=2.5.29.14 时(它是 SubjectKeyIdentifier) cert.getExtensionValue("2.5.29.14"); 我得到这个 byte[] 范围:

[4,22,4,20,5,125,-118,106,-44,108,39,-74,-108,-20,-27,-32,-113,64,-69,125,-8,102 ,-52,-24]

当我在证书中看到时,SubjectKeyIdentifier 从 5 开始

问题 1:这个范围的开头是什么?它是 4 个字节。

当我在 X509CRL 中看到 AuthorityKeyIdentifier(如果 CRL 由该证书签名,则 CRL 的 AuthorityKeyIdentifier == 证书的 SubjectKeyIdentifier)有相同的:

[4,24,48,22,-128,20,5,125,-118,106,-44,108,39,-74,-108,-20,-27,-32,-113,64, -69,125,-8,102,-52,-24] 但开头还有另外 6 个字节。

问题 2:这个范围的开头是什么?它是 6 字节。

还有一个问题:

问题 3:如何解析 ExtensionValue 以便仅获取 Identifier 值。这个 4 和 6 字节是固定的吗?解析的最佳方式是什么?

【问题讨论】:

  • 或者如何使用 bouncycastle 做到这一点?

标签: java certificate ssl-certificate x509certificate bouncycastle


【解决方案1】:

问题 1 的答案: 这些字节是 ASN 1 数据结构的二进制表示。 ASN 1(Abstract Syntaxt Notation One)是 ITU 定义的标准,通常用于 RFC/消息协议中以定义更高级别的数据结构(例如 X.509 证书)。

ASN 1 的基本语法由三元组(标签类型、长度、值)组成。一些 ASN 1 标签允许嵌套元素。在你的情况下,你有一个

ASN 1 OCTET STRING(标签类型 4),长度为 22,其中包含 ASN 1 OCTET STRING(字节数组中的第二个 4),长度为 20。 密钥标识符

问题 2 的答案:AuthorityKeyIdentifier 的定义与 SubjectKeyIdentifier 不同(详情请查看 RFC 5280)。在你的情况下,它是一个

ASN 1 个字节长度为 24 的字符串,其中包含一个 ASN 1 CONSTRUCTED SEQUENCE(标签类型 16 用于 ASN 1 SEQUENCE,标签类型 32 用于 ASN 1 CONSTRUCTED 逻辑上或'red -> 16 + 32 = 48),长度为 22,其中包含 长度为 20 的 ASN 1 上下文特定数据(标签类型 128,将 -128 转换为字节) 密钥标识符

数据结构与 SubjectKeyIdentifier 扩展不同,因为 AuthorityKeyIdentifier 扩展可能由颁发者和用于验证当前证书的证书序列号组成。

在您的情况下,两个键标识符(字节数组的最后 20 个字节)是相等的。因此,您可以使用第一个问题中提到的证书来验证第二个问题中提到的 CRL 的签名(验证防止 CRL 被操纵)。

对问题 3 的回答:我强烈建议不要自己实施 ASN 1。使用诸如 Bouncycastle 之类的库。要正确解析数据结构,您必须使用适当的类,尤其是对于 Bouncycastle,没有便利类可以通过尽力而为的方法确定 ASN 1 结构的类型。然而,这种方法几乎不可能实施。

例如,假设我们有字节数组 [4,4,67,68,45,53] 此数据(ASN 1 OCTET STRING)是否表示:

  • LDAP 消息或
  • JPEG 或
  • 人类可读的字符串或
  • ...?

由于在 ASN 1 上定义的协议数量众多,因此无法确定数据应该代表哪个对象。此外假设所有列出的解释都是可能的(它们不是)应该由通用库选择哪一个?再次假设该数据将是有效的 JPEG 图像和有效的 LDAP 消息。 JPEG 将具有透明度、rgb 颜色等内容。 LDAP 消息具有用于协议操作(BIND 请求、BIND 响应、SEARCH 请求等)的 id 以及更多内容。您想进行一些棘手的位操作以从一种转换为另一种吗?

此外,数据可能代表的东西与我们奇妙的库所猜测的完全不同。不幸的是,由于 TCP 包损坏,数据已损坏,...现在我们的图书馆不能给我们类似的消息

"Bad LDAP message, syntax violated by ..."

因为它不小心将数据解析为完全合法的 JPEG。

要解析显示的数据,例如使用 Bouncycastle(假设版本 1.51):

//retrieve the certificate from somewhere
X509Certificate c = ...;
String oid = Extension.authorityKeyIdentifier.getId();
byte[] extensionValue = c.getExtensionValue(oid);
ASN1OctetString akiOc = ASN1OctetString.getInstance(extensionValue);
AuthorityKeyIdentifier aki = AuthorityKeyIdentifier.getInstance(akiOc.getOctets());

然后就可以调用了

aki.getKeyIdentifier();
aki.getAuthorityCertIssuer();
aki.getAuthorityCertSerialNumber();

用于进一步处理。

【讨论】:

  • @Vogel612:这样更好?我真的可以缩短答案来改进它,但是当它不再是自包含的时候。
  • 如何从证书中的字符串扩展中获取人类可读的字符串?
  • @Sandra:阅读答案应该很清楚。如果你真的有值部分 ASN1OctetString 应该是你的朋友。但是,正如我的回答中所指出的,如果提供的字符串包含完整的扩展名(包括 OID),它会更复杂(因为 ASN1 的一般解析真的很困难)。如果您知道扩展类型,请使用答案中提供的代码,但将其调整为您的扩展。
【解决方案2】:

cert.getExtensionValue("2.5.29.14") 的返回是一个 OCTET STRING 的编码。

在 Bouncy Castle 中,您可以获得实际的编码值

byte[] octets = ASN1OctetString.getInstance(cert.getExtensionValue("2.5.29.14")).getOctets();

对于 SubjectKeyIdentifier,此值将是另一个编码的 OCTET STRING,因此您可以重复该过程(如使用 ASN1OctetString)或使用 SubjectKeyIdentifier.getInstance(octets)。可以对 AuthorityKeyIdentifier 执行相同的过程。

如果您正在做很多此类事情,您可能还想查看 bcpkix 发行版中 org.bouncycastle.cert 中的类。持有者类旨在使此类分析和处理更容易进行。

【讨论】:

  • 他们还不相等。 :-(
  • @user1454674:您的评论可能指出字节数组不同。大卫有点不准确,字节数组由于不同的数据结构而有所不同,正如我的回答中更详细地解释的那样。
  • 如何获取自定义字符串扩展的人类可读字符串?
猜你喜欢
  • 2022-11-22
  • 1970-01-01
  • 1970-01-01
  • 2021-11-29
  • 2014-06-08
  • 2016-12-28
  • 2012-09-11
  • 1970-01-01
  • 2020-09-25
相关资源
最近更新 更多