Użycie openssl, aby uzyskać certyfikat z serwera

353

Próbuję uzyskać certyfikat zdalnego serwera, którego mogę użyć do dodania do mojego magazynu kluczy i użycia w mojej aplikacji Java.

Starszy programista (który jest na wakacjach :() poinformował mnie, że mogę to uruchomić:

openssl s_client -connect host.host:9999

Aby zrzucić surowy certyfikat, który mogę następnie skopiować i wyeksportować. Otrzymuję następujące dane wyjściowe:

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:

Próbowałem również z tą opcją

-showcerts 

i ten (działający na Debianie, pamięta cię)

-CApath /etc/ssl/certs/ 

Ale dostań ten sam błąd.

To źródło mówi, że mogę użyć tej flagi CApath, ale nie wydaje się to pomocne. Próbowałem wielu ścieżek bezskutecznie.

Daj mi znać, gdzie się mylę.

paskudny pasty
źródło

Odpowiedzi:

461

Z SNI

Jeśli serwer zdalny używa SNI (to znaczy, że współdzieli wiele hostów SSL na jednym adresie IP), musisz wysłać poprawną nazwę hosta, aby uzyskać odpowiedni certyfikat.

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

Bez SNI

Jeśli serwer zdalny nie używa SNI, możesz pominąć -servernameparametr:

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


Aby wyświetlić pełne szczegóły certyfikatu witryny, możesz również użyć tego łańcucha poleceń:

$ echo | \
    openssl s_client -servername www.example.com -connect www.example.com:443 2>/dev/null | \
    openssl x509 -text
Ari Maniatis
źródło
3
Hmm Nadal pojawia się ten sam błąd podczas próby wykonania tego polecenia. Zauważyłem, że moja wersja opensslowa to „OpenSSL 0.9.8g 19 paź 2007”. Czy masz jakies pomysły?
paskudny pasty
39
Przydatne: 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
Alternatywny przydatny skrypt z madboa.com :echo | openssl s_client -connect server:port 2>&1 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > cert.pem
rmeakins,
9
Aby uczynić ten nieco bardziej zwięzłe, można wymienić sedz openssl x509, i czytać je w użyciu sub-shell:openssl x509 -in <(openssl s_client -connect server:port -prexit 2>/dev/null)
Gabe Martin-Dempesy
27
Równieżecho | openssl s_client -connect google.com:443 2>/dev/null | openssl x509
MattSizzle
68

Chociaż zgadzam się z odpowiedzią Ari (i wziąłem udział w głosowaniu :), musiałem zrobić dodatkowy krok, aby uruchomić ją z Javą w systemie Windows (gdzie trzeba ją wdrożyć):

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

Przed dodaniem openssl x509 -outform DERkonwersji otrzymywałem błąd z keytoola w systemie Windows, skarżąc się na format certyfikatu. Import pliku .der działał poprawnie.

David Jaquay
źródło
Dziwny. Korzystam z certyfikatów PEM z keytool w systemie Windows od Java 6 i nigdy nie napotkałem problemu.
imgx64
39

Okazuje się, że tutaj jest bardziej złożona: musiałem podać o wiele więcej szczegółów, aby to się stało. Myślę, że ma to coś wspólnego z faktem, że jest to połączenie wymagające uwierzytelnienia klienta, a hankshake potrzebował więcej informacji, aby przejść do etapu, w którym certyfikaty zostały zrzucone.

Oto moje działające polecenie:

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

Mamy nadzieję, że jest to krok w dobrym kierunku dla każdego, kto mógłby zrobić więcej informacji.

paskudny pasty
źródło
6
Przykro mi, ale twoja odpowiedź nie ma większego sensu. Musiałeś przekazać certyfikat na serwer, aby uzyskać certyfikat?
Ari Maniatis
2
Tak. Uwierzytelnianie klienta AFAIK.
paskudny pasty
11
Okazuje się, że „-prexit” również zwróci te dane. Na przykład; openssl s_client -connect host: port -prexit
Robert
39

Jednoliniowy program do wypakowywania certyfikatu ze zdalnego serwera w formacie PEM, tym razem przy użyciu sed:

openssl s_client -connect www.google.com:443 2>/dev/null </dev/null |  sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p'
André Fernandes
źródło
2
Ten jest prawie idealny do wyodrębnienia certyfikatu, po prostu brakuje -servernameopcji, nie wiem dlaczego, ale musiałem go użyć, aby uzyskać pełny certyfikat.
Karl.S.
-servername jest wymagana do wskazania nazwy serwera (SNI). Wyszukiwanie w sieci może zostać rozszerzone na resztę.
Sam Gleske,
32

Najłatwiejszym do tego wierszem poleceń, który zawiera wyjście PEM w celu dodania go do magazynu kluczy, a także wyjście czytelne dla człowieka, a także obsługuje SNI, co jest ważne, jeśli pracujesz z serwerem HTTP:

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

Opcja -servername umożliwia włączenie obsługi SNI, a tekst openssl x509 drukuje certyfikat w formacie czytelnym dla człowieka.

Florian
źródło
Możesz dodać do swojej -servername swoją subdomenę, na przykład ws.example.com zamiast example.com (zastosuj to również do parametru -connect).
russellhoff
24

Aby uzyskać certyfikat zdalnego serwera, możesz użyć opensslnarzędzia i możesz je znaleźć pomiędzy, BEGIN CERTIFICATEa END CERTIFICATEktóre musisz skopiować i wkleić do pliku certyfikatu (CRT).

Oto polecenie, które to pokazuje:

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

Aby zwrócić wszystkie certyfikaty z łańcucha, wystarczy dodać g(globalny) jak:

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

Następnie możesz po prostu zaimportować plik certyfikatu ( file.crt) do pęku kluczy i uczynić go zaufanym, aby Java nie narzekała.

W systemie OS X możesz dwukrotnie kliknąć plik lub przeciągnąć i upuścić dostęp do pęku kluczy, aby pojawił się w loginie / certyfikatach. Następnie kliknij dwukrotnie importowany certyfikat i ustaw opcję Zawsze ufaj SSL .

W CentOS 5 możesz dołączyć je do /etc/pki/tls/certs/ca-bundle.crtpliku (i uruchomić sudo update-ca-trust force-enable:), lub w CentOS 6 skopiować je /etc/pki/ca-trust/source/anchors/i uruchomić sudo update-ca-trust extract.

W Ubuntu skopiuj je /usr/local/share/ca-certificatesi uruchom sudo update-ca-certificates.

kenorb
źródło
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
źródło
6

aby wydrukować tylko łańcuch certyfikatów, a nie certyfikat serwera:

# 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}'

aby zaktualizować zaufanie CA do 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

w 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
Mathieu CARBONNEAUX
źródło
Dokładnie to, czego potrzebowałem na CentOS7. Dzięki!
Arthur Hebert,
5

Możesz uzyskać i zapisać certyfikat główny serwera, używając następnego skryptu 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'") }'

Po prostu nadpisz wymagane zmienne.

Andriej Aleksandrow
źródło
4

Jeśli twój serwer to serwer e-mail (MS Exchange lub Zimbra), być może musisz dodać flagi starttlsi 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

Gdzie,

  • HOST_EMAIL to domena serwera, na przykład mail-server.com.

  • SECURE_PORT to port komunikacyjny, na przykład 587 lub 465

  • Nazwa pliku wyjściowego CERTIFICATE_NAME (format BASE 64 / PEM)

SHoko
źródło