在Java中如何解码DER编码的字符串?

18

我正在尝试从数字证书中读取自定义扩展。我知道该值是DER编码的GeneralString。有没有一种简单的方法来正确解码并获取Java字符串?我尝试了以下方法,但“s”包括一些编码元数据作为垃圾字符在字符串的开头。

byte[] ext = cert.getExtensionValue("1.2.3.4");
String s= new String(ext);
System.out.println(s);

有没有快速简单的方法来完成这个任务?或者我真的需要使用一些全功能的ASN.1库吗?

谢谢!

4个回答

17

根据下一页中包含的说明,我进行了一些更改,代码与我一起正常工作。

从早期BC版本移植到1.47和更高版本- The Legion of the Bouncy Castle http://www.bouncycastle.org/wiki/display/JA1/Porting+from+earlier+BC+releases+to+1.47+and+later

private String getExtensionValue(X509Certificate X509Certificate, String oid) throws IOException
{
    String decoded = null;
    byte[] extensionValue = X509Certificate.getExtensionValue(oid);

    if (extensionValue != null)
    {
        ASN1Primitive derObject = toDERObject(extensionValue);
        if (derObject instanceof DEROctetString)
        {
            DEROctetString derOctetString = (DEROctetString) derObject;

            derObject = toDERObject(derOctetString.getOctets());
            if (derObject instanceof ASN1String)
            {
                ASN1String s = (ASN1String)derObject;
                decoded = s.getString();
            }

        }
    }
    return decoded;
}

/**
 * From https://dev59.com/f3E95IYBdhLWcg3wN7Kv
 */
private ASN1Primitive toDERObject(byte[] data) throws IOException
{
    ByteArrayInputStream inStream = new ByteArrayInputStream(data);
    ASN1InputStream asnInputStream = new ASN1InputStream(inStream);

    return asnInputStream.readObject();
}

8
这在BouncyCastle中非常简单:
private String getExtensionValue(X509Certificate X509Certificate, String oid) throws IOException
{
    String decoded = null;
    byte[] extensionValue = X509Certificate.getExtensionValue(oid);

    if (extensionValue != null)
    {
        DERObject derObject = toDERObject(extensionValue);
        if (derObject instanceof DEROctetString)
        {
            DEROctetString derOctetString = (DEROctetString) derObject;

            derObject = toDERObject(derOctetString.getOctets());
            if (derObject instanceof DERUTF8String)
            {
                DERUTF8String s = DERUTF8String.getInstance(derObject);
                decoded = s.getString();
            }

        }
    }
    return decoded;
}

private DERObject toDERObject(byte[] data) throws IOException
{
    ByteArrayInputStream inStream = new ByteArrayInputStream(data);
    ASN1InputStream asnInputStream = new ASN1InputStream(inStream);

    return asnInputStream.readObject();
}

2
嗨,看起来DERObject已被弃用。你有没有更新代码示例的机会?我想现在必须使用org.bouncycastle.sasn1.Asn1Object,但我还没有能够使其正常工作。 - user1513388
@user1513388 抱歉,这已经超过2年了。我现在甚至没有在任何地方使用Java,所以我不确定我是否会再次尝试这个。 - Ragesh
2
已经很晚了,但请使用ASN1Primitive而不是DerObject。 请访问以下链接:http://www.bouncycastle.org/wiki/display/JA1/Porting+from+earlier+BC+releases+to+1.47+and+later - Saqib Rezwan

5

JcaX509ExtensionUtils以更简单的方式完成了上面答案中的操作。

X509Certificate certificate;
byte[] encodedExtensionValue = certificate.getExtensionValue(oid);
if (encodedExtensionValue != null) {
    ASN1Primitive extensionValue = JcaX509ExtensionUtils
            .parseExtensionValue(encodedExtensionValue);
    String values = extensionValue.toString();          
}

2
在Oracle VM(JDK 7)中:
    DerValue val = new DerValue(ext);
    String s = val.getGeneralString();

http://www.docjar.com/docs/api/sun/security/util/DerValue.html

注意:原问题要求“快速而肮脏”的解决方案,因此我认为这在那时是有效的,但由于它依赖于Sun内部API,特别是自JDK 9以来,不应再使用。

Bouncy Castle是正确的解决方案。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接