Adding a new SSL certificate to solve Verify return code: 20 (unable to get local issuer certificate)?

ssaeed picture ssaeed · Jul 5, 2014 · Viewed 10.9k times · Source

UPDATE: If I let the API call hang and keyboard interrupt it, here is what it shows it was stuck on:

  File "/usr/lib/python2.7/ssl.py", line 405, in do_handshake
    self._sslobj.do_handshake()

Are you guys sure it is not an SSL related issue?

I have been getting an error that seems to be somewhat common, that of "Verify return code: 20 (unable to get local issuer certificate)". With the help of this thread I found a certificate that eliminates the error when I pass the path to a file as an arg, as per this thread. Now how do I permanently make this new certificate my like default certificate?

To be clear, "echo '' | openssl s_client -connect api.stripe.com:443" yields this:

CONNECTED(00000003)
depth=2 C = US, O = DigiCert Inc, OU = www.digicert.com, CN = DigiCert High Assurance EV Root CA
verify error:num=20:unable to get local issuer certificate
verify return:0
---
Certificate chain
 0 s:/C=US/ST=California/L=San Francisco/O=Stripe, Inc./CN=api.stripe.com
   i:/C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert High Assurance CA-3
 1 s:/C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert High Assurance CA-3
   i:/C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert High Assurance EV Root CA
 2 s:/C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert High Assurance EV Root CA
   i:/C=US/O=GTE Corporation/OU=GTE CyberTrust Solutions, Inc./CN=GTE CyberTrust Global Root
---
Server certificate
-----BEGIN CERTIFICATE-----
MIIFHDCCBASgAwIBAgIQCBKNwt21MdAyGnD9g/FpLzANBgkqhkiG9w0BAQUFADBm
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMSUwIwYDVQQDExxEaWdpQ2VydCBIaWdoIEFzc3VyYW5j
ZSBDQS0zMB4XDTEzMDkyNzAwMDAwMFoXDTE1MDEwODEyMDAwMFowajELMAkGA1UE
BhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBGcmFuY2lz
Y28xFTATBgNVBAoTDFN0cmlwZSwgSW5jLjEXMBUGA1UEAxMOYXBpLnN0cmlwZS5j
b20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCbC50FiFYms4rUoW7o
CmW+jw6IUEt1oYyE7bWLMB/rmdGlw3cv7u82WR8HezLH9Fj60NvQhGvAzFYBjRWA
+VnF5rxEYS05piwvF0jR1QSpeMzId7GOrHKV125pPuYzp+Mj44e3nr/uP91ICMVn
gz6U39OqiU9aBUTI8bhuiqcWK+4M7yQ5j9DGcq/wJISfLSr9zVYxOH75TqaMDFUh
EUqaWYpoJatQAYAobATCEVs5uw3T+K0tlRjcxhw5Zx698lajqTGORLwvVcF+ErZ7
ukVNnStu3LyWaR2pMs8zytlx2nepFjIp7m/SCcxTc9GmRY6zubbfo/ih9sjofv2K
nye9AgMBAAGjggHAMIIBvDAfBgNVHSMEGDAWgBRQ6nOJ2yn7EI+e5QEg1N55mUiD
    LnN0cmlwZS5jb20wDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMB
    BggrBgEFBQcDAjBhBgNVHR8EWjBYMCqgKKAmhiRodHRwOi8vY3JsMy5kaWdpY2Vy
    dC5jb20vY2EzLWcyNy5jcmwwKqAooCaGJGh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNv
    bS9jYTMtZzI3LmNybDBCBgNVHSAEOzA5MDcGCWCGSAGG/WwBATAqMCgGCCsGAQUF
    BwIBFhxodHRwczovL3d3dy5kaWdpY2VydC5jb20vQ1BTMHsGCCsGAQUFBwEBBG8w
    bTAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEUGCCsGAQUF
    BzAChjlodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRIaWdoQXNz
    dXJhbmNlQ0EtMy5jcnQwDAYDVR0TAQH/BAIwADANBgkqhkiG9w0BAQUFAAOCAQEA
    j1zUdQBzjpMTeexGYpxMLWW4IYcblZeP03V15WnGnpGq5eaLHKDNJ9K7MRIOtDaw
    K4EVCIO1ru8ojf6eFwcRuozRkbMNSRAYLbFyTS3CWygC1De4vLwuhRxvnpKYcG57
    7kgPx+nxIQtQdauL5AinxXMysY8+GZP1qzc2zlSV0MnvW2p5D3g0lb1ZMFQLpzDm
    ACJcg7xiOrs6lS70EfvcEPrVmRn287aE7b3jEBQ+dkokxNEC0Mi7G4CJQVP1oape
    wtKjWMSeQA/VdUVuoxoUa        gNh7gzLqoc6s7z5HmWVpR1KXiASRFYXsBFeIXnvehJc
    6HeLGqB0qcMYHcE8wmJErA==
-----END CERTIFICATE-----
subject=/C=US/ST=California/L=San Francisco/O=Stripe, Inc./CN=api.stripe.com
issuer=/C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert High Assurance CA-3
---
No client certificate CA names sent
---
SSL handshake has read 4712 bytes and written 443 bytes
---
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
SSL-Session:
    Protocol  : TLSv1.2
    Cipher    : ECDHE-RSA-AES128-GCM-SHA256
    Session-ID: F5EA24F3FE87EA6D4D2D5F8EBBD66811BE85116047AB1111F22968B324698D86
    Session-ID-ctx: 
    Master-Key: EEBA4D6255330C751DACE424844778CAA561F9BA339488CB8B32D78047A681B3066DD683A733732AB778EB1C72FB1EE2
    Key-Arg   : None
    PSK identity: None
    PSK identity hint: None
    SRP username: None
    TLS session ticket lifetime hint: 300 (seconds)
    TLS session ticket:
    0000 - f0 46 61 22 d7 65 e3 95-e7 4b b3 f6 d6 79 9d 69   .Fa".e...K...y.i
    0010 - b1 8d 4a a2 a7 97 ba de-68 1a ff 63 f6 2a 64 34   ..J.....h..c.*d4
    0020 - 44 e6 01 64 d9 a9 ff 26-32 21 be 49 2a fc 85 42   D..d...&2!.I*..B
    0030 - ee eb c8 b1 65 cc 43 be-05 69 e8 d6 5c bd e0 19   ....e.C..i..\...
    0040 - 57 b3 07 5a d4 6b 90 f2-a0 b4 31 96 1f 41 6d 88   W..Z.k....1..Am.
    0050 - e3 23 ea b2 33 e3 33 2e-29 33 ab 30 65 a1 eb 6d   .#..3.3.)3.0e..m
    0060 - 99 66 65 c1 bf 2b e2 25-70 a7 f8 17 c4 4b 8a bd   .fe..+.%p....K..
    0070 - cf 37 6a ee 38 dc 96 c5-24 6b 35 40 1c f1 d6 35   [email protected]
    0080 - 64 0f 78 c7 90 98 f8 08-15 81 73 ce d6 e4 3e 38   d.x.......s...>8
    0090 - af 81 51 ef a1 0b 20 95-09 80 af c8 9d 08 14 e3   ..Q... .........

        Start Time: 1404582660
    Timeout   : 300 (sec)
    Verify return code: 20 (unable to get local issuer certificate)
---
DONE

Whereas "echo '' | openssl s_client -CApath ~/Downloads/DigiCertHighAssuranceEVRootCA.crt -connect api.stripe.com:443" yields this:

CONNECTED(00000003)
depth=3 C = US, O = GTE Corporation, OU = "GTE CyberTrust Solutions, Inc.", CN = GTE CyberTrust Global Root
verify return:1
depth=2 C = US, O = DigiCert Inc, OU = www.digicert.com, CN = DigiCert High Assurance EV Root CA
verify return:1
depth=1 C = US, O = DigiCert Inc, OU = www.digicert.com, CN = DigiCert High Assurance CA-3
verify return:1
depth=0 C = US, ST = California, L = San Francisco, O = "Stripe, Inc.", CN = api.stripe.com
verify return:1
---
Certificate chain
 0 s:/C=US/ST=California/L=San Francisco/O=Stripe, Inc./CN=api.stripe.com
   i:/C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert High Assurance CA-3
 1 s:/C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert High Assurance CA-3
   i:/C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert High Assurance EV Root CA
 2 s:/C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert High Assurance EV Root CA
   i:/C=US/O=GTE Corporation/OU=GTE CyberTrust Solutions, Inc./CN=GTE CyberTrust Global Root
---
Server certificate
-----BEGIN CERTIFICATE-----
MIIFHDCCBASgAwIBAgIQCBKNwt21MdAyGnD9g/FpLzANBgkqhkiG9w0BAQUFADBm
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMSUwIwYDVQQDExxEaWdpQ2VydCBIaWdoIEFzc3VyYW5j
ZSBDQS0zMB4XDTEzMDkyNzAwMDAwMFoXDTE1MDEwODEyMDAwMFowajELMAkGA1UE
BhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBGcmFuY2lz
Y28xFTATBgNVBAoTDFN0cmlwZSwgSW5jLjEXMBUGA1UEAxMOYXBpLnN0cmlwZS5j
b20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCbC50FiFYms4rUoW7o
CmW+jw6IUEt1oYyE7bWLMB/rmdGlw3cv7u82WR8HezLH9Fj60NvQhGvAzFYBjRWA
+VnF5rxEYS05piwvF0jR1QSpeMzId7GOrHKV125pPuYzp+Mj44e3nr/uP91ICMVn
gz6U39OqiU9aBUTI8bhuiqcWK+4M7yQ5j9DGcq/wJISfLSr9zVYxOH75TqaMDFUh
EUqaWYpoJatQAYAobATCEVs5uw3T+K0tlRjcxhw5Zx698lajqTGORLwvVcF+ErZ7
ukVNnStu3LyWaR2pMs8zytlx2nepFjIp7m/SCcxTc9GmRY6zubbfo/ih9sjofv2K
nye9AgMBAAGjggHAMIIBvDAfBgNVHSMEGDAWgBRQ6nOJ2yn7EI+e5QEg1N55mUiD
9zAdBgNVHQ4EFgQUgrT82oRIRdlSABFBqltZv7JNDBAwGQYDVR0RBBIwEIIOYXBp
LnN0cmlwZS5jb20wDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMB
BggrBgEFBQcDAjBhBgNVHR8EWjBYMCqgKKAmhiRodHRwOi8vY3JsMy5kaWdpY2Vy
dC5jb20vY2EzLWcyNy5jcmwwKqAooCaGJGh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNv
bS9jYTMtZzI3LmNybDBCBgNVHSAEOzA5MDcGCWCGSAGG/WwBATAqMCgGCCsGAQUF
BwIBFhxodHRwczovL3d3dy5kaWdpY2VydC5jb20vQ1BTMHsGCCsGAQUFBwEBBG8w
bTAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEUGCCsGAQUF
BzAChjlodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRIaWdoQXNz
dXJhbmNlQ0EtMy5jcnQwDAYDVR0TAQH/BAIwADANBgkqhkiG9w0BAQUFAAOCAQEA
j1zUdQBzjpMTeexGYpxMLWW4IYcblZeP03V15WnGnpGq5eaLHKDNJ9K7MRIOtDaw
K4EVCIO1ru8ojf6eFwcRuozRkbMNSRAYLbFyTS3CWygC1De4vLwuhRxvnpKYcG57
7kgPx+nxIQtQdauL5AinxXMysY8+GZP1qzc2zlSV0MnvW2p5D3g0lb1ZMFQLpzDm
ACJcg7xiOrs6lS70EfvcEPrVmRn287aE7b3jEBQ+dkokxNEC0Mi7G4CJQVP1oape
wtKjWMSeQA/VdUVuoxoUagNh7gzLqoc6s7z5HmWVpR1KXiASRFYXsBFeIXnvehJc
6HeLGqB0qcMYHcE8wmJErA==
-----END CERTIFICATE-----
subject=/C=US/ST=California/L=San Francisco/O=Stripe, Inc./CN=api.stripe.com
issuer=/C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert High Assurance CA-3
---
    No client certificate CA names sent
---
SSL handshake has read 4712 bytes and written 443 bytes
---
New, TLSv1/SSLv3, Cipher is ECDHE-RSA-AES128-GCM-SHA256
Server public key is 2048 bit
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
SSL-Session:
    Protocol  : TLSv1.2
    Cipher    : ECDHE-RSA-AES128-GCM-SHA256
    Session-ID: 7ACAFB7EFC59892B2FD356197EE62E8E94F05DA51FAC29C21CA4790D69916169
    Session-ID-ctx: 
    Master-Key: 4E58BAB4E6C5C36BFEE31C5AA49AB8B22C6ADB684C3A7A9FC1FE2D899676C5CDF2823C51E35120E61FA04F2291DBBF0D
    Key-Arg   : None
    PSK identity: None
    PSK identity hint: None
    SRP username: None
    TLS session ticket lifetime hint: 300 (seconds)
    TLS session ticket:
    0000 - 89 ab 9c 38 a7 3e 8a ae-43 22 63 ea fa 5d db 7e   ...8.>..C"c..].~
    0010 - b8 31 46 06 ba d7 5f ed-0f f4 58 47 ef 18 9c fc   .1F..._...XG....
    0020 - bf a5 ff f0 17 27 15 b0-ab 0e 38 53 6a f2 54 95   .....'....8Sj.T.
    0030 - 7a 68 0a f6 78 2d 30 ec-1b 54 27 3f 58 8f b0 59   zh..x-0..T'?X..Y
    0040 - 95 93 c1 fb 67 8c 1b 94-85 76 74 59 35 f7 c5 06   ....g....vtY5...
    0050 - 2e a1 41 cb 49 c0 6f 3d-77 d5 4b 4a 7f fd 9c d2   ..A.I.o=w.KJ....
    0060 - 07 4a 52 e6 04 8f 63 9b-fd a6 7b 94 5b 1e 3d 50   .JR...c...{.[.=P
    0070 - e3 77 dd b9 da 56 e7 5b-16 09 15 a8 b5 02 b7 07   .w...V.[........
    0080 - 1e 31 39 cb 07 c7 85 45-25 0c a6 d8 10 93 bc 21   .19....E%......!
    0090 - e8 0d b9 3c 08 8a 99 ce-75 eb 41 5e fe 5e af 8e   ...<....u.A^.^..

    Start Time: 1404583006
    Timeout   : 300 (sec)
    Verify return code: 0 (ok)
---
DONE

And the latter seems to me to solve this problem, if only I could make that "permanent". Would the solution be to convert it to PEM and put it in /usr/lib/ssl/certs/ ?

If so, I am having trouble converting the certificate to PEM. I get the following, which I am currently "researching":

$ openssl x509 -in DigiCertHighAssuranceEVRootCA.crt  -out  DigiCertHighAssuranceEVRootCA.pem -outform PEM
unable to load certificate
3074123452:error:0906D06C:PEM routines:PEM_read_bio:no start line:pem_lib.c:703:Expecting: TRUSTED CERTIFICATE

EDIT: argh, successfully converted to .pem and moved it to that dir and it didn't make a difference.

For background, this isn't on a like a production server or anything, this is just on my computer, which runs Xubuntu. I ran into this problem out of the blue while trying to run a script to interact with Stripe's API. The same script was running fine as wine the day before. Then all of the sudden the API calls started timing out. I contacted Stripe support, which was uncharacteristically slow, and the guy gave me some commands to run which brought to light this issue. Still waiting on a response back from them, but this seems to be the problem. I am hoping that using the certificate I downloaded all the time will allow me to once again interact with the Stripe API when I do things other than "echo '' | openssl s_client -connect api.stripe.com:443"

if anyone has any guesses as to what I might have inadvertently done to cause this problem all of the sudden, I would really appreciate. Been kind of flabbergasted as to why this occurred.

EDIT:

I have been asked for the Stripe script itself.

import stripe

STRIPE_SECRET = "mys3cretkey"
STRIPE_PUBLISHABLE = "testkeypublishable"

stripe.api_key = STRIPE_SECRET
customer = stripe.Customer.retrieve('cus_4FJ2a8cSopzrwQ')
print customer['created']

However, I would like to reiterate that this and every other Stripe related script and action were working just fine until a few days ago. I have been making Stripe API calls and web scraping and all sorts of other stuff blissfully oblivious to certs and ssl handshakes for months before this problem arose a few days ago. Also, Stripe's doc provide examples of API calls with your key and test info on the right, so you can just copy that and play around with it. Copying that doesn't work either. Making test transactions on our "site" on my local environment doesn't work either.

But, ha, it has worked like 1/12 times since the problem started...it's weird...

I tried echo '' | openssl s_client -connect google.com:443 as well and I got the same issue. So that is reason to think this problem is not Stripe-specific, though they did have some trouble with people connecting to their API they day these problems arose for me, trouble they said on Twitter was resolved. (And our production site is fine).

Edit: Been asked to provide a little more info.

  1. Things that may have changed. The only thing that comes to mind as possibly affecting this is that I have started using my VM more. Note "more"--I was using it before and running these scripts just fine. It is a Windows 7 VM I use for .NET work. (For the curious, it runs poorly).

  2. Errors from Stripe. If I let the script hang long enough, I get a traceback the end of witch is this:

      File "/usr/local/lib/python2.7/dist-packages/stripe/http_client.py", line 140, in     _handle_request_error
    raise error.APIConnectionError(msg)
    stripe.error.APIConnectionError: Unexpected error communicating with Stripe.  If this problem persists,
    let us know at [email protected].
    
    (Network error: Timeout: HTTPSConnectionPool(host='api.stripe.com', port=443): Read timed out.)
    
  3. The scripts and openssl tests are both just on my local machine here, my laptop. When I referenced test transactions on our site, that was localhost here, with the same Stripe test API key as the scripts.

Thanks

Answer

Steffen Ullrich picture Steffen Ullrich · Jul 5, 2014

You need to add the path where s_client should look for the certificates, because it does not use any default path. This should work:

openssl s_client -CApath /etc/ssl/certs/ -connect api.stripe.com:443

There should be no need to any any certificates to /etc/ssl/certs, because the relevant CA should already be included with (X)ubuntu.