การใช้ 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 

และอันนี้ (ทำงานบนเดเบียนใจคุณ)

-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 ตุลาคม 2550' คุณมีความคิดใด ๆ
Pasty ที่น่ารังเกียจ

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)
Gabe Martin-Dempesy

27
ยังecho | openssl s_client -connect google.com:443 2>/dev/null | openssl x509
MattSizzle

68

ในขณะที่ฉันเห็นด้วยกับคำตอบของ Ari (และอัปเดตมัน :) ฉันต้องทำขั้นตอนเพิ่มเติมเพื่อให้มันทำงานร่วมกับ 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

ปรากฎว่ามีความซับซ้อนมากขึ้นที่นี่: ฉันต้องการให้รายละเอียดเพิ่มเติมมากมายเพื่อให้ได้สิ่งนี้ ฉันคิดว่ามันเกี่ยวข้องกับความจริงที่ว่าการเชื่อมต่อที่ต้องการการรับรองความถูกต้องของลูกค้าและแฮงค์เชคต้องการข้อมูลเพิ่มเติมเพื่อไปยังขั้นตอนที่ใบรับรองถูกทิ้ง

นี่คือคำสั่งการทำงานของฉัน:

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

หวังว่านี่จะเป็นการสะกิดไปในทิศทางที่ถูกต้องสำหรับทุกคนที่สามารถทำได้ด้วยข้อมูลเพิ่มเติม


6
ฉันขอโทษ แต่คำตอบของคุณไม่สมเหตุสมผล คุณต้องการส่งใบรับรองไปยังเซิร์ฟเวอร์เพื่อรับใบรับรองหรือไม่
Ari Maniatis

2
อ๋อ การตรวจสอบลูกค้า AFAIK
Pasty ที่น่ารังเกียจ

11
ปรากฎว่า '-prexit' จะส่งคืนข้อมูลนั้นเช่นกัน เช่น; openssl s_client - เชื่อมต่อโฮสต์: พอร์ต -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

- ชื่อเซิร์ฟเวอร์จำเป็นสำหรับการระบุชื่อเซิร์ฟเวอร์ (SNI) การค้นหาเว็บสามารถขยายในส่วนที่เหลือ
Sam Gleske

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 -textพิมพ์ใบรับรองในรูปแบบที่อ่านมนุษย์


คุณสามารถเพิ่มชื่อโดเมนย่อยของคุณตัวอย่างเช่น 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 คุณสามารถดับเบิลคลิกที่ไฟล์หรือลากและวางใน Keychain Access ของคุณดังนั้นมันจะปรากฏในล็อกอิน / ใบรับรอง จากนั้นดับเบิลคลิกที่นำเข้ามีหนังสือรับรองและทำให้มันเสมอความน่าเชื่อถือสำหรับ 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-certificatessudo update-ca-certificates


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

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 trust บน 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 ขอบคุณ!
Arthur Hebert

5

คุณสามารถรับและเก็บใบรับรองหลักเซิร์ฟเวอร์โดยใช้สคริปต์ทุบตีถัดไป:

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)


โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.