Testing an Intermediate Certificate Locally

by Tykling


17. jan 2019 14:17 UTC


Background

Today I was testing out https support on a partner API. They've been using a selfsigned certificate during development, and since they will move to production soon the certificate has been replaced by a CA signed certificate from GoDaddy.

I was still getting certificate errors though, and I suspected that they'd forgotten to include the intermediate certificate from the issuer. I wanted to check locally which intermediate to use so I could send an easily actionable error report to the partner.

I've changed the partners domain to example.com to protect the innocent.

The Certificate

First things first, I use openssl s_client -showcerts for connecting and showing the certificate:

[tsr@mrx2 ~]$ echo | openssl s_client -showcerts -connect chayntest.example.com:7000                                                                                                                                                                                  
CONNECTED(00000003)
depth=0 OU = Domain Control Validated, CN = *.example.com
verify error:num=20:unable to get local issuer certificate
verify return:1
depth=0 OU = Domain Control Validated, CN = *.example.com
verify error:num=21:unable to verify the first certificate
verify return:1
---
Certificate chain
 0 s:/OU=Domain Control Validated/CN=*.example.com
   i:/C=US/ST=Arizona/L=Scottsdale/O=GoDaddy.com, Inc./OU=http://certs.godaddy.com/repository//CN=Go Daddy Secure Certificate Authority - G2
-----BEGIN CERTIFICATE-----
MIIFJDCCBAygAwIBAgIJAKPtTjF+G3fhMA0GCSqGSIb3DQEBCwUAMIG0MQswCQYD
VQQGEwJVUzEQMA4GA1UECBMHQXJpem9uYTETMBEGA1UEBxMKU2NvdHRzZGFsZTEa
MBgGA1UEChMRR29EYWRkeS5jb20sIEluYy4xLTArBgNVBAsTJGh0dHA6Ly9jZXJ0
cy5nb2RhZGR5LmNvbS9yZXBvc2l0b3J5LzEzMDEGA1UEAxMqR28gRGFkZHkgU2Vj
dXJlIENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTE3MDMxNTEyMDkwMFoX
DTE5MDMxNDA4MDIzOFowODEhMB8GA1UECxMYRG9tYWluIENvbnRyb2wgVmFsaWRh
dGVkMRMwEQYDVQQDDAoqLndhb28ub3JnMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
MIIBCgKCAQEAvt4LPzD5G63y/QI8Iue9QFqmgQeBLHVd5mR7Bsj/SXNuVzLxFTQA
x0ZSWa6Ux0y734r1zoHz4f3sM8OVVwdQgq9AbvL8Sj9wozNFUIQSCCO6vxRW74W+
7ff54pwxhfxiy14cw3koAqmW6uqcrbJZFEPvFWyoq11TyXB6aIfv+/dIMs03lrdG
Iaf5aPbZcBnB5iH+6CR13ZBIeyegXg93pWnevETBus9GJTW15Q/J2IBn1KdWVjg1
6H1nWmuyTMhR6NiDPVfP7l9uJGc6HxfdH+XBLkbEnz+BZT+CnzVmW/CF68dFiqNK
6z4Zv54hbZolyjwiQkV+clvBlKMjeG5CAwIDAQABo4IBsjCCAa4wDAYDVR0TAQH/
BAIwADAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDgYDVR0PAQH/BAQD
AgWgMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6Ly9jcmwuZ29kYWRkeS5jb20vZ2Rp
ZzJzMS00NDAuY3JsMF0GA1UdIARWMFQwSAYLYIZIAYb9bQEHFwEwOTA3BggrBgEF
BQcCARYraHR0cDovL2NlcnRpZmljYXRlcy5nb2RhZGR5LmNvbS9yZXBvc2l0b3J5
LzAIBgZngQwBAgEwdgYIKwYBBQUHAQEEajBoMCQGCCsGAQUFBzABhhhodHRwOi8v
b2NzcC5nb2RhZGR5LmNvbS8wQAYIKwYBBQUHMAKGNGh0dHA6Ly9jZXJ0aWZpY2F0
ZXMuZ29kYWRkeS5jb20vcmVwb3NpdG9yeS9nZGlnMi5jcnQwHwYDVR0jBBgwFoAU
QMK9J47MNIMwojPX+2yz8LQsgM4wHwYDVR0RBBgwFoIKKi53YW9vLm9yZ4IId2Fv
by5vcmcwHQYDVR0OBBYEFEoeWTF5dogGGN9DOCT/+L4avvEfMA0GCSqGSIb3DQEB
CwUAA4IBAQBFF/N1sNJjQbLloXKRtmwRlwSZ+zJv6L0hKVYjgXSHSqS6faSSxPZx
M1O0ERWkyT4iyGX93v1w/wqJFmHqU1xeu6dbggaHc3l5lN3RIidM3+sDbSbZd5Jr
VNrfVsJgdtKFLpBHRTDbhuDzKb8MdAc5wbktCYNpoFn5mDHKY7mvOScr96+K8Vbp
kzVJBj5CYT2N33KGop83gIzw4JGNbaNgsajPAdY/tXZUtvT3BwUpt+slh8RG0NsH
2XJpzZteJZYu+k8LZtHIeXO29/5Q+/sUoYOVfphUmJej4rai+ChaCSAS2pzsVh+r
rjA6T74+9zDOdrWhp6b01nFxKM4k4roK
-----END CERTIFICATE-----
---
Server certificate
subject=/OU=Domain Control Validated/CN=*.example.com
issuer=/C=US/ST=Arizona/L=Scottsdale/O=GoDaddy.com, Inc./OU=http://certs.godaddy.com/repository//CN=Go Daddy Secure Certificate Authority - G2
---
No client certificate CA names sent
Peer signing digest: SHA512
Server Temp Key: ECDH, P-256, 256 bits
---
SSL handshake has read 2011 bytes and written 433 bytes
---
New, TLSv1/SSLv3, Cipher is ECDHE-RSA-AES256-GCM-SHA384
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-AES256-GCM-SHA384
    Session-ID: 08C7F3C3174C6E5338B01111A552336920C16237E1C4337AD6421A4C6904BC9F
    Session-ID-ctx: 
    Master-Key: E7FFBF6E1F932BE1386EA315370D68AB3E2C6CF4FB75CD328123E1627BE0BB4A462E3CCC17D5FA6465D54FDF11AC3F80
    Key-Arg   : None
    PSK identity: None
    PSK identity hint: None
    SRP username: None
    TLS session ticket lifetime hint: 300 (seconds)
    TLS session ticket:
    0000 - 6e 3d 11 dc 55 42 af 04-51 7e 45 0b 99 8a ab 4d   n=..UB..Q~E....M
    0010 - bb 08 af a4 9c 22 0e b3-ab ad de 93 8b 2b d0 5b   .....".......+.[
    0020 - 97 12 9c e9 95 f0 aa 42-84 37 00 02 af a0 86 01   .......B.7......
    0030 - 9c f2 d3 8e 76 db 81 77-50 c3 eb 3e 2e 5f 55 fc   ....v..wP..>._U.
    0040 - dc b4 c2 6f d1 22 30 96-f4 bc 00 30 2f bb 24 7c   ...o."0....0/.$|
    0050 - 11 17 0b a5 51 af 52 d9-98 d9 23 0b 32 08 36 18   ....Q.R...#.2.6.
    0060 - 55 80 e5 b7 2f 14 53 61-ce b4 96 91 6e 30 1e b8   U.../.Sa....n0..
    0070 - 87 4e 23 dc 9e 0b 65 40-8a d1 f8 fd 91 df 86 43   .N#...e@.......C
    0080 - 71 f6 0d 8a 4c d9 b2 02-f0 d3 d7 1a 60 ee fa 2d   q...L.......`..-
    0090 - 02 c6 3a 71 99 3c e9 20-50 fa 74 98 50 bb 25 3f   ..:q.<. P.t.P.%?
    00a0 - 4d 2e df ea 01 3a 78 ba-f1 a5 fc 5b ba 93 5e 45   M....:x....[..^E
    00b0 - 08 74 91 56 28 1b 5d b1-43 b5 b4 fa 97 c5 74 e5   .t.V(.].C.....t.

    Start Time: 1547734089
    Timeout   : 300 (sec)
    Verify return code: 21 (unable to verify the first certificate)
---
DONE
[tsr@mrx2 ~]$ 

The important part here is verify error:num=20:unable to get local issuer certificate which tells me that OpenSSL is unable to verify the certificate using my operating systems list of trusted CAs. This might be because of a missing intermediate certificate.

The Testbed

To work out which intermediate needs to be installed I first create an empty folder to work in, and then copy the server certificate into a file - that is, from -----BEGIN CERTIFICATE----- to -----END CERTIFICATE----- and everything between:

[tsr@mrx2 ~]$ mkdir cert
[tsr@mrx2 ~]$ cd cert/
[tsr@mrx2 ~/cert]$ cat < wildcard.example.com.crt
> -----BEGIN CERTIFICATE-----
> MIIFJDCCBAygAwIBAgIJAKPtTjF+G3fhMA0GCSqGSIb3DQEBCwUAMIG0MQswCQYD
> VQQGEwJVUzEQMA4GA1UECBMHQXJpem9uYTETMBEGA1UEBxMKU2NvdHRzZGFsZTEa
> MBgGA1UEChMRR29EYWRkeS5jb20sIEluYy4xLTArBgNVBAsTJGh0dHA6Ly9jZXJ0
> cy5nb2RhZGR5LmNvbS9yZXBvc2l0b3J5LzEzMDEGA1UEAxMqR28gRGFkZHkgU2Vj
> dXJlIENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTE3MDMxNTEyMDkwMFoX
> DTE5MDMxNDA4MDIzOFowODEhMB8GA1UECxMYRG9tYWluIENvbnRyb2wgVmFsaWRh
> dGVkMRMwEQYDVQQDDAoqLndhb28ub3JnMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
> MIIBCgKCAQEAvt4LPzD5G63y/QI8Iue9QFqmgQeBLHVd5mR7Bsj/SXNuVzLxFTQA
> x0ZSWa6Ux0y734r1zoHz4f3sM8OVVwdQgq9AbvL8Sj9wozNFUIQSCCO6vxRW74W+
> 7ff54pwxhfxiy14cw3koAqmW6uqcrbJZFEPvFWyoq11TyXB6aIfv+/dIMs03lrdG
> Iaf5aPbZcBnB5iH+6CR13ZBIeyegXg93pWnevETBus9GJTW15Q/J2IBn1KdWVjg1
> 6H1nWmuyTMhR6NiDPVfP7l9uJGc6HxfdH+XBLkbEnz+BZT+CnzVmW/CF68dFiqNK
> 6z4Zv54hbZolyjwiQkV+clvBlKMjeG5CAwIDAQABo4IBsjCCAa4wDAYDVR0TAQH/
> BAIwADAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDgYDVR0PAQH/BAQD
> AgWgMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6Ly9jcmwuZ29kYWRkeS5jb20vZ2Rp
> ZzJzMS00NDAuY3JsMF0GA1UdIARWMFQwSAYLYIZIAYb9bQEHFwEwOTA3BggrBgEF
> BQcCARYraHR0cDovL2NlcnRpZmljYXRlcy5nb2RhZGR5LmNvbS9yZXBvc2l0b3J5
> LzAIBgZngQwBAgEwdgYIKwYBBQUHAQEEajBoMCQGCCsGAQUFBzABhhhodHRwOi8v
> b2NzcC5nb2RhZGR5LmNvbS8wQAYIKwYBBQUHMAKGNGh0dHA6Ly9jZXJ0aWZpY2F0
> ZXMuZ29kYWRkeS5jb20vcmVwb3NpdG9yeS9nZGlnMi5jcnQwHwYDVR0jBBgwFoAU
> QMK9J47MNIMwojPX+2yz8LQsgM4wHwYDVR0RBBgwFoIKKi53YW9vLm9yZ4IId2Fv
> by5vcmcwHQYDVR0OBBYEFEoeWTF5dogGGN9DOCT/+L4avvEfMA0GCSqGSIb3DQEB
> CwUAA4IBAQBFF/N1sNJjQbLloXKRtmwRlwSZ+zJv6L0hKVYjgXSHSqS6faSSxPZx
> M1O0ERWkyT4iyGX93v1w/wqJFmHqU1xeu6dbggaHc3l5lN3RIidM3+sDbSbZd5Jr
> VNrfVsJgdtKFLpBHRTDbhuDzKb8MdAc5wbktCYNpoFn5mDHKY7mvOScr96+K8Vbp
> kzVJBj5CYT2N33KGop83gIzw4JGNbaNgsajPAdY/tXZUtvT3BwUpt+slh8RG0NsH
> 2XJpzZteJZYu+k8LZtHIeXO29/5Q+/sUoYOVfphUmJej4rai+ChaCSAS2pzsVh+r
> rjA6T74+9zDOdrWhp6b01nFxKM4k4roK
> -----END CERTIFICATE-----
> EOF
[tsr@mrx2 ~/cert]$ 

Now, the issuer of this certificate is also mentioned in the OpenSSL output above, including a URL to their repository:

issuer=/C=US/ST=Arizona/L=Scottsdale/O=GoDaddy.com, Inc./OU=http://certs.godaddy.com/repository//CN=Go Daddy Secure Certificate Authority - G2

I went to http://certs.godaddy.com/repository/ and downloaded the certificate labeled GoDaddy Class 2 Certification Authority Root Certificate - G2 with the filename gdroot-g2.crt and put that in the same folder.

[tsr@mrx2 ~/cert]$ fetch https://certs.godaddy.com/repository/gdroot-g2.crt
gdroot-g2.crt                                         1367  B   16 MBps    00s
[tsr@mrx2 ~/cert]$ ls -l
total 9
-rw-r--r--  1 tsr  tsr  1367 Nov  1 23:11 gdroot-g2.crt
-rw-r--r--  1 tsr  tsr  1842 Jan 17 14:15 wildcard.example.com.crt
Before OpenSSL can use my new CA dir I need to run c_rehash:
[tsr@mrx2 ~/cert]$ ls -l
total 9
-rw-r--r--  1 tsr  tsr  1367 Nov  1 23:11 gdroot-g2.crt
-rw-r--r--  1 tsr  tsr  1842 Jan 17 14:15 wildcard.example.com.crt
[tsr@mrx2 ~/cert]$ c_rehash .
Doing .
[tsr@mrx2 ~/cert]$ ls -l
total 10
lrwxr-xr-x  1 tsr  tsr    21 Jan 17 14:44 376492c8.0 -> wildcard.example.com.crt
lrwxr-xr-x  1 tsr  tsr    13 Jan 17 14:44 cbf06781.0 -> gdroot-g2.crt
-rw-r--r--  1 tsr  tsr  1367 Nov  1 23:11 gdroot-g2.crt
-rw-r--r--  1 tsr  tsr  1842 Jan 17 14:15 wildcard.example.com.crt
[tsr@mrx2 ~/cert]$ 
A quick test verifies that the test setup works. I still haven't added the intermediate cert so I would expect the same result as with my OS CAdir. I add -CApath . to the OpenSSL command to make it use the new one:
[tsr@mrx2 ~/cert]$ echo | openssl s_client -showcerts -CApath . -connect chayntest.example.com:7000 > /dev/null
depth=0 OU = Domain Control Validated, CN = *.example.com
verify error:num=20:unable to get local issuer certificate
verify return:1
depth=0 OU = Domain Control Validated, CN = *.example.com
verify error:num=21:unable to verify the first certificate
verify return:1
DONE
[tsr@mrx2 ~/cert]$ 

Still no dice, as expected.

The Fix

Lets see what happens when we add the intermediate into the mix. I go back to the GoDaddy cert page and downloaded the first intermediate I could find in the G2 section, labeled GoDaddy Secure Server Certificate (Intermediate Certificate) - G2 with the filename gdig2.crt.pem. I then run c_rehash again to make OpenSSL recognise the new certificate:

[tsr@mrx2 ~/cert]$ fetch https://certs.godaddy.com/repository/gdig2.crt.pem
gdig2.crt.pem                                         1728  B   42 kBps    00s
[tsr@mrx2 ~/cert]$ c_rehash . 
Doing .
[tsr@mrx2 ~/cert]$ echo | openssl s_client -showcerts -CApath . -connect chayntest.example.com:7000 > /dev/null
depth=2 C = US, ST = Arizona, L = Scottsdale, O = "GoDaddy.com, Inc.", CN = Go Daddy Root Certificate Authority - G2
verify return:1
depth=1 C = US, ST = Arizona, L = Scottsdale, O = "GoDaddy.com, Inc.", OU = http://certs.godaddy.com/repository/, CN = Go Daddy Secure Certificate Authority - G2
verify return:1
depth=0 OU = Domain Control Validated, CN = *.example.com
verify return:1
DONE
[tsr@mrx2 ~/cert]$ 

Much better. I have confirmed that gdig2.crt.pem is the missing intermediate for the partners server and I sent them an email (which was handled very quickly).

I could have just told them "still doesn't work", but in my experience going the extra mile for a partner or customer can pay off in unexpected ways sometimes.

Search this blog

Tags for this blogpost