Получение цепочки или эмитента CA из сертификата x509 с помощью OpenSSL CLI

Я пытаюсь построить цепочку (или просто получить ее откуда-то) из сертификата с использованием OpenSSL, предпочтительно с использованием интерфейса командной строки.

Я нашел несколько примеров в Интернете, но я застрял в вопросе "Где я могу получить сертификат CA, выдавший сертификат?"

Например, проверьте этот веб-сайт с таблицей команд openssl, вы найдете команду

openssl s_client -showcerts -host example.com -port 443

получить цепочку. Вы можете попробовать это, используяwww.google.com вместо того example.com. Результат должен дать вам цепочку. Другие веб-сайты рано или поздно используют ту же команду...

Итак, я не могу получить цепочку напрямую из сертификата, но я должен где-то попросить цепочку.

Теперь моя проблема: где мне взять имя хоста, куда я могу отправить свой запрос на цепочку?

Я взглянул на два сертификата.

  1. stackexchange.com
  2. google.com

С помощью OpenSSL, Я могу спросить эмитента с помощью команды

openssl x509 -in certFile -noout -issuer

и я получаю соответственно

  1. эмитент =C = США, O = Let's Encrypt, CN = Let's Encrypt Authority X3
  2. эмитент =C = США, O = Google Trust Services, CN = GTS CA 1O1

Честно говоря, я не знаю, что мне делать с этими результатами....

Затем, исследуя с помощью команды

openssl x509 -text -in certFile

Я нашел расширения AIA:

  1. Эмитенты CA - URI:http://cert.int-x3.letsencrypt.org/
  2. Эмитенты CA - URI:http://pki.goog/gsr2/GTS1O1.crt

Хорошо, в первом примере я наконец могу использовать команду

openssl s_client -showcerts -host http://cert.int-x3.letsencrypt.org/ -port 443

а с гуглом я не знаю как скачать цепочку с помощью openssl.... я мог бы использовать wget может быть, но у меня нет того формата, который я получил от stackexchange...

Итак, напоследок мои вопросы:

  • Как мне работать с этими различиями?
  • Есть ли лучший способ получить цепочку из сертификата, не спрашивая эмитента CA?
  • CA Issuer - это расширение от AIA, и я думаю, что это не обязательно, могу ли я на него положиться?
  • Как я могу получить CA Issuer, используя OpenSSL, без разбора вывода самостоятельно? (что-то типаopenssl x509 -caIssuer -in certFile)

PS: То, что я пытаюсь достичь в самом конце, - это проверить сертификат, пройти всю цепочку и проверить все OCSP или CRL для каждого сертификата в цепочке... Если у вас есть рабочий пример на C++ или просто используя OpenSSL CLI, буду очень благодарен:)

РЕДАКТИРОВАТЬ:

Сейчас я создаю цепочку самостоятельно.

Используя расширения AIA, я получаю URI CA Issuer, загружаю сертификат CA Issuer (при необходимости конвертирую в PEM) и так далее, пока я больше не найду CA Issuer. Тогда, вероятно, это корневой ЦС.

После этого я вручную собираю весь пем и создаю цепочку.

3 ответа

Решение

Кажется, много примеров в Интернете имеют в виду сертификат SSL. В сертификате SSL вы можете просто подключиться к сайту и загрузить полную цепочку. Я думаю, что именно в самом протоколе SSL сервер должен предоставить вам полную цепочку.

Я делал это для сертификатов SMIME, поэтому меня смутил, потому что я не могу использовать тот же метод, который они используют для сертификатов SSL.

После разговора с моими коллегами, а также сравнения того, что я делал с некоторыми похожими программами, найденными в Интернете, кажется, что расширение AIA - правильный способ сделать это. Возможно, это не обязательно в стандарте X509, но похоже, что оно широко используется (я никогда не видел сертификата SMIME без расширения AIA).

Затем я создаю цепочку вручную, возвращаюсь, используя расширение AIA, пока не найду сертификат без такого расширения.

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

(Конечно, не забудьте проверить статус отзыва через CRL или OCSP)

Пока все работает хорошо:)

Знайте, что это немного устарело, и это было решено, но я подумал, что добавлю небольшой скрипт, который я пишу, чтобы проанализировать CA Issuer из вывода x509:

      getcaissuer() {
openssl x509 -noout -text -in $1 | awk '/^[ \t]+CA Issuers[ \t]+-[ \t]+URI:/ { print gensub(/^.*URI:(.*)$/,"\\1","g",$0); }'
}

# usage:  getcaissuer <certificate>

Бонус от ответа @bng44270, этот скрипт будет подниматься по цепочке, захватывая сертификаты в текущий каталог.

      #!/bin/bash
# get-cert-chain.sh

machine=${1?No address passed}

machine_cert=${machine}.pem

# from https://stackoverflow.com/a/68637388/5401366
getcaissuer() {
    openssl x509 -noout -text -in $1 -ext authorityInfoAccess | awk '/^[ \t]+CA Issuers[ \t]+-[ \t]+URI:/ { print gensub(/^.*URI:(.*)$/,"\\1","g",$0); }'
}

if [ ! -e "${machine_cert}" ];
then
    openssl s_client -connect ${machine}:443 -showcerts </dev/null 2>/dev/null | openssl x509 -outform PEM >${machine_cert}
fi;

cur_cert=$machine_cert

while :;
do
    # Get the first matching http line to grab the next cert loc
    nextca=$(getcaissuer ${cur_cert} | grep -m1 http)

    # ran out of stuff to retrieve
    [ -z "${nextca}" ] && break

    echo "Trying to get '${nextca}'"

    nextfile=$(basename ${nextca})

    if [ ! -e ${nextfile} ];
    then
        echo "Getting $nextca"
        curl -sO $nextca
    else
        echo "Found ${nextfile}"
    fi

    # Convert
    cat $nextfile | openssl x509 -inform DER -outform PEM > ${nextfile}.pem

    # down the rabbit hole...
    cur_cert=${nextfile}.pem

done
Другие вопросы по тегам