Как декодировать кодированную DER-строку в Java? - PullRequest
15 голосов
/ 09 марта 2010

Я пытаюсь прочитать пользовательское расширение из цифрового сертификата. Я знаю, что значение GeneralString закодировано в DER. Есть ли простой способ правильно его декодировать и получить строку Java? Я попробовал следующее, но 's' включает некоторые метаданные кодирования в виде ненужных символов в начале строки.

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

Есть ли быстрый и простой способ сделать это? Или мне действительно нужно использовать полноценную библиотеку ASN.1?

Спасибо!

Ответы [ 5 ]

12 голосов
/ 10 декабря 2012

Используя инструкции, приведенные на следующей странице, я внес некоторые изменения, и код работал нормально со мной.

Портирование с более ранних выпусков до 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 /1494854/kak-dekodirovat-kodirovannuy-der-stroku-v-java
 */
private ASN1Primitive toDERObject(byte[] data) throws IOException
{
    ByteArrayInputStream inStream = new ByteArrayInputStream(data);
    ASN1InputStream asnInputStream = new ASN1InputStream(inStream);

    return asnInputStream.readObject();
}
8 голосов
/ 18 марта 2010

С 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();
}
6 голосов
/ 09 марта 2010

BouncyCastle (среди всего прочего):

Библиотека для чтения и записи закодированных объектов ASN.1.

2 голосов
/ 01 октября 2013

В Oracle VM (JDK 7):

    DerValue val = new DerValue(ext);
    String s = val.getGeneralString();

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

ПРИМЕЧАНИЕ. В первоначальном вопросе требовалось «быстрое и грязное» решение, поэтому я думаю, что тогда оно было действительным, но поскольку оно опирается на внутренний API Sun, его больше не следует использовать, особенно после JDK 9 и далее.

Надувной Замок - правильное решение для этого.

2 голосов
/ 18 июля 2013

JcaX509ExtensionUtils делает то, что ответили выше, гораздо проще.

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