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

时间:2010-03-09 14:18:55

标签: java asn.1 decoder

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

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

有一种快速简便的方法吗?或者我真的需要使用一些完整的ASN.1库吗?

谢谢!

5 个答案:

答案 0 :(得分:12)

使用下页中包含的说明我做了一些更改,代码也适用于我。

从BC早期版本移植到1.47及更高版本 - 充气城堡的军团 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 http://stackoverflow.com/questions/2409618/how-do-i-decode-a-der-encoded-string-in-java
 */
private ASN1Primitive toDERObject(byte[] data) throws IOException
{
    ByteArrayInputStream inStream = new ByteArrayInputStream(data);
    ASN1InputStream asnInputStream = new ASN1InputStream(inStream);

    return asnInputStream.readObject();
}

答案 1 :(得分: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 :(得分:6)

BouncyCastle(除此之外):

  

用于读写编码的ASN.1对象的库。

答案 3 :(得分:2)

JcaX509ExtensionUtils以更简单的方式完成上述答案。

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

答案 4 :(得分: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是正确的解决方案。