Использование openssl для получения сертификата с сервера

354

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

Старший разработчик (который в отпуске :() сообщил мне, что я могу запустить это:

openssl s_client -connect host.host:9999

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

depth=1 /C=NZ/ST=Test State or Province/O=Organization Name/OU=Organizational Unit Name/CN=Test CA
verify error:num=19:self signed certificate in certificate chain
verify return:0
23177:error:14094410:SSL routines:SSL3_READ_BYTES:sslv3 alert handshake failure:s3_pkt.c:1086:SSL alert number 40
23177:error:140790E5:SSL routines:SSL23_WRITE:ssl handshake failure:s23_lib.c:188:

Я также пытался с этой опцией

-showcerts 

и этот (работает на Debian)

-CApath /etc/ssl/certs/ 

Но получите ту же ошибку.

Этот источник говорит, что я могу использовать этот флаг CApath, но он, похоже, не помогает. Я пробовал несколько путей безрезультатно.

Пожалуйста, дайте мне знать, где я иду не так.

противный пирог
источник

Ответы:

464

С SNI

Если удаленный сервер использует SNI (то есть разделяет несколько хостов SSL на одном IP-адресе), вам необходимо отправить правильное имя хоста, чтобы получить правильный сертификат.

openssl s_client -showcerts -servername www.example.com -connect www.example.com:443 </dev/null

Без SNI

Если удаленный сервер не использует SNI, вы можете пропустить -servernameпараметр:

openssl s_client -showcerts -connect www.example.com:443 </dev/null


Чтобы просмотреть полную информацию о сертификате сайта, вы также можете использовать эту цепочку команд:

$ echo | \
    openssl s_client -servername www.example.com -connect www.example.com:443 2>/dev/null | \
    openssl x509 -text
Ари Маниатис
источник
3
Хм. Я все еще получаю ту же ошибку при попытке этой команды. Я заметил, что моя версия Openssl «OpenSSL 0.9.8g 19 октября 2007». У тебя есть идеи?
противный пирог
39
Полезно: echo "" | openssl s_client -connect server:port -prexit 2>/dev/null | sed -n -e '/BEGIN\ CERTIFICATE/,/END\ CERTIFICATE/ p' stackoverflow.com/a/12918442/843000
mbrownnyc
16
Альтернативный полезный скрипт, от madboa.com :echo | openssl s_client -connect server:port 2>&1 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > cert.pem
rmeakins
9
Для того, чтобы сделать это немного более кратким, вы можете заменить sedс openssl x509, и читать его в использовании подоболочку:openssl x509 -in <(openssl s_client -connect server:port -prexit 2>/dev/null)
Гейб Martin-Dempesy
27
Такжеecho | openssl s_client -connect google.com:443 2>/dev/null | openssl x509
MattSizzle
68

Хотя я согласен с ответом Ари (и проголосовал за него :), мне нужно было сделать дополнительный шаг, чтобы заставить его работать с Java в Windows (где его нужно было развернуть):

openssl s_client -showcerts -connect www.example.com:443 < /dev/null | openssl x509 -outform DER > derp.der

Перед добавлением openssl x509 -outform DERпреобразования я получал сообщение об ошибке от keytool в Windows с жалобой на формат сертификата. Импорт файла .der работал нормально.

Дэвид Жакей
источник
Странный. Я использую сертификаты PEM с keytool в Windows начиная с Java 6 и никогда не сталкивался с проблемой.
imgx64
39

Оказывается, здесь сложнее: мне нужно было предоставить гораздо больше подробностей, чтобы начать работу. Я думаю, что это как-то связано с тем фактом, что это соединение, которое требует аутентификации клиента, и hankshake требовалось больше информации, чтобы перейти к этапу сброса сертификатов.

Вот моя рабочая команда:

openssl s_client -connect host:port -key our_private_key.pem -showcerts \
                 -cert our_server-signed_cert.pem

Надеемся, что это толчок в правильном направлении для тех, кто мог бы получить больше информации.

противный пирог
источник
6
Извините, но ваш ответ не имеет особого смысла. Вам нужно было передать сертификат на сервер, чтобы получить сертификат?
Ари Маниатис
2
Ага. Аутентификация клиента AFAIK.
противная выпечка
11
Оказывается, '-prexit' также вернет эти данные. Например; openssl s_client -connect host: port -prexit
Robert
39

Однострочник для извлечения сертификата с удаленного сервера в формате PEM, на этот раз с использованием sed:

openssl s_client -connect www.google.com:443 2>/dev/null </dev/null |  sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p'
Андре Фернандес
источник
2
Этот почти идеально подходит для извлечения сертификата, просто пропуская -servernameопцию, не знаю почему, но мне пришлось использовать его, чтобы получить полный сертификат.
Karl.S
-servername требуется для указания имени сервера (SNI). Веб-поиск может расширить на остальных.
Сэм Глеск
32

Самая простая командная строка для этого, которая включает вывод PEM для добавления его в хранилище ключей, а также вывод, читаемый человеком, а также поддерживает SNI, что важно, если вы работаете с сервером HTTP:

openssl s_client -servername example.com -connect example.com:443 \
    </dev/null 2>/dev/null | openssl x509 -text

Опция -servername включает поддержку SNI, а текст openssl x509 печатает сертификат в удобочитаемом формате.

Florian
источник
Вы можете добавить к -servername свой поддомен, например, ws.example.com вместо example.com (примените это также к параметру -connect).
russellhoff
24

Для того, чтобы получить сертификат удаленного сервера вы можете использовать opensslинструмент , и вы можете найти его между BEGIN CERTIFICATEи END CERTIFICATEкоторый вам нужно скопировать и вставить в свой файл сертификата (CRT).

Вот команда, демонстрирующая это:

ex +'/BEGIN CERTIFICATE/,/END CERTIFICATE/p' <(echo | openssl s_client -showcerts -connect example.com:443) -scq > file.crt

Чтобы вернуть все сертификаты из цепочки, просто добавьте g(глобальный), например:

ex +'g/BEGIN CERTIFICATE/,/END CERTIFICATE/p' <(echo | openssl s_client -showcerts -connect example.com:443) -scq

Тогда вы можете просто импортировать файл сертификата (file.crt ) в цепочку для ключей и сделать его доверенным, чтобы Java не жаловалась.

В OS X вы можете дважды щелкнуть файл или перетащить его в свой брелок для доступа, чтобы он появился в логине / сертификатах. Затем дважды щелкните по импортированному сертификату и сделайте его Always Trust for SSL .

В CentOS 5 вы можете добавить их в /etc/pki/tls/certs/ca-bundle.crtфайл (и запустить sudo update-ca-trust force-enable:), или в CentOS 6 скопировать их /etc/pki/ca-trust/source/anchors/и запустить sudo update-ca-trust extract.

В Ubuntu скопируйте их /usr/local/share/ca-certificatesи запустите sudo update-ca-certificates.

kenorb
источник
12
HOST=gmail-pop.l.google.com
PORT=995

openssl s_client -servername $HOST -connect $HOST:$PORT < /dev/null 2>/dev/null | openssl x509 -outform pem
akond
источник
6

распечатать только цепочку сертификатов, а не сертификат сервера:

# MYHOST=myhost.com
# MYPORT=443
# openssl s_client -connect ${MYHOST}:${MYPORT} -showcerts 2>/dev/null </dev/null | awk '/^.*'"${MYHOST}"'/,/-----END CERTIFICATE-----/{next;}/-----BEGIN/,/-----END CERTIFICATE-----/{print}'

обновить доверие CA на CentOS / RHEL 6/7:

# update-ca-trust enable
# openssl s_client -connect ${MYHOST}:${MYPORT} -showcerts 2>/dev/null </dev/null | awk '/^.*'"${MYHOST}"'/,/-----END CERTIFICATE-----/{next;}/-----BEGIN/,/-----END CERTIFICATE-----/{print}' >/etc/pki/ca-trust/source/anchors/myca.cert
# update-ca-trust extract

на CentOS / RHEL 5:

# openssl s_client -connect ${MYHOST}:${MYPORT} -showcerts 2>/dev/null </dev/null | awk '/^.*'"${MYHOST}"'/,/-----END CERTIFICATE-----/{next;}/-----BEGIN/,/-----END CERTIFICATE-----/{print}' >>/etc/pki/tls/certs/ca-bundle.crt
Матье КАРБОННО
источник
Именно то, что мне было нужно на CentOS7. Спасибо!
Артур Хеберт
5

Вы можете получить и сохранить корневой сертификат сервера, используя следующий скрипт bash:

CERTS=$(echo -n | openssl s_client -connect $HOST_NAME:$PORT -showcerts | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p')
echo "$CERTS" | awk -v RS="-----BEGIN CERTIFICATE-----" 'NR > 1 { printf RS $0 > "'$SERVER_ROOT_CERTIFICATE'"; close("'$SERVER_ROOT_CERTIFICATE'") }'

Просто перезапишите обязательные переменные.

Андрей Александров
источник
4

Если ваш сервер почтовый сервер (MS Exchange или Zimbra) , может быть , вам нужно добавить starttlsи smtpфлаги:

openssl s_client -starttls smtp -connect HOST_EMAIL:SECURE_PORT 2>/dev/null </dev/null | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > CERTIFICATE_NAME.pem

Куда,

  • HOST_EMAIL - это домен сервера, например, mail-server.com.

  • SECURE_PORT - это порт связи, например, 587 или 465

  • Имя выходного файла CERTIFICATE_NAME (формат BASE 64 / PEM)

Шоко
источник
2

В интересах других, таких как я, которые пытались следовать полезному совету при доступе к AWS CloudFront, но не смогли, нужно добавить хитрость -servername domain.name...

Источник: https://serverfault.com/a/780450/8972

Амос Шапира
источник