Как просмотреть все SSL-сертификаты в пакете?

Вопрос или проблема

У меня есть пакет сертификатов в файле .crt.

При выполнении команды openssl x509 -in bundle.crt -text -noout отображается только корневой сертификат.

Как увидеть остальные сертификаты?

http://comments.gmane.org/gmane.comp.encryption.openssl.user/43587 предлагает следующую однострочную команду:

openssl crl2pkcs7 -nocrl -certfile CHAINED.pem | openssl pkcs7 -print_certs -text -noout

Это действительно сработало для меня, но я не понимаю деталей, поэтому не могу сказать, есть ли какие-то подводные камни.

обновлено 22 июня:

для openssl 1.1.1 и выше: ответ в одну команду можно найти здесь serverfault.com/a/1079893 (openssl storeutl -noout -text -certs bundle.crt)

Чтобы просто перечислить субъекты:

openssl storeutl -noout -text -certs \
   $(openssl version -d | sed -E 's/OPENSSLDIR: "([^"]*)"/\1/')/cert.pem | \
   grep Subject: 

Команда keytool из Java выполняет эту задачу:

keytool -printcert -v -file <certs.crt>

Примечание: Двойной клик в Windows не работает. Windows читает только первый сертификат в хранилище ключей и автоматически расширяет цепочку доверия из своего встроенного хранилища сертификатов.

Результаты:

  1. Все, кроме первого сертификата в файле .crt, не отображаются
  2. Вы можете увидеть отображаемую цепочку доверия, отличную от той, что у вас в файле .crt. Это может привести к неправильным выводам.
openssl storeutl -noout -text -certs bundle.crt
Парафразируя из документации OpenSSL:

Программа openssl storeutl была добавлена в OpenSSL 1.1.1.

Команда storeutl может использоваться для отображения содержимого, извлеченного из заданных URI.

  • -noout предотвращает вывод данных PEM
  • -text выводит объекты в текстовом виде, аналогично выводу -text из openssl x509
  • -certs только выбирает сертификаты из данного URI

Однострочник, который отображает сводку каждого сертификата в файле.

openssl crl2pkcs7 -nocrl -certfile CHAINED.pem | openssl pkcs7 -print_certs -noout

Он объединяет все сертификаты в один промежуточный файл PKCS7 и затем разбирает информацию в каждой части этого файла.

(Это то же самое, что ответ Бени, но выводит короче, без опции -text).

пример:

$ openssl crl2pkcs7 -nocrl -certfile bundled.crt | openssl pkcs7 -print_certs -noout

subject=/C=NL/postalCode=5705 CN/L=City/street=Example 20/O=Foobar B.V./OU=ICT/OU=Wildcard SSL/CN=*.example.com
issuer=/C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=COMODO RSA Organization Validation Secure Server CA

subject=/C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=COMODO RSA Organization Validation Secure Server CA
issuer=/C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=COMODO RSA Certification Authority

subject=/C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=COMODO RSA Certification Authority
issuer=/C=SE/O=AddTrust AB/OU=AddTrust External TTP Network/CN=AddTrust External CA Roo

Следование этой FAQ привело меня к этому perl-скрипту, который очень настоятельно заставляет меня думать, что openssl не имеет нативной поддержки для обработки nth сертификата в пакетах, и что вместо этого мы должны использовать какой-то инструмент для разделения ввода перед тем, как передавать каждый сертификат в openssl. Этот perl-скрипт, свободно адаптированный от скрипта Ника Берча, кажется, выполняет задачу:

#!/usr/bin/perl
# скрипт для разделения много сертификатного ввода на отдельные сертификаты
# Художественная лицензия
#
# v0.0.1         Ник Бёрч <[email protected]>
# v0.0.2         Том Ятс <[email protected]>
#

$filename = shift;
unless($filename) {
  die("Вы должны указать файл сертификата.\n");
}
open INP, "<$filename" or die("Не удалось загрузить \"$filename\"\n");

$thisfile = "";

while(<INP>) {
   $thisfile .= $_;
   if($_ =~ /^\-+END(\s\w+)?\sCERTIFICATE\-+$/) {
      print "Найден полный сертификат:\n";
      print `echo \'$thisfile\' | openssl x509 -noout -text`;
      $thisfile = "";
   }
}
close INP;

Поскольку нет решения на основе awk:

$ awk '/BEGIN/ { i++; } /BEGIN /, /END / { print > i ".extracted.crt" }' ca-bundle
$ for cert in *.extracted.crt; do openssl x509 -in $cert -text -noout; done

Первая команда разбивает пакет на сертификаты, ищя строки “BEGIN ” и “END “. Вторая команда проходит по извлечённым сертификатам и отображает их.

Это может быть не красиво или элегантно, но это было быстро и сработало для меня, используя bash на linux и блоки в формате PEM в файле ca-cert bundle.

while read line
do
    if [ "${line//END}" != "$line" ]; then
        txt="$txt$line\n"
        printf -- "$txt" | openssl x509 -subject -issuer -noout
        txt=""
    else
        txt="$txt$line\n"
    fi
done < /path/to/bundle/file

Вы можете это всё объединить в одну строку и подстроить опции openssl под себя. Я действительно希望, что для этого было бы более элегантное решение, но в данном случае я думаю, что поиск более элегантного решения занял бы больше времени, чем написание неэлегантного.

Попробуйте этот скрипт:
https://github.com/jkolezyn/cert_tree

Он отображает сертификаты в pem-пакете в виде дерева, построенного на основе полей Subject и Issuer.

Он выводит дерево вроде этого:

cert_tree.py -p ~/.certs/ca_list.pem  
━ CorpRoot            [1]
    ┣━ ServerCA       [2]
    ┣━ example_cert   [3]
    ┗━ example_2      [8]
━ RootCert            [4]
    ┣━ example_cert3  [5] [ИСТЕК 03.06.2019 13:26:21]
    ┣━ other          [6]
    ┣━ other1         [7] [ИСТЕК 16.06.2017 21:12:18]
    ┗━ AnotherOne     [9]

cert_tree.py -pe ~/.certs/mycert.pem
━ RootCert                [3] [действителен до: 2023-07-08 17:57:15]
    ┗━ IntermediateCert   [2] [действителен до: 2023-07-08 18:55:58]
        ┗━ UserCert       [1] [действителен до: 2023-09-17 13:33:00]

В bash обычно нужна только одна (длинная) строка кода 🙂

tfile=$( mktemp -u ) && \
csplit -z -q -f "$tfile" bundle.crt  '/----BEGIN CERTIFICATE-----/' '{*}' && \
find "${tfile%/*}" -name "${tfile##*/}*" -exec openssl x509 -noout -subject -in "{}" \; -delete

awk -v cmd='openssl x509 -noout -text' \
  '/BEGIN/{close(cmd)}; {print | cmd}' \
  < bundle.pem | less

Или чтобы перечислить только субъекты и издателей:

awk -v cmd='openssl x509 -noout -subject -issuer' \
  '/BEGIN/{close(cmd)}; {print | cmd}' \
  < bundle.pem

Как это работает. print запускает cmd и передает ему строки одну за другой, пока не достигнется строка /BEGIN/. В этот момент он закрывает трубку. Следующий print запускает другую cmd и начинает передавать строки в свежесозданную трубку.

Долг чести принадлежит Стефану Шазелу.

Вот решение на основе awk, которое не зависит от промежуточных файлов.

cat bundle.crt | awk '{
  if ($0 == "-----BEGIN CERTIFICATE-----") cert=""
  else if ($0 == "-----END CERTIFICATE-----") print cert
  else cert=cert$0
}' | while read CERT; do
  echo "$CERT" | base64 -d | openssl x509 -inform DER -text -noout
done

Это работает, извлекая блоки PEM из stdin и объединяя каждый блок в одну строку, закодированную в формате base64. Затем строки читаются, декодируются и передаются в openssl как сертификаты, закодированные в DER.

Я хотел бы вставить здесь идиоматическую perl-команду:

  perl -ne "\$n++ if /BEGIN/; print if \$n == 1;" mysite.pem

Если есть текст, то немного более надежное изменение:

 perl -ne "\$n++ if /^-----BEGIN CERTIFICATE-----\$/; print if \$n == 3 && /^-----BEGIN CERTIFICATE-----\$/.../^-----END CERTIFICATE-----\$/;" mysite.pem

Просто измените значение, что должно быть n во втором утверждении, чтобы получить n-ный сертификат.

@user1686 предложил другое решение в https://superuser.com/questions/1599666/view-all-certs-in-a-pem-cert-file-full-cert-chain-with-openssl-or-another-comm

это часть стека GnuTLS.

certtool -i < multiplecerts.pem

Небольшое изменение в публикации MadHatter, чтобы позволить вам копировать/вставлять прямо в CLI. Я также включил хеш MD5, который полезен при проверке корректности сертификатов. Строка stdin возвращает md5 хеш сертификата(ов).

perl -e 'my $thisfile = "";
foreach (<>) {
   $thisfile .= $_;
   if($_ =~ /^\-+END(\s\w+)?\sCERTIFICATE\-+$/) {
      print "Найден полный сертификат:\n";
      print `echo "$thisfile" | openssl x509 -noout -text`;
      print `echo "$thisfile" | openssl x509 -noout -modulus | openssl md5`;
      $thisfile = "";
   }
}' < my_id_cert_and_ca_bundle.crt

Если вы хотите получить хороший краткий вывод, вы можете использовать эту версию. Полезно, если вы просто проверяете, что у вас есть все сертификаты, но не проверяете использование и т. д. сертификата(ов).

perl -e 'my $thisfile = "";
foreach (<>) {
   $thisfile .= $_;
   if($_ =~ /^\-+END(\s\w+)?\sCERTIFICATE\-+$/) {
      print "Найден полный сертификат:\n";
      print `echo "$thisfile" | openssl x509 -noout -serial -subject -dates -alias -issuer`;
      print `echo "$thisfile" | openssl x509 -noout -modulus | openssl md5` . "\n";
      $thisfile = "";
   }
}' < my_id_cert_and_ca_bundle.crt

На всякий случай, если ваша версия openssl не поддерживает все эти флаги, вот некоторые egrep, которые вы можете использовать. То же самое, что и в первом, но просто передать в egrep.

perl -e '.....
' < my_id_cert_and_ca_bundle.crt | egrep "Serial|Subject:|Not |Public-Key|^Cert|stdin|ssuer"

Чтобы проверить MD5 хеш частного ключа, вы можете сделать следующее.

openssl rsa -noout -modulus -in privateKey.key | openssl md5

Ссылка: SSL Shopper – Сопоставление сертификата и ключа

Ответ или решение

Чтобы просмотреть все SSL-сертификаты в файле-обертке (например, в файле с расширением .crt), вы можете использовать различные команды и скрипты, поскольку OpenSSL не поддерживает прямой вывод всех сертификатов из одного файла одновременно. Ниже приведены несколько методов для достижения этой цели.

1. Использование команды OpenSSL

Начиная с OpenSSL версии 1.1.1, вы можете использовать команду openssl storeutl, чтобы извлечь и отобразить все сертификаты в файле. Команда выглядит следующим образом:

openssl storeutl -noout -text -certs bundle.crt

2. Использование комбинации OpenSSL команд

Если у вас есть несколько сертификатов в PEM-формате, вы можете сначала скомбинировать их в формат PKCS#7, а затем вывести. Этот метод позволит вам увидеть все сертификаты:

openssl crl2pkcs7 -nocrl -certfile bundle.crt | openssl pkcs7 -print_certs -noout

3. Использование инструментов Java Keytool

Если у вас установлен Java, вы можете использовать команду keytool для вывода всех сертификатов в файле:

keytool -printcert -v -file bundle.crt

4. Скрипты и утилиты

Для более автоматизированного подхода можно использовать скрипты. Например, вы можете воспользоваться следующим Perl-скриптом, который разделит файл на отдельные сертификаты и выведет их:

#!/usr/bin/perl
use strict;
use warnings;

my $filename = shift;
unless ($filename) {
    die("Укажите файл сертификатов.\n");
}

my $thisfile = "";

open my $inp, '<', $filename or die("Не удалось открыть \"$filename\"\n");
while (<$inp>) {
    $thisfile .= $_;
    if ($_ =~ /^-+END(\s\w+)?\sCERTIFICATE-+$/) {
        print "Найден полный сертификат:\n";
        print `echo "$thisfile" | openssl x509 -noout -text`;
        $thisfile = "";
    }
}
close $inp;

5. Использование команды awk

Если вы предпочитаете решение без использования промежуточных файлов, вы можете использовать awk в вашей командной строке:

awk -v cmd='openssl x509 -noout -text' '/BEGIN/{close(cmd)}; {print | cmd}' < bundle.pem

6. Утилиты GnuTLS

Если у вас установлена GnuTLS, вы также можете использовать certtool, чтобы просмотреть сертификаты в файле:

certtool -i < multiplecerts.pem

Заключение

Каждый из этих методов подходит для просмотра всех сертификатов в файле-обертке. Выбор метода зависит от ваших предпочтений и доступного программного обеспечения. Метод openssl storeutl является наиболее простым и современным подходом, если вы используете OpenSSL 1.1.1 или выше.

Оцените материал
Добавить комментарий

Капча загружается...