I try to parse extra data of certificate in java. I interested in subjectAlternativeNames section. My code is:
CertificateFactory certFactory = CertificateFactory.getInstance("X.509")
certFactory.generateCertificate(ByteArrayInputStream(x509EntryChain.leafCertificate))
X509CertInfo
contains java.io.IOException: invalid URI name:DNS:*.cetrel.lu, DNS:mail.cetrel.lu, DNS:www.cetrel.lu
.
and subjectAlternativeNames
is empty.
How can I parse it?
I am interested only in extra_data
, not in leaf_input
. I can find the certificate here: http://transparencyreport.google.com/https/certificates/
The DNS names
section is empty, seems Google can't parse it either.
Full code to parce cert:
import org.apache.commons.codec.binary.Base64;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import sun.security.x509.CertificateExtensions;
import sun.security.x509.X509CertImpl;
import sun.security.x509.X509CertInfo;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
public class CertParser {
public static void main(String[] args) throws CertificateException, IOException {
CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
ByteArrayInputStream in = new ByteArrayInputStream(Base64.decodeBase64(
"AAAAAAFXsGq8HwAAAAW+MIIFujCCBKKgAwIBAgIDAZZpMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNVBAYTAkxVMRYwFAYDVQQKEw1MdXhUcnVzdCBTLkEuMR4wHAYDVQQDExVMdXhUcnVzdCBRdWFsaWZpZWQgQ0EwHhcNMTAwNDE1MDY0MzM0WhcNMTMwNDE1MDY0MzM0WjB8MQswCQYDVQQGEwJMVTERMA8GA1UEBxMITXVuc2JhY2gxFDASBgNVBAoTC0NFVFJFTCBTLkEuMRAwDgYDVQQLEwdJT1AtU1NTMRQwEgYDVQQDFAsqLmNldHJlbC5sdTEcMBoGCSqGSIb3DQEJARYNc3NzQGNldHJlbC5sdTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALhf+I7RshQlHMMWq/WPDLNxx+ODMd4Tn9ej14igvMEE+RYEagdMOZoeO8Bqz9qV2atzFHqz0D+Ad+cxuznBGKl4rhS9gUejgoAMox7car0+LSsv1NT4J0gAlnmH3BJlDMd9CihT0D/sRwMNfa8GYAvCuGDtWIvYb497RFy+2kmzk3cwCk3BgOO3MsT7iqhcn65Pd1Lq1vLjCCuQBoWLlcKk4uptPsyFKrHEh1/0ksY5evqBPxioVppoN+oay20RK36JzrzAl+vfpzq03WRlM2IgM0ItnesLqid9GqTUsOTq59i5aVX1EKlfgM5v7YCpYMLrJA+JBO3beR/4FSczfccCAwEAAaOCAnowggJ2MAwGA1UdEwEB/wQCMAAwYAYIKwYBBQUHAQEEVDBSMCMGCCsGAQUFBzABhhdodHRwOi8vb2NzcC5sdXh0cnVzdC5sdTArBggrBgEFBQcwAoYfaHR0cDovL2NhLmx1eHRydXN0Lmx1L0xUUUNBLmNydDBBBgNVHREEOjA4hjZETlM6Ki5jZXRyZWwubHUsIEROUzptYWlsLmNldHJlbC5sdSwgRE5TOnd3dy5jZXRyZWwubHUwggEABgNVHSAEgfgwgfUwgegGCCuBKwEBAgYBMIHbMIGtBggrBgEFBQcCAjCBoBqBnUx1eFRydXN0IFNlcnZlciBDZXJ0aWZpY2F0ZS4gTm90IHN1cHBvcnRlZCBieSBTU0NELCBLZXkgR2VuZXJhdGlvbiBieSBTdWJzY3JpYmVyLiBHVEMsIENQIGFuZCBDUFMgb24gaHR0cDovL3JlcG9zaXRvcnkubHV4dHJ1c3QubHUuIFNpZ25lZCBieSBhIFF1YWxpZmllZCBDQS4wKQYIKwYBBQUHAgEWHWh0dHA6Ly9yZXBvc2l0b3J5Lmx1eHRydXN0Lmx1MAgGBgQAj3oBAzARBglghkgBhvhCAQEEBAMCBeAwDgYDVR0PAQH/BAQDAgSwMCcGA1UdJQQgMB4GCCsGAQUFBwMBBggrBgEFBQcDAgYIKwYBBQUHAwQwHwYDVR0jBBgwFoAUjZCjB90aE3eZTJKrTUPeP80pZAUwMQYDVR0fBCowKDAmoCSgIoYgaHR0cDovL2NybC5sdXh0cnVzdC5sdS9MVFFDQS5jcmwwHQYDVR0OBBYEFLhOdzNJg4CSchxSsHbwKWMVm8xnMA0GCSqGSIb3DQEBBQUAA4IBAQBrQ9bYRA5O8a+4vIfVx5izH5x9yieKuQjpF4Etc4YUxfk3h5yZieWJuZGHygUjV5TCYDdhtVf6FFWkJ4FT5l6zDQeOLrEWqL12qcT4hGFN61mwjZO7kca8IHlqPPeqtYVg/Ssbpun+bjPOsGdvrvMulqNNTz5UeQuovc/VFaoHpYCQhezrQ6E6uQ684f6LFVIbsah6pT58wEnrf6xE1aRdSk27e3bF8wns3zOVsWE2wKck5pMS5DkGwjWli27Aqt6QQCyCKC7xqqxwL8GfnmXZNdn2iYYfSyr0I7rdqxa7FsuNFkEb8/PdZlyMxQP867YnucRCyLzzjCnRy1bOLnUeAAA="
));
readNumber(in, 1); // version
readNumber(in, 1); // type
readNumber(in, 8); // timestamp
readNumber(in, 2); // entry type
int length = (int) readNumber(in, 3);
byte[] x509 = readFixedLength(in, length);
X509CertImpl cert = (X509CertImpl) certFactory.generateCertificate(new ByteArrayInputStream(x509));
((CertificateExtensions)((X509CertInfo)cert.get("x509.info")).get("extensions")).getUnparseableExtensions(); // <-- want too be empty, but it's not!!!
}
static byte[] readFixedLength(InputStream inputStream, int dataLength) throws IOException {
byte[] toReturn = new byte[dataLength];
int bytesRead = inputStream.read(toReturn);
if (bytesRead < dataLength) {
throw new RuntimeException();
}
return toReturn;
}
static long readNumber(InputStream inputStream, int numBytes) throws IOException {
long toReturn = 0;
for (int i = 0; i < numBytes; i++) {
int valRead = inputStream.read();
if (valRead < 0) {
throw new RuntimeException();
}
toReturn = (toReturn << 8) | valRead;
}
return toReturn;
}
}
After you shared your code to access the certificate, I could safe and inspect it.
As was already clear from the question, the problematic extension is the subject alternative name. Its value is specified (RFC 5280) as an instance of
GeneralNames
which is aSEQUENCE
ofGeneralName
which is aCHOICE
:This is a dump of the extension in question of your certificate:
The value is tagged with a 6 (
[6]
). Thus, theuniformResourceIdentifier
choice is used. RFC 5280 in the context of subject alternative names requires for the value of this choice:Thus, the
sun.security.x509.X509CertImpl
attempts to parse the value as an URI. This obviously must fail as the value simply is no URI:If you want to access the value nonetheless, simply retrieve and parse it from the
UnparseableExtensions
map you have like this:for
sun.security.x509.Extension
andsun.security.util.DerValue
.The output: