Как проверить альтернативные имена субъекта для сертификата SSL/TLS?
Есть ли способ программно проверить альтернативные имена субъекта сертификата SAN SSL?
Используя, например, следующую команду, я могу получить много информации, но не все SAN:
openssl s_client -connect www.website.com:443
Большое спасибо!
5 ответов
Чтобы получить альтернативные имена субъекта (SAN) для сертификата, используйте следующую команду:
openssl s_client -connect website.com:443 | openssl x509 -noout -text | grep DNS:
Сначала эта команда подключается к нужному сайту (website.com, порт 443 для SSL):
openssl s_client -connect website.com:443
Тогда труба (|
) что в эту команду:
openssl x509 -noout -text
Это берет файл сертификата и выводит все его сочные детали. -noout
flag не позволяет выводить сам файл сертификата (в кодировке base64), который нам не нужен. -text
флаг говорит ему выводить детали сертификата в текстовой форме.
Обычно есть много выходных данных (подпись, издатель, расширения и т. Д.), Которые нам не нужны, поэтому мы передаем их в простой grep:
grep DNS:
Поскольку записи в SAN начинаются с DNS:
this simply returns only the lines that contain that, stripping out all the other info and leaving us with the desired information.
You may note that the command does not cleanly exit; openssl s_client
actually acts as a client and leaves the connection open, waiting for input. If you want it to immediately exit (eg to parse the output in a shell script) simply pipe echo
into it:
echo | openssl s_client -connect website.com:443 | openssl x509 -noout -text | grep DNS:
How do I get the SAN directly from a file?
For this, you don't need the openssl s_client
команда. Просто добавь -in MyCertificate.crt
на openssl x509
command and once again pipe through grep, eg:
openssl x509 -noout -text -in MyCertificate.crt | grep DNS:
Также можно использовать встроенные функции openssl:
openssl s_client -connect website.com:443 </dev/null | openssl x509 -noout -ext subjectAltName
Если вы просто хотите увидеть сети SAN,grep DNS:
это очевидное решение.
Если вы хотите иметь более чистый список для дальнейшей обработки, вы можете использовать это регулярное выражение Perl для извлечения только имен: @names=/\sDNS:([^\s,]+)/g
Например:
true | openssl s_client -connect example.com:443 2>/dev/null \
| openssl x509 -noout -text \
| perl -l -0777 -ne '@names=/\bDNS:([^\s,]+)/g; print join("\n", sort @names);'
Что выведет это:
example.com
example.edu
example.net
example.org
www.example.com
www.example.edu
www.example.net
www.example.org
Так что вы можете передать это while read name; do echo "do stuff with $name"; done
и т.п.
Или для списка через запятую в одной строке замените join("\n",
с join(",",
(The -0777
переключатель для perl позволяет читать весь ввод сразу, а не построчно)
Есть ли способ программно проверить альтернативные имена сертификата SAN SSL?
В сертификате X509 может быть несколько SAN. Ниже приводится вики OpenSSL на клиенте SSL / TLS. Он перебирает имена и печатает их.
Вы получаете X509*
из функции как SSL_get_peer_certificate
из соединения TLS, d2i_X509
по памяти или PEM_read_bio_X509
из файловой системы.
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);
}
так как кто-то получит просто список SAN — по одному в строке:
openssl x509 -noout -text -in "${CERT_FILE}" | grep -Po 'DNS:\K[^,]+'
Лучшее,