Como faço para decodificar uma string codificada DER em Java?
Pergunta
Eu estou tentando ler uma extensão personalizada de um certificado digital. Eu sei o valor é um GeneralString codificado em DER. Existe uma maneira fácil de decodificar corretamente e obter uma String Java? Eu tentei o seguinte, mas 's' inclui alguns dos metadados de codificação como caracteres lixo no início da cadeia.
byte[] ext = cert.getExtensionValue("1.2.3.4");
String s= new String(ext);
System.out.println(s);
Existe uma maneira rápida e fácil de fazer isso? Ou eu realmente precisa usar alguma biblioteca ASN.1 de pleno direito?
Obrigado!
Solução
BouncyCastle é (entre tudo o resto):
Uma biblioteca para ler e escrever objetos ASN.1 codificados.
Outras dicas
Usando instruções contidas na página seguinte eu fiz algumas mudanças eo código funcionou bem para mim.
Portando a partir de versões anteriores BC para 1,47 e, mais tarde - A Legião do Castelo Bouncy http://www.bouncycastle.org/ wiki / display / JA1 / Portando + de + antes + BC + lançamentos + a + 1,47 + e + mais tarde
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();
}
Este acaba por ser bastante simples com 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();
}
JcaX509ExtensionUtils
faz o que as respostas acima fazer de uma maneira muito mais simples.
X509Certificate certificate;
byte[] encodedExtensionValue = certificate.getExtensionValue(oid);
if (encodedExtensionValue != null) {
ASN1Primitive extensionValue = JcaX509ExtensionUtils
.parseExtensionValue(encodedExtensionValue);
String values = extensionValue.toString();
}
No Oracle VM (JDK 7):
DerValue val = new DerValue(ext);
String s = val.getGeneralString();
http://www.docjar.com/docs /api/sun/security/util/DerValue.html
NOTA: A pergunta original pediu uma solução "rápida e suja", então eu acho que isso estava de volta válida então, mas uma vez que se baseia na API interna Sun, não deve ser mais utilizado especialmente desde JDK 9 em diante.
Bouncy Castle é a solução adequada para isso.