使用 BouncyCastle 从 DER 文件解析 AttributeCertificate 时遇到未知标记
Unknown tag encountered parsing AttributeCertificate from DER file with BouncyCastle
我在使用 BouncyCastle Java API.
解析 DER 属性证书时遇到问题
错误
这是我尝试使用的代码。我首先将证书文件读取为名为 stream
的 InputStream,然后尝试将其转换为 Bouncycastle AttributeCertificate
对象:
ASN1InputStream derIn = new ASN1InputStream(stream);
ASN1Sequence seq = (ASN1Sequence) derIn.readObject();
AttributeCertificate cert = AttributeCertificate.getInstance(seq); <-- exception here
ac = new X509AttributeCertificateHolder(cert);
第三行导致 IllegalArgumentException
:
IllegalArgumentException: unknown object in getInstance: org.bouncycastle.asn1.ASN1Integer
at org.bouncycastle.asn1.ASN1Sequence.getInstance(Unknown Source)
at org.bouncycastle.asn1.x509.IssuerSerial.getInstance(Unknown Source)
at org.bouncycastle.asn1.x509.Holder.getInstance(Unknown Source)
at org.bouncycastle.asn1.x509.AttributeCertificateInfo.getInstance(Unknown Source)
...
Bouncycastle 还会抛出一个 IOException
表示遇到 "unknown tag":
java.io.IOException: unknown tag 28 encountered
at org.bouncycastle.asn1.ASN1InputStream.buildObject(Unknown Source)
at org.bouncycastle.asn1.ASN1InputStream.readObject(Unknown Source)
...
分析
我已经链接了我正在尝试解析的证书文件 here。 证书本身是使用 OpenSSL 生成的。
该证书还包括我正在使用的 ABAC 凭据,这是一个简单的字符串:
[some_uuid].experiment_create <- [some_uuid].partner.experiment_create
我查看了 "unknown tag 28",似乎 ASN.1 标签 28 表示一个 UniversalString。我在网上发现 "the UniversalString type models a Unicode character string implicitly serialized into UTF-32 big endian."
这对我来说表明证书中可能存在字符编码问题。但是当我使用 openssl asn1parse
查看证书文件时,它似乎很好:
0:d=0 hl=4 l= 660 cons: SEQUENCE
4:d=1 hl=4 l= 509 cons: SEQUENCE
8:d=2 hl=2 l= 3 cons: cont [ 0 ]
10:d=3 hl=2 l= 1 prim: INTEGER :02
13:d=2 hl=2 l= 1 prim: INTEGER :00
16:d=2 hl=2 l= 13 cons: SEQUENCE
18:d=3 hl=2 l= 9 prim: OBJECT :sha256WithRSAEncryption
29:d=3 hl=2 l= 0 prim: NULL
31:d=2 hl=2 l= 51 cons: SEQUENCE
33:d=3 hl=2 l= 49 cons: SET
35:d=4 hl=2 l= 47 cons: SEQUENCE
37:d=5 hl=2 l= 3 prim: OBJECT :commonName
42:d=5 hl=2 l= 40 prim: UTF8STRING :bf3a72c271f661dae81647a16c1babf3a52da28e
84:d=2 hl=2 l= 30 cons: SEQUENCE
86:d=3 hl=2 l= 13 prim: UTCTIME :170828213103Z
101:d=3 hl=2 l= 13 prim: UTCTIME :270826213103Z
116:d=2 hl=2 l= 51 cons: SEQUENCE
118:d=3 hl=2 l= 49 cons: SET
120:d=4 hl=2 l= 47 cons: SEQUENCE
122:d=5 hl=2 l= 3 prim: OBJECT :commonName
127:d=5 hl=2 l= 40 prim: UTF8STRING :bf3a72c271f661dae81647a16c1babf3a52da28e
169:d=2 hl=3 l= 159 cons: SEQUENCE
172:d=3 hl=2 l= 13 cons: SEQUENCE
174:d=4 hl=2 l= 9 prim: OBJECT :rsaEncryption
185:d=4 hl=2 l= 0 prim: NULL
187:d=3 hl=3 l= 141 prim: BIT STRING
331:d=2 hl=3 l= 183 cons: cont [ 3 ]
334:d=3 hl=3 l= 180 cons: SEQUENCE
337:d=4 hl=3 l= 144 cons: SEQUENCE
340:d=5 hl=2 l= 8 prim: OBJECT :id-aca-group
350:d=5 hl=3 l= 131 prim: OCTET STRING [HEX DUMP]:0C8180626633613732633237316636363164616538313634376131366331626162663361353264613238652E6578706572696D656E745F637265617465203C2D20626633613732633237316636363164616538313634376131366331626162663361353264613238652E706172746E65722E6578706572696D656E745F637265617465
484:d=4 hl=2 l= 31 cons: SEQUENCE
486:d=5 hl=2 l= 3 prim: OBJECT :X509v3 Authority Key Identifier
491:d=5 hl=2 l= 24 prim: OCTET STRING [HEX DUMP]:30168014162E4EF6CD52F37CD2EDDFBEA484E70D6CDE9048
517:d=1 hl=2 l= 13 cons: SEQUENCE
519:d=2 hl=2 l= 9 prim: OBJECT :sha256WithRSAEncryption
530:d=2 hl=2 l= 0 prim: NULL
532:d=1 hl=3 l= 129 prim: BIT STRING
其他程序似乎也能正常工作; openssl x509
提供此输出:
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 0 (0x0)
Signature Algorithm: sha256WithRSAEncryption
Issuer: CN=bf3a72c271f661dae81647a16c1babf3a52da28e
Validity
Not Before: Aug 28 21:31:03 2017 GMT
Not After : Aug 26 21:31:03 2027 GMT
Subject: CN=bf3a72c271f661dae81647a16c1babf3a52da28e
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (1024 bit)
Modulus:
00:c5:d4:35:49:4d:bd:ee:9a:93:51:a4:e1:46:df:
46:c0:1e:f6:b1:85:70:4d:31:2b:20:6f:ab:82:16:
b4:9d:3e:ea:f3:38:53:e2:7b:be:36:37:f3:11:7f:
90:5d:aa:ad:e7:e8:61:3c:46:8d:7a:69:4d:c6:89:
e2:f7:07:d9:3f:b0:5d:f7:ee:40:e5:86:48:7b:4c:
0e:0f:11:0c:96:41:e6:99:02:17:df:4e:60:3d:d0:
42:b5:dc:22:e0:64:6d:ad:17:22:b7:a2:15:ec:dd:
89:c2:b4:58:01:64:d7:db:fe:62:1e:c5:40:0c:e0:
b9:12:7e:fe:4c:31:65:e6:51
Exponent: 65537 (0x10001)
X509v3 extensions:
id-aca-group:
...bf3a72c271f661dae81647a16c1babf3a52da28e.experiment_create <- bf3a72c271f661dae81647a16c1babf3a52da28e.partner.experiment_create
X509v3 Authority Key Identifier:
keyid:16:2E:4E:F6:CD:52:F3:7C:D2:ED:DF:BE:A4:84:E7:0D:6C:DE:90:48
Signature Algorithm: sha256WithRSAEncryption
1e:0f:2a:7a:cf:95:77:0f:5c:48:f3:12:c4:b9:8a:5a:d9:b9:
62:1c:60:0c:a0:13:70:f3:c5:aa:de:6d:6f:92:7f:0d:a2:3b:
c9:bd:cc:45:6c:4b:21:8d:32:81:8b:af:13:6e:a3:96:18:05:
3b:83:fb:8c:3b:2a:d8:87:22:56:9e:4b:1d:06:e6:7f:ba:36:
89:e8:c6:8a:5a:9e:2c:9b:44:5e:19:fe:68:13:12:93:48:df:
f9:34:42:01:d5:62:c1:ca:e4:e2:3b:86:b7:4c:75:ba:60:5b:
c9:f7:68:9a:b0:b5:1c:33:01:5e:77:c0:7c:13:11:e1:09:67:
42:dd
基于这些,我找不到证书有任何明显的错误。我能找到的唯一线索是 ASN1InputStream.java 的 Bouncycastle 源代码块,它抛出了我发现的异常:
// Build an object given its tag and the number of bytes to construct it from.
protected ASN1Primitive buildObject(
int tag,
int tagNo,
int length)
throws IOException
{
...
if (isConstructed)
{
// TODO There are other tags that may be constructed (e.g. BIT_STRING)
switch (tagNo)
{
case OCTET_STRING:
//
// yes, people actually do this...
//
ASN1EncodableVector v = buildDEREncodableVector(defIn);
ASN1OctetString[] strings = new ASN1OctetString[v.size()];
for (int i = 0; i != strings.length; i++)
{
strings[i] = (ASN1OctetString)v.get(i);
}
return new BEROctetString(strings);
case SEQUENCE:
if (lazyEvaluate)
{
return new LazyEncodedSequence(defIn.toByteArray());
}
else
{
return DERFactory.createSequence(buildDEREncodableVector(defIn));
}
case SET:
return DERFactory.createSet(buildDEREncodableVector(defIn));
case EXTERNAL:
return new DERExternal(buildDEREncodableVector(defIn));
default:
throw new IOException("unknown tag " + tagNo + " encountered");
}
}
return createPrimitiveDERObject(tagNo, defIn, tmpBuffers);
}
似乎支持这些 "other tags that may be constructed,",包括标记 28,尚未编码,但我不确定我的证书在哪里损坏或如何修复标记。
谁能指出我正确的方向?谢谢。
您的证书不是有效的属性证书,它是一个(接近有效的)public密钥证书,尽管它包含一个用于使用的扩展 OID具有不符合标准定义的内容结构的属性证书(在 rfc3281/5755 中定义)。 openssl x509
仅处理 public-密钥证书; OpenSSL 根本不支持属性证书(除非您使用低级 asn1 例程并自己实现所有内容)。 BC 两者都支持,但实际上几乎没有人使用属性证书。
public-密钥和属性证书的外包装是旧的 SIGNED 宏,因此该级别解析成功。第一个字段实际上是错误的——AttributeCertificateInfo 应该以包含 1(而不是 2)的 version INTEGER
开头,而你的实际 TBSCertificate 以包含 2 的有效 version [context0] EXPLICIT INTEGER
开头——但 BC 没有捕捉到这一点,因为根据v1 版本中的 source 是可选的和默认的。然后它会尝试解析 Holder
,这应该是几个标记的 OPTIONAL 项目的 SEQUENCE
,实际上是标记的 INTEGER 版本;我不确定在检测到此错误之前它是如何设法解析 Holder.IssuerSerial 的。我不知道它在哪里或如何找到标签 28。
可能不是你的情况,但我在解析 OCSP 响应时遇到了类似的错误:
java.io.IOException: unknown tag 28 encountered
at org.bouncycastle.asn1.ASN1InputStream.buildObject(Unknown Source)
at org.bouncycastle.asn1.ASN1InputStream.readObject(Unknown Source)
at org.bouncycastle.cert.ocsp.OCSPResp.<init>(Unknown Source)
...
在我获取 OCSP 响应的请求中缺少值为 application/ocsp-request
的 header Content-Type
,因此我从 Bouncy Castle[=23= 获取了无效数据]观点
您应该检查 InputStream
/ASN1InputStream
/ASN1Sequence
您正在尝试消费。
我在使用 BouncyCastle Java API.
解析 DER 属性证书时遇到问题错误
这是我尝试使用的代码。我首先将证书文件读取为名为 stream
的 InputStream,然后尝试将其转换为 Bouncycastle AttributeCertificate
对象:
ASN1InputStream derIn = new ASN1InputStream(stream);
ASN1Sequence seq = (ASN1Sequence) derIn.readObject();
AttributeCertificate cert = AttributeCertificate.getInstance(seq); <-- exception here
ac = new X509AttributeCertificateHolder(cert);
第三行导致 IllegalArgumentException
:
IllegalArgumentException: unknown object in getInstance: org.bouncycastle.asn1.ASN1Integer
at org.bouncycastle.asn1.ASN1Sequence.getInstance(Unknown Source)
at org.bouncycastle.asn1.x509.IssuerSerial.getInstance(Unknown Source)
at org.bouncycastle.asn1.x509.Holder.getInstance(Unknown Source)
at org.bouncycastle.asn1.x509.AttributeCertificateInfo.getInstance(Unknown Source)
...
Bouncycastle 还会抛出一个 IOException
表示遇到 "unknown tag":
java.io.IOException: unknown tag 28 encountered
at org.bouncycastle.asn1.ASN1InputStream.buildObject(Unknown Source)
at org.bouncycastle.asn1.ASN1InputStream.readObject(Unknown Source)
...
分析
我已经链接了我正在尝试解析的证书文件 here。 证书本身是使用 OpenSSL 生成的。
该证书还包括我正在使用的 ABAC 凭据,这是一个简单的字符串:
[some_uuid].experiment_create <- [some_uuid].partner.experiment_create
我查看了 "unknown tag 28",似乎 ASN.1 标签 28 表示一个 UniversalString。我在网上发现 "the UniversalString type models a Unicode character string implicitly serialized into UTF-32 big endian."
这对我来说表明证书中可能存在字符编码问题。但是当我使用 openssl asn1parse
查看证书文件时,它似乎很好:
0:d=0 hl=4 l= 660 cons: SEQUENCE
4:d=1 hl=4 l= 509 cons: SEQUENCE
8:d=2 hl=2 l= 3 cons: cont [ 0 ]
10:d=3 hl=2 l= 1 prim: INTEGER :02
13:d=2 hl=2 l= 1 prim: INTEGER :00
16:d=2 hl=2 l= 13 cons: SEQUENCE
18:d=3 hl=2 l= 9 prim: OBJECT :sha256WithRSAEncryption
29:d=3 hl=2 l= 0 prim: NULL
31:d=2 hl=2 l= 51 cons: SEQUENCE
33:d=3 hl=2 l= 49 cons: SET
35:d=4 hl=2 l= 47 cons: SEQUENCE
37:d=5 hl=2 l= 3 prim: OBJECT :commonName
42:d=5 hl=2 l= 40 prim: UTF8STRING :bf3a72c271f661dae81647a16c1babf3a52da28e
84:d=2 hl=2 l= 30 cons: SEQUENCE
86:d=3 hl=2 l= 13 prim: UTCTIME :170828213103Z
101:d=3 hl=2 l= 13 prim: UTCTIME :270826213103Z
116:d=2 hl=2 l= 51 cons: SEQUENCE
118:d=3 hl=2 l= 49 cons: SET
120:d=4 hl=2 l= 47 cons: SEQUENCE
122:d=5 hl=2 l= 3 prim: OBJECT :commonName
127:d=5 hl=2 l= 40 prim: UTF8STRING :bf3a72c271f661dae81647a16c1babf3a52da28e
169:d=2 hl=3 l= 159 cons: SEQUENCE
172:d=3 hl=2 l= 13 cons: SEQUENCE
174:d=4 hl=2 l= 9 prim: OBJECT :rsaEncryption
185:d=4 hl=2 l= 0 prim: NULL
187:d=3 hl=3 l= 141 prim: BIT STRING
331:d=2 hl=3 l= 183 cons: cont [ 3 ]
334:d=3 hl=3 l= 180 cons: SEQUENCE
337:d=4 hl=3 l= 144 cons: SEQUENCE
340:d=5 hl=2 l= 8 prim: OBJECT :id-aca-group
350:d=5 hl=3 l= 131 prim: OCTET STRING [HEX DUMP]:0C8180626633613732633237316636363164616538313634376131366331626162663361353264613238652E6578706572696D656E745F637265617465203C2D20626633613732633237316636363164616538313634376131366331626162663361353264613238652E706172746E65722E6578706572696D656E745F637265617465
484:d=4 hl=2 l= 31 cons: SEQUENCE
486:d=5 hl=2 l= 3 prim: OBJECT :X509v3 Authority Key Identifier
491:d=5 hl=2 l= 24 prim: OCTET STRING [HEX DUMP]:30168014162E4EF6CD52F37CD2EDDFBEA484E70D6CDE9048
517:d=1 hl=2 l= 13 cons: SEQUENCE
519:d=2 hl=2 l= 9 prim: OBJECT :sha256WithRSAEncryption
530:d=2 hl=2 l= 0 prim: NULL
532:d=1 hl=3 l= 129 prim: BIT STRING
其他程序似乎也能正常工作; openssl x509
提供此输出:
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 0 (0x0)
Signature Algorithm: sha256WithRSAEncryption
Issuer: CN=bf3a72c271f661dae81647a16c1babf3a52da28e
Validity
Not Before: Aug 28 21:31:03 2017 GMT
Not After : Aug 26 21:31:03 2027 GMT
Subject: CN=bf3a72c271f661dae81647a16c1babf3a52da28e
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (1024 bit)
Modulus:
00:c5:d4:35:49:4d:bd:ee:9a:93:51:a4:e1:46:df:
46:c0:1e:f6:b1:85:70:4d:31:2b:20:6f:ab:82:16:
b4:9d:3e:ea:f3:38:53:e2:7b:be:36:37:f3:11:7f:
90:5d:aa:ad:e7:e8:61:3c:46:8d:7a:69:4d:c6:89:
e2:f7:07:d9:3f:b0:5d:f7:ee:40:e5:86:48:7b:4c:
0e:0f:11:0c:96:41:e6:99:02:17:df:4e:60:3d:d0:
42:b5:dc:22:e0:64:6d:ad:17:22:b7:a2:15:ec:dd:
89:c2:b4:58:01:64:d7:db:fe:62:1e:c5:40:0c:e0:
b9:12:7e:fe:4c:31:65:e6:51
Exponent: 65537 (0x10001)
X509v3 extensions:
id-aca-group:
...bf3a72c271f661dae81647a16c1babf3a52da28e.experiment_create <- bf3a72c271f661dae81647a16c1babf3a52da28e.partner.experiment_create
X509v3 Authority Key Identifier:
keyid:16:2E:4E:F6:CD:52:F3:7C:D2:ED:DF:BE:A4:84:E7:0D:6C:DE:90:48
Signature Algorithm: sha256WithRSAEncryption
1e:0f:2a:7a:cf:95:77:0f:5c:48:f3:12:c4:b9:8a:5a:d9:b9:
62:1c:60:0c:a0:13:70:f3:c5:aa:de:6d:6f:92:7f:0d:a2:3b:
c9:bd:cc:45:6c:4b:21:8d:32:81:8b:af:13:6e:a3:96:18:05:
3b:83:fb:8c:3b:2a:d8:87:22:56:9e:4b:1d:06:e6:7f:ba:36:
89:e8:c6:8a:5a:9e:2c:9b:44:5e:19:fe:68:13:12:93:48:df:
f9:34:42:01:d5:62:c1:ca:e4:e2:3b:86:b7:4c:75:ba:60:5b:
c9:f7:68:9a:b0:b5:1c:33:01:5e:77:c0:7c:13:11:e1:09:67:
42:dd
基于这些,我找不到证书有任何明显的错误。我能找到的唯一线索是 ASN1InputStream.java 的 Bouncycastle 源代码块,它抛出了我发现的异常:
// Build an object given its tag and the number of bytes to construct it from.
protected ASN1Primitive buildObject(
int tag,
int tagNo,
int length)
throws IOException
{
...
if (isConstructed)
{
// TODO There are other tags that may be constructed (e.g. BIT_STRING)
switch (tagNo)
{
case OCTET_STRING:
//
// yes, people actually do this...
//
ASN1EncodableVector v = buildDEREncodableVector(defIn);
ASN1OctetString[] strings = new ASN1OctetString[v.size()];
for (int i = 0; i != strings.length; i++)
{
strings[i] = (ASN1OctetString)v.get(i);
}
return new BEROctetString(strings);
case SEQUENCE:
if (lazyEvaluate)
{
return new LazyEncodedSequence(defIn.toByteArray());
}
else
{
return DERFactory.createSequence(buildDEREncodableVector(defIn));
}
case SET:
return DERFactory.createSet(buildDEREncodableVector(defIn));
case EXTERNAL:
return new DERExternal(buildDEREncodableVector(defIn));
default:
throw new IOException("unknown tag " + tagNo + " encountered");
}
}
return createPrimitiveDERObject(tagNo, defIn, tmpBuffers);
}
似乎支持这些 "other tags that may be constructed,",包括标记 28,尚未编码,但我不确定我的证书在哪里损坏或如何修复标记。
谁能指出我正确的方向?谢谢。
您的证书不是有效的属性证书,它是一个(接近有效的)public密钥证书,尽管它包含一个用于使用的扩展 OID具有不符合标准定义的内容结构的属性证书(在 rfc3281/5755 中定义)。 openssl x509
仅处理 public-密钥证书; OpenSSL 根本不支持属性证书(除非您使用低级 asn1 例程并自己实现所有内容)。 BC 两者都支持,但实际上几乎没有人使用属性证书。
public-密钥和属性证书的外包装是旧的 SIGNED 宏,因此该级别解析成功。第一个字段实际上是错误的——AttributeCertificateInfo 应该以包含 1(而不是 2)的 version INTEGER
开头,而你的实际 TBSCertificate 以包含 2 的有效 version [context0] EXPLICIT INTEGER
开头——但 BC 没有捕捉到这一点,因为根据v1 版本中的 source 是可选的和默认的。然后它会尝试解析 Holder
,这应该是几个标记的 OPTIONAL 项目的 SEQUENCE
,实际上是标记的 INTEGER 版本;我不确定在检测到此错误之前它是如何设法解析 Holder.IssuerSerial 的。我不知道它在哪里或如何找到标签 28。
可能不是你的情况,但我在解析 OCSP 响应时遇到了类似的错误:
java.io.IOException: unknown tag 28 encountered
at org.bouncycastle.asn1.ASN1InputStream.buildObject(Unknown Source)
at org.bouncycastle.asn1.ASN1InputStream.readObject(Unknown Source)
at org.bouncycastle.cert.ocsp.OCSPResp.<init>(Unknown Source)
...
在我获取 OCSP 响应的请求中缺少值为 application/ocsp-request
的 header Content-Type
,因此我从 Bouncy Castle[=23= 获取了无效数据]观点
您应该检查 InputStream
/ASN1InputStream
/ASN1Sequence
您正在尝试消费。