简体   繁体   中英

Python ssl.get_server_certificate downloads wrong certificate?

I'm trying to download SSL certificates using Python 3 and ssl.get_server_certificate so my tool can deal with self-signed certificates in a generic way. However, when I run this:

$ python
Python 3.7.0 (default, Sep 15 2018, 19:13:07) 
[GCC 8.2.1 20180831] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import ssl
>>> ssl.get_server_certificate(('self-signed.badssl.com', 443))
'-----BEGIN CERTIFICATE-----\nMIIE8DCCAtigAwIBAgIJAM28Wkrsl2exMA0GCSqGSIb3DQEBCwUAMH8xCzAJBgNV\nBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1TYW4gRnJhbmNp\nc2NvMQ8wDQYDVQQKDAZCYWRTU0wxMjAwBgNVBAMMKUJhZFNTTCBJbnRlcm1lZGlh\ndGUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MB4XDTE2MDgwODIxMTcwNVoXDTE4MDgw\nODIxMTcwNVowgagxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYw\nFAYDVQQHDA1TYW4gRnJhbmNpc2NvMTYwNAYDVQQKDC1CYWRTU0wgRmFsbGJhY2su\nIFVua25vd24gc3ViZG9tYWluIG9yIG5vIFNOSS4xNDAyBgNVBAMMK2JhZHNzbC1m\nYWxsYmFjay11bmtub3duLXN1YmRvbWFpbi1vci1uby1zbmkwggEiMA0GCSqGSIb3\nDQEBAQUAA4IBDwAwggEKAoIBAQDCBOz4jO4EwrPYUNVwWMyTGOtcqGhJsCK1+ZWe\nsSssdj5swEtgTEzqsrTAD4C2sPlyyYYC+VxBXRMrf3HES7zplC5QN6ZnHGGM9kFC\nxUbTFocnn3TrCp0RUiYhc2yETHlV5NFr6AY9SBVSrbMo26r/bv9glUp3aznxJNEx\ntt1NwMT8U7ltQq21fP6u9RXSM0jnInHHwhR6bCjqN0rf6my1crR+WqIW3GmxV0Tb\nChKr3sMPR3RcQSLhmvkbk+atIgYpLrG6SRwMJ56j+4v3QHIArJII2YxXhFOBBcvm\n/mtUmEAnhccQu3Nw72kYQQdFVXz5ZD89LMOpfOuTGkyG0cqFAgMBAAGjRTBDMAkG\nA1UdEwQCMAAwNgYDVR0RBC8wLYIrYmFkc3NsLWZhbGxiYWNrLXVua25vd24tc3Vi\nZG9tYWluLW9yLW5vLXNuaTANBgkqhkiG9w0BAQsFAAOCAgEAsuFs0K86D2IB20nB\nQNb+4vs2Z6kECmVUuD0vEUBR/dovFE4PfzTr6uUwRoRdjToewx9VCwvTL7toq3dd\noOwHakRjoxvq+lKvPq+0FMTlKYRjOL6Cq3wZNcsyiTYr7odyKbZs383rEBbcNu0N\nc666/ozs4y4W7ufeMFrKak9UenrrPlUe0nrEHV3IMSF32iV85nXm95f7aLFvM6Lm\nEzAGgWopuRqD+J0QEt3WNODWqBSZ9EYyx9l2l+KI1QcMalG20QXuxDNHmTEzMaCj\n4Zl8k0szexR8rbcQEgJ9J+izxsecLRVp70siGEYDkhq0DgIDOjmmu8ath4yznX6A\npYEGtYTDUxIvsWxwkraBBJAfVxkp2OSg7DiZEVlMM8QxbSeLCz+63kE/d5iJfqde\ncGqX7rKEsVW4VLfHPF8sfCyXVi5sWrXrDvJm3zx2b3XToU7EbNONO1C85NsUOWy4\nJccoiguV8V6C723IgzkSgJMlpblJ6FVxC6ZX5XJ0ZsMI9TIjibM2L1Z9DkWRCT6D\nQjuKbYUeURhScofQBiIx73V7VXnFoc1qHAUd/pGhfkCUnUcuBV1SzCEhjiwjnVKx\nHJKvc9OYjJD0ZuvZw9gBrY7qKyBX8g+sglEGFNhruH8/OhqrV8pBXX/EWY0fUZTh\niywmc6GTT7X94Ze2F7iB45jh7WQ=\n-----END CERTIFICATE-----\n'

It doesn't return the same certificate as openssl s_client :

$  openssl s_client -connect self-signed.badssl.com:443 -servername self-signed.badssl.com -showcerts
CONNECTED(00000005)
depth=0 C = US, ST = California, L = San Francisco, O = BadSSL, CN = *.badssl.com
verify error:num=18:self signed certificate
verify return:1
depth=0 C = US, ST = California, L = San Francisco, O = BadSSL, CN = *.badssl.com
verify return:1
---
Certificate chain
 0 s:C = US, ST = California, L = San Francisco, O = BadSSL, CN = *.badssl.com
   i:C = US, ST = California, L = San Francisco, O = BadSSL, CN = *.badssl.com
-----BEGIN CERTIFICATE-----
MIIDeTCCAmGgAwIBAgIJAPlgiuOcJ/T1MA0GCSqGSIb3DQEBCwUAMGIxCzAJBgNV
BAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1TYW4gRnJhbmNp
c2NvMQ8wDQYDVQQKDAZCYWRTU0wxFTATBgNVBAMMDCouYmFkc3NsLmNvbTAeFw0x
ODA4MTUxNTIxNTNaFw0yMDA4MTQxNTIxNTNaMGIxCzAJBgNVBAYTAlVTMRMwEQYD
VQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1TYW4gRnJhbmNpc2NvMQ8wDQYDVQQK
DAZCYWRTU0wxFTATBgNVBAMMDCouYmFkc3NsLmNvbTCCASIwDQYJKoZIhvcNAQEB
BQADggEPADCCAQoCggEBAMIE7PiM7gTCs9hQ1XBYzJMY61yoaEmwIrX5lZ6xKyx2
PmzAS2BMTOqytMAPgLaw+XLJhgL5XEFdEyt/ccRLvOmULlA3pmccYYz2QULFRtMW
hyefdOsKnRFSJiFzbIRMeVXk0WvoBj1IFVKtsyjbqv9u/2CVSndrOfEk0TG23U3A
xPxTuW1CrbV8/q71FdIzSOciccfCFHpsKOo3St/qbLVytH5aohbcabFXRNsKEqve
ww9HdFxBIuGa+RuT5q0iBikusbpJHAwnnqP7i/dAcgCskgjZjFeEU4EFy+b+a1SY
QCeFxxC7c3DvaRhBB0VVfPlkPz0sw6l865MaTIbRyoUCAwEAAaMyMDAwCQYDVR0T
BAIwADAjBgNVHREEHDAaggwqLmJhZHNzbC5jb22CCmJhZHNzbC5jb20wDQYJKoZI
hvcNAQELBQADggEBAKr7JtZHTDuYs8/vGDFrtXb+dkjdNsZEIgyVh4vWZtLOANtO
39wM/LwGXUSjonEsYJabJgYpRdRSex41f78QfnARJona7fkcc1aHci7jdrzsxaNJ
iCc4G49ahgJ1NEIFmRNeEYlKYNNFeyGT6wxkLaV9AnC45MHlaumQyrRJwuXCQH/i
16Wk/qDtsu2nw6t+13OqwGfxR9krxDikVFO0YqgSMhqPmufz/6nY6uaXuOqzGv+P
rjJZDqCoRmVMqrISIUALWGCF3yasrViM6owIEhtN71UwrFZYYOeZ9nw2wvRK210z
c8LlWjgG56wRkLrq/mSINsQ3xmChO1PsBAeSHDU=
-----END CERTIFICATE-----
---
Server certificate
subject=C = US, ST = California, L = San Francisco, O = BadSSL, CN = *.badssl.com

issuer=C = US, ST = California, L = San Francisco, O = BadSSL, CN = *.badssl.com

---
No client certificate CA names sent
Peer signing digest: SHA512
Peer signature type: RSA
Server Temp Key: ECDH, P-256, 256 bits
---
SSL handshake has read 1599 bytes and written 450 bytes
Verification error: self signed certificate
---
New, TLSv1.2, Cipher is ECDHE-RSA-AES128-GCM-SHA256
Server public key is 2048 bit
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
SSL-Session:
    Protocol  : TLSv1.2
    Cipher    : ECDHE-RSA-AES128-GCM-SHA256
    Session-ID: FF42F7711650D30FCB32C352CED98BB7EE5E4A6CC1EC5398150CE5398D740B72
    Session-ID-ctx: 
    Master-Key: D8174DC9863D4D2700432501BD315312473279C24478141D9CCDB03EA6E2EB9779CF98FA998A76E8A591BAC77FBA9CEB
    PSK identity: None
    PSK identity hint: None
    SRP username: None
    TLS session ticket lifetime hint: 300 (seconds)
    TLS session ticket:
    0000 - 84 88 44 09 93 10 49 77-c5 12 b5 3a 9b 2a 06 75   ..D...Iw...:.*.u
    0010 - a7 34 c2 95 8b cd db 80-81 68 09 9f b1 79 8e da   .4.......h...y..
    0020 - c9 0f f0 d1 3d 74 39 81-58 ac 9b b6 9c e4 3f 51   ....=t9.X.....?Q
    0030 - 5d 89 12 aa e7 78 9a 8b-0b c5 74 8c d4 6e 79 8f   ]....x....t..ny.
    0040 - b0 25 3a 5f 72 8f f1 6c-24 30 b9 b9 19 23 33 ae   .%:_r..l$0...#3.
    0050 - 1c f1 d7 20 4f 88 60 32-1a cd a1 25 34 d0 03 6d   ... O.`2...%4..m
    0060 - c2 e2 25 0d 6f d9 22 6c-6a 92 df bd 3a 02 fe 2f   ..%.o."lj...:../
    0070 - 4a 9a 23 84 b0 d9 27 ec-05 9c 3a e7 bc 2e a2 4e   J.#...'...:....N
    0080 - ca 42 f3 5f 57 cc 90 e5-c8 42 de 91 c3 99 eb b5   .B._W....B......
    0090 - 9b 27 c1 12 2d 17 46 c4-52 ff 4a a3 93 22 10 b8   .'..-.F.R.J.."..
    00a0 - 45 74 db 7f e4 66 6d 10-dd b7 49 e4 da 9c e5 b6   Et...fm...I.....
    00b0 - 08 bb 50 68 69 b3 f9 e8-37 69 9f c1 68 9a ce 0e   ..Phi...7i..h...
    00c0 - c9 cc 23 49 50 de ee 08-22 61 0d dd 3c a2 32 44   ..#IP..."a..<.2D

    Start Time: 1539840980
    Timeout   : 7200 (sec)
    Verify return code: 18 (self signed certificate)
    Extended master secret: no
---

And I can't use the former certificate for verification, whereas the latter works.

What am I doing wrong?

Edit: Addressed "duplicate" comment below, replaced openssl call.

While not documented as such get_server_certificate treats the given (host,port) only as the target for connection but does not set host as the server_name in the TLS SNI extension like browsers would do. This results in the following certificate:

$ python3 -c 'import ssl; print(ssl.get_server_certificate(("self-signed.badssl.com", 443)))' |\
  openssl x509 -text
...
  Subject:... O=BadSSL Fallback. Unknown subdomain or no SNI., CN=badssl-fallback-unknown-subdomain-or-no-sni

Contrary to this openssl s_client ... when using the -servername option (and also without this options in newer versions of openssl ) will set the SNI extension to the given hostname which results in:

$ openssl s_client -connect self-signed.badssl.com:443 -servername self-signed.badssl.com  |\
  openssl x509 -text
...
  Subject: C=US, ST=California, L=San Francisco, O=BadSSL, CN=*.badssl.com

When not using the SNI extension either by forgetting the -servername option in older versions of openssl or by explicitly setting -noservername in newer versions one gets the same certificate as returned by get_server_certificate :

$ openssl s_client -connect self-signed.badssl.com:443 [-noservername]  |\
  openssl x509 -text
...
  Subject:... O=BadSSL Fallback. Unknown subdomain or no SNI., CN=badssl-fallback-unknown-subdomain-or-no-sni

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM