web-dev-qa-db-fra.com

Comment afficher le nom alternatif de sujet d'un certificat?

La réponse la plus proche que j'ai trouvée utilise "grep".

> openssl x509 -text -noout -in cert.pem | grep DNS

Y a-t-il une meilleure façon de faire cela? Je préfère seulement la ligne de commande.

Merci.

41
user180574

Notez que vous pouvez limiter la sortie de -text aux extensions en ajoutant l'option suivante:

-certopt no_subject,no_header,no_version,no_serial,no_signame,no_validity,no_issuer,no_pubkey,no_sigdump,no_aux

c'est à dire.:

openssl x509 -text -noout -in cert.pem \
  -certopt no_subject,no_header,no_version,no_serial,no_signame,no_validity,no_issuer,no_pubkey,no_sigdump,no_aux

Cependant, vous devrez toujours appliquer une logique d'analyse de texte pour obtenir uniquement le Subject Alternative Name.

Si cela ne suffit pas, je pense que vous devrez écrire un petit programme qui utilise la bibliothèque openssl pour extraire le champ spécifique que vous recherchez. Voici quelques exemples de programmes montrant comment analyser un certificat, y compris l'extraction de champs d'extension tels que Subject Alternative Name:

https://zakird.com/2013/10/13/certificate-parsing-with-openssl

Notez que vous n’aurez pas à utiliser openssl et C si vous choisissez la programmation ... vous pouvez choisir votre langue préférée et la bibliothèque d'analyseur ASN.1, et l'utiliser. Par exemple, en Java, vous pouvez utiliser http://jac-asn1.sourceforge.net/ et bien d’autres.

31
Raman

Extrait de https://stackoverflow.com/a/13128918/1695680

$ true | openssl s_client -connect example.com:443 | openssl x509 -noout -text | grep DNS:

Exemple

$ true | openssl s_client -connect localhost:8443 | openssl x509 -noout -text | grep DNS:
depth=2 C = US, ST = NC, L = SomeCity, O = SomeCompany Security, OU = SomeOU, CN = SomeCN
verify error:num=19:self signed certificate in certificate chain
DONE
                DNS:localhost, DNS:127.0.0.1, DNS:servername1.somedom.com, DNS:servername2.somedom.local
18
ThorSummoner

Voici ma solution (avec openssl et sed ):

bash premier

sed -ne '
    s/^\( *\)Subject:/\1/p;
    /X509v3 Subject Alternative Name/{
        N;
        s/^.*\n//;
      :a;
        s/^\( *\)\(.*\), /\1\2\n\1/;
        ta;
        p;
        q;
    }' < <(openssl x509 -in cert.pem -noout -text)

pourrait être écrit:

sed -ne 's/^\( *\)Subject:/\1/p;/X509v3 Subject Alternative Name/{
    N;s/^.*\n//;:a;s/^\( *\)\(.*\), /\1\2\n\1/;ta;p;q; }' < <(
    openssl x509 -in cert.pem -noout -text )

et pourrait rendre quelque chose comme:

         CN=www.example.com
                DNS:il0001.sample.com
                DNS:example.com
                DNS:demodomain.com
                DNS:testsite.com
                DNS:www.il0001.sample.com
                DNS:www.il0001.sample.com.vsite.il0001.sample.com
                DNS:www.example.com
                DNS:www.example.com.vsite.il0001.sample.com
                DNS:www.demodomain.com
                DNS:www.demodomain.com.vsite.il0001.sample.com
                DNS:www.testsite.com
                DNS:www.testsite.com.vsite.il0001.sample.com

Idem pour le serveur live

sed -ne 's/^\( *\)Subject:/\1/p;/X509v3 Subject Alternative Name/{
    N;s/^.*\n//;:a;s/^\( *\)\(.*\), /\1\2\n\1/;ta;p;q; }' < <(
    openssl x509 -noout -text -in <(
        openssl s_client -ign_eof 2>/dev/null <<<$'HEAD / HTTP/1.0\r\n\r' \
            -connect google.com:443 ) )

Sortie de mai:

         C=US, ST=California, L=Mountain View, O=Google Inc, CN=*.google.com
                DNS:*.google.com
                DNS:*.Android.com
                DNS:*.appengine.google.com
                DNS:*.cloud.google.com
                DNS:*.gcp.gvt2.com
                DNS:*.google-analytics.com
                DNS:*.google.ca
                DNS:*.google.cl
                DNS:*.google.co.in
                DNS:*.google.co.jp
                DNS:*.google.co.uk
                DNS:*.google.com.ar
                DNS:*.google.com.au
                DNS:*.google.com.br
                DNS:*.google.com.co
                DNS:*.google.com.mx
                DNS:*.google.com.tr
                DNS:*.google.com.vn
                DNS:*.google.de
                DNS:*.google.es
                DNS:*.google.fr
                DNS:*.google.hu
                DNS:*.google.it
                DNS:*.google.nl
                DNS:*.google.pl
                DNS:*.google.pt
                DNS:*.googleadapis.com
                DNS:*.googleapis.cn
                DNS:*.googlecommerce.com
                DNS:*.googlevideo.com
                DNS:*.gstatic.cn
                DNS:*.gstatic.com
                DNS:*.gvt1.com
                DNS:*.gvt2.com
                DNS:*.metric.gstatic.com
                DNS:*.Urchin.com
                DNS:*.url.google.com
                DNS:*.youtube-nocookie.com
                DNS:*.youtube.com
                DNS:*.youtubeeducation.com
                DNS:*.ytimg.com
                DNS:Android.clients.google.com
                DNS:Android.com
                DNS:developer.Android.google.cn
                DNS:g.co
                DNS:goo.gl
                DNS:google-analytics.com
                DNS:google.com
                DNS:googlecommerce.com
                DNS:Urchin.com
                DNS:www.goo.gl
                DNS:youtu.be
                DNS:youtube.com
                DNS:youtubeeducation.com

POSIX Shell maintenant

Comme < <(...) est un bashism, la même commande doit être écrite:

openssl x509 -in cert.pem -noout -text | sed -ne '
  s/^\( *\)Subject:/\1/p;
  /X509v3 Subject Alternative Name/{
      N;
      s/^.*\n//;
    :a;
      s/^\( *\)\(.*\), /\1\2\n\1/;
      ta;
      p;
      q;
  }'

et

printf 'HEAD / HTTP/1.0\r\n\r\n' |
    openssl s_client -ign_eof 2>/dev/null -connect google.com:443 |
    openssl x509 -noout -text |
    sed -ne 's/^\( *\)Subject:/\1/p;/X509v3 Subject Alternative Name/{
        N;s/^.*\n//;:a;s/^\( *\)\(.*\), /\1\2\n\1/;ta;p;q; }'
10
F. Hauri

Solution très simple utilisant grep

openssl x509 -in /path/to/x509/cert -noout -text|grep -oP '(?<=DNS:|IP Address:)[^,]+'|sort -uV

Pour le certificat Google, cela génère:

Android.clients.google.com
Android.com
developer.Android.google.cn
g.co
goo.gl
google.com
googlecommerce.com
google-analytics.com
hin.com
Urchin.com
www.goo.gl
youtu.be
youtube.com
youtubeeducation.com
*.Android.com
*.appengine.google.com
*.cloud.google.com
*.gcp.gvt2.com
*.googleadapis.com
*.googleapis.cn
*.googlecommerce.com
*.googlevideo.com
*.google.ca
*.google.cl
*.google.com
*.google.com.ar
*.google.com.au
*.google.com.br
*.google.com.co
*.google.com.mx
*.google.com.tr
*.google.com.vn
*.google.co.in
*.google.co.jp
*.google.co.uk
*.google.de
*.google.es
*.google.fr
*.google.hu
*.google.it
*.google.nl
*.google.pl
*.google.pt
*.gstatic.cn
*.gstatic.com
*.gvt1.com
*.gvt2.com
*.metric.gstatic.com
*.Urchin.com
*.url.google.com
*.youtubeeducation.com
*.youtube.com
*.ytimg.com
*.google-analytics.com
*.youtube-nocookie.com
3
ThinGuy

Vous pouvez utiliser awk pour vous rapprocher du SAN, en canalisant les options ci-dessus dans l'instruction awk:

openssl x509 -in mycertfile.crt -text -noout \
  -certopt no_subject,no_header,no_version,no_serial,no_signame,no_validity,no_subject,no_issuer,no_pubkey,no_sigdump,no_aux \
 | awk '/X509v3 Subject Alternative Name/','/X509v3 Basic Constraints/'
1
RandomW

Une solution améliorée basée sur awk (info-bulle: @RandomW): 

openssl x509 -in certfile -text -noout \
  -certopt no_header,no_version,no_serial,no_signame,no_validity,no_issuer,no_pubkey,no_sigdump,no_aux \
| awk '/X509v3 Subject Alternative Name:/ {san=1;next} 
      san && /^ *X509v3/ {exit} 
      san { sub(/DNS:/,"",$1);print $1}'

Ceci imprime une liste, de même que les solutions grep et sed également trouvées ici. La différence est qu'il existe un contrôle plus strict de l'endroit où se trouvent les informations. Si le format de sortie change un jour, cette version est plus robuste et supportera mieux les changements. Seul le texte entre "Subject Alternative Name" et la toute prochaine section "X509v3" est imprimé et tout le texte facultatif précédant "DNS:" est supprimé.

Android.clients.google.com
Android.com
developer.Android.google.cn
g.co
goo.gl
...
0
Otheus

Ajouter une alternative python . La condition préalable est que vous ayez une chaîne avec les enregistrements "DNS:".

# Fetch the certificate details (subprocess, OpenSSL module, etc)
# dnsstring contains the "DNS:" line of the "openssl" output
# Example of how to get the string of DNS names from a string output of the certificate
for idx, line in enumerate(certoutput.split()):
    if ' X509v3 Authority Key Identifier:' in line:
        dnsstring = certoutput.split()[idx + 1]

# Get a list
[x.replace('DNS:', '').replace(',', '') for x in dnsstring]

# Format to a comma separated string
', '.join([x.replace('DNS:', '').replace(',', '') for x in dnsstring])

Un exemple de ligne de commande:

true | \
  openssl s_client -showcerts -connect google.com:443 2>/dev/null | \
  openssl x509 -noout -text 2>/dev/null | grep " DNS:" | \
  python -c"import sys; print ', '.join([x.replace('DNS:', '').replace(',', '') for x in sys.stdin.readlines()[0].split()])"

Sortie:

*.google.com, *.Android.com, <etc>
0
sastorsl

Comment afficher le nom alternatif de sujet d'un certificat?

Il peut y avoir plusieurs SAN dans un certificat X509. Ce qui suit provient du wiki OpenSSL à l’adresse Client SSL/TLS . Il boucle sur les noms et les imprime.

Vous obtenez le X509* à partir d'une fonction comme SSL_get_peer_certificate à partir d'une connexion TLS, d2i_X509 à partir de la mémoire ou PEM_read_bio_X509 à partir du système de fichiers.

void print_san_name(const char* label, X509* const cert)
{
    int success = 0;
    GENERAL_NAMES* names = NULL;
    unsigned char* utf8 = NULL;

    do
    {
        if(!cert) break; /* failed */

        names = X509_get_ext_d2i(cert, NID_subject_alt_name, 0, 0 );
        if(!names) break;

        int i = 0, count = sk_GENERAL_NAME_num(names);
        if(!count) break; /* failed */

        for( i = 0; i < count; ++i )
        {
            GENERAL_NAME* entry = sk_GENERAL_NAME_value(names, i);
            if(!entry) continue;

            if(GEN_DNS == entry->type)
            {
                int len1 = 0, len2 = -1;

                len1 = ASN1_STRING_to_UTF8(&utf8, entry->d.dNSName);
                if(utf8) {
                    len2 = (int)strlen((const char*)utf8);
                }

                if(len1 != len2) {
                    fprintf(stderr, "  Strlen and ASN1_STRING size do not match (embedded null?): %d vs %d\n", len2, len1);
                }

                /* If there's a problem with string lengths, then     */
                /* we skip the candidate and move on to the next.     */
                /* Another policy would be to fails since it probably */
                /* indicates the client is under attack.              */
                if(utf8 && len1 && len2 && (len1 == len2)) {
                    fprintf(stdout, "  %s: %s\n", label, utf8);
                    success = 1;
                }

                if(utf8) {
                    OPENSSL_free(utf8), utf8 = NULL;
                }
            }
            else
            {
                fprintf(stderr, "  Unknown GENERAL_NAME type: %d\n", entry->type);
            }
        }

    } while (0);

    if(names)
        GENERAL_NAMES_free(names);

    if(utf8)
        OPENSSL_free(utf8);

    if(!success)
        fprintf(stdout, "  %s: <not available>\n", label);

}
0
jww