Не могу проанализировать тему Альтернативные имена в java - PullRequest
0 голосов
/ 17 февраля 2020

Я пытаюсь разобрать дополнительные данные сертификата в java. Меня интересует тема в разделе Альтернативные имена. Мой код:

CertificateFactory certFactory = CertificateFactory.getInstance("X.509")
certFactory.generateCertificate(ByteArrayInputStream(x509EntryChain.leafCertificate))

X509CertInfo содержит java.io.IOException: invalid URI name:DNS:*.cetrel.lu, DNS:mail.cetrel.lu, DNS:www.cetrel.lu. и subjectAlternativeNames пусто.

Как я могу его проанализировать?

Меня интересует только extra_data, а не leaf_input. Я могу найти сертификат здесь: http://transparencyreport.google.com/https/certificates/

Раздел DNS names пуст, кажется, Google тоже не может его проанализировать.

Полный код для проверки сертификата :


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;
    }
}

1 Ответ

1 голос
/ 17 февраля 2020

После того, как вы поделились своим кодом для доступа к сертификату, я смог его сохранить и проверить.

Как уже было ясно из вопроса, расширение проблематики c является альтернативным именем субъекта. Его значение указывается (RF C 5280) как экземпляр GeneralNames, который является SEQUENCE из GeneralName, который является CHOICE:

SubjectAltName ::= GeneralNames

GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName

GeneralName ::= CHOICE {
     otherName                 [0]  AnotherName,
     rfc822Name                [1]  IA5String,
     dNSName                   [2]  IA5String,
     x400Address               [3]  ORAddress,
     directoryName             [4]  Name,
     ediPartyName              [5]  EDIPartyName,
     uniformResourceIdentifier [6]  IA5String,
     iPAddress                 [7]  OCTET STRING,
     registeredID              [8]  OBJECT IDENTIFIER }

Это дамп рассматриваемого расширения вашего сертификата:

    <30 41>
 676   65: . . . . SEQUENCE {
    <06 03>
 678    3: . . . . . OBJECT IDENTIFIER subjectAltName (2 5 29 17)
         : . . . . . . (X.509 extension)
    <04 3A>
 683   58: . . . . . OCTET STRING, encapsulates {
    <30 38>
 685   56: . . . . . . SEQUENCE {
    <86 36>
 687   54: . . . . . . . [6]
         : . . . . . . . . 'DNS:*.cetrel.lu, DNS:mail.cetrel.lu, DNS:www.cet'
         : . . . . . . . . 'rel.lu'
         : . . . . . . . }
         : . . . . . . }
         : . . . . . }

Значение помечено 6 ([6]). Таким образом, выбор uniformResourceIdentifier используется. RF C 5280 в контексте альтернативных имен субъекта требует для значения этого выбора:

Имя НЕ ДОЛЖНО быть относительным URI, и оно ДОЛЖНО следовать синтаксису URI и правилам кодирования, указанным в [RFC3986]. Имя ДОЛЖНО включать в себя как схему (например, «http» или «ftp»), так и спецификацию схемы c -part.

Таким образом, sun.security.x509.X509CertImpl пытается проанализировать значение как URI. Это, очевидно, должно завершиться сбоем, поскольку значение просто не является URI:

java.io.IOException: invalid URI name:DNS:*.cetrel.lu, DNS:mail.cetrel.lu, DNS:www.cetrel.lu
    at sun.security.x509.URIName.<init>(URIName.java:109)
    at sun.security.x509.URIName.<init>(URIName.java:96)
    at sun.security.x509.GeneralName.<init>(GeneralName.java:122)
    at sun.security.x509.GeneralName.<init>(GeneralName.java:76)
    at sun.security.x509.GeneralNames.<init>(GeneralNames.java:68)
    at sun.security.x509.SubjectAlternativeNameExtension.<init>(SubjectAlternativeNameExtension.java:141)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
    at sun.security.x509.CertificateExtensions.parseExtension(CertificateExtensions.java:113)
    at sun.security.x509.CertificateExtensions.init(CertificateExtensions.java:88)
    at sun.security.x509.CertificateExtensions.<init>(CertificateExtensions.java:78)
    at sun.security.x509.X509CertInfo.parse(X509CertInfo.java:702)
    at sun.security.x509.X509CertInfo.<init>(X509CertInfo.java:167)
    at sun.security.x509.X509CertImpl.parse(X509CertImpl.java:1804)
    at sun.security.x509.X509CertImpl.<init>(X509CertImpl.java:195)
    at sun.security.provider.X509Factory.engineGenerateCertificate(X509Factory.java:102)
    at java.security.cert.CertificateFactory.generateCertificate(CertificateFactory.java:339)
Caused by: java.net.URISyntaxException: Illegal character in opaque part at index 16: DNS:*.cetrel.lu, DNS:mail.cetrel.lu, DNS:www.cetrel.lu
    at java.net.URI$Parser.fail(URI.java:2848)
    at java.net.URI$Parser.checkChars(URI.java:3021)
    at java.net.URI$Parser.parse(URI.java:3058)
    at java.net.URI.<init>(URI.java:588)
    at sun.security.x509.URIName.<init>(URIName.java:107)
    ... 46 more

Если вы все же хотите получить доступ к значению, просто извлеките его и проанализируйте с карты UnparseableExtensions, которая у вас выглядит следующим образом:

Map<String, Extension> unparseables = ((CertificateExtensions)((X509CertInfo)cert.get("x509.info")).get("extensions")).getUnparseableExtensions();

Extension extension = unparseables.get("2.5.29.17");
byte[] value = extension.getValue();
DerValue derValue = new DerValue(value);
while (derValue.data.available() > 0) {
    DerValue encName = derValue.data.getDerValue();
    if ((encName.tag & 0x1f) == 6) {
        encName.resetTag(DerValue.tag_IA5String);
        System.out.printf("IA5String value from URI GeneralName value: %s\n", encName.getIA5String());
    }
}

для sun.security.x509.Extension и sun.security.util.DerValue.

Выход:

IA5String value from URI GeneralName value: DNS:*.cetrel.lu, DNS:mail.cetrel.lu, DNS:www.cetrel.lu
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...