2

As a test of my TLS/SSL knowledge, I'm trying to verify wikipedia.org's TLS cert. I have downloaded the server-distributed certificate to a file called cert.pem and the root cert (from Globalsign's public cert page here) into a file called Root-R3.pem. When I attempt to validate the certificate by passing the root and cert into openssl's verify utility using STDIN, like so:

cat Root-R3.pem cert.pem | openssl verify -verbose

OpenSSL returns 0 and I get the following message out:

stdin: OK

However, when I attempt to pass the files directly into OpenSSL's verify tool, like so:

openssl verify -CAfile Root-R3.pem cert.pem

OpenSSL returns 2 and I get the following message out:

cert.pem: C = US, ST = California, L = San Francisco, O = "Wikimedia Foundation, Inc.", CN = *.wikipedia.org
error 20 at 0 depth lookup:unable to get local issuer certificate

Why is it that I get two different results for (what I feel is) the same request - verifying the server cert from the root cert?

Bonus points - why is the verbose flag not doing anything? Seems like I can call verify anyway I want and the verbose flag is useless.

I'm on macos, and the openssl command is being aliased to LibreSSL v2.6.5. The output of the cat command is below the horizontal dash.


> cat Root-R3.pem  cert.pem

-----BEGIN CERTIFICATE-----
MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkG
A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv
b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw
MDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i
YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT
aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ
jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp
xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp
1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG
snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ
U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8
9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E
BTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0B
AQUFAAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOz
yj1hTdNGCbM+w6DjY1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE
38NflNUVyRRBnMRddWQVDf9VMOyGj/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymP
AbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhHhm4qxFYxldBniYUr+WymXUad
DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME
HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIIMTCCBxmgAwIBAgIMFkDF1F0uxNlMfXxqMA0GCSqGSIb3DQEBCwUAMGYxCzAJ
BgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMTwwOgYDVQQDEzNH
bG9iYWxTaWduIE9yZ2FuaXphdGlvbiBWYWxpZGF0aW9uIENBIC0gU0hBMjU2IC0g
RzIwHhcNMTgxMTA4MjEyMTA0WhcNMTkxMTIyMDc1OTU5WjB5MQswCQYDVQQGEwJV
UzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzEj
MCEGA1UEChMaV2lraW1lZGlhIEZvdW5kYXRpb24sIEluYy4xGDAWBgNVBAMMDyou
d2lraXBlZGlhLm9yZzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABGd1rS7GauMx
J15BmViShjVMjwQJNjjw+OUhnIaqE5QF/q6c/LIvVh4N3473a7J52JcfmlfCrXvD
thHzaZNEneKjggWVMIIFkTAOBgNVHQ8BAf8EBAMCA4gwgaAGCCsGAQUFBwEBBIGT
MIGQME0GCCsGAQUFBzAChkFodHRwOi8vc2VjdXJlLmdsb2JhbHNpZ24uY29tL2Nh
Y2VydC9nc29yZ2FuaXphdGlvbnZhbHNoYTJnMnIxLmNydDA/BggrBgEFBQcwAYYz
aHR0cDovL29jc3AyLmdsb2JhbHNpZ24uY29tL2dzb3JnYW5pemF0aW9udmFsc2hh
MmcyMFYGA1UdIARPME0wQQYJKwYBBAGgMgEUMDQwMgYIKwYBBQUHAgEWJmh0dHBz
Oi8vd3d3Lmdsb2JhbHNpZ24uY29tL3JlcG9zaXRvcnkvMAgGBmeBDAECAjAJBgNV
HRMEAjAAMEkGA1UdHwRCMEAwPqA8oDqGOGh0dHA6Ly9jcmwuZ2xvYmFsc2lnbi5j
b20vZ3MvZ3Nvcmdhbml6YXRpb252YWxzaGEyZzIuY3JsMIICxQYDVR0RBIICvDCC
AriCDyoud2lraXBlZGlhLm9yZ4INd2lraW1lZGlhLm9yZ4INbWVkaWF3aWtpLm9y
Z4INd2lraWJvb2tzLm9yZ4IMd2lraWRhdGEub3Jnggx3aWtpbmV3cy5vcmeCDXdp
a2lxdW90ZS5vcmeCDndpa2lzb3VyY2Uub3Jngg93aWtpdmVyc2l0eS5vcmeCDndp
a2l2b3lhZ2Uub3Jngg53aWt0aW9uYXJ5Lm9yZ4IXd2lraW1lZGlhZm91bmRhdGlv
bi5vcmeCBncud2lraYISd21mdXNlcmNvbnRlbnQub3JnghEqLm0ud2lraXBlZGlh
Lm9yZ4IPKi53aWtpbWVkaWEub3JnghEqLm0ud2lraW1lZGlhLm9yZ4IWKi5wbGFu
ZXQud2lraW1lZGlhLm9yZ4IPKi5tZWRpYXdpa2kub3JnghEqLm0ubWVkaWF3aWtp
Lm9yZ4IPKi53aWtpYm9va3Mub3JnghEqLm0ud2lraWJvb2tzLm9yZ4IOKi53aWtp
ZGF0YS5vcmeCECoubS53aWtpZGF0YS5vcmeCDioud2lraW5ld3Mub3JnghAqLm0u
d2lraW5ld3Mub3Jngg8qLndpa2lxdW90ZS5vcmeCESoubS53aWtpcXVvdGUub3Jn
ghAqLndpa2lzb3VyY2Uub3JnghIqLm0ud2lraXNvdXJjZS5vcmeCESoud2lraXZl
cnNpdHkub3JnghMqLm0ud2lraXZlcnNpdHkub3JnghAqLndpa2l2b3lhZ2Uub3Jn
ghIqLm0ud2lraXZveWFnZS5vcmeCECoud2lrdGlvbmFyeS5vcmeCEioubS53aWt0
aW9uYXJ5Lm9yZ4IZKi53aWtpbWVkaWFmb3VuZGF0aW9uLm9yZ4IUKi53bWZ1c2Vy
Y29udGVudC5vcmeCDXdpa2lwZWRpYS5vcmcwHQYDVR0lBBYwFAYIKwYBBQUHAwEG
CCsGAQUFBwMCMB0GA1UdDgQWBBSt4NNfC33t2i98DfZjjYpZGMJsijAfBgNVHSME
GDAWgBSW3mHxvRwWKVMcwMx9O4MAQOYafDCCAQQGCisGAQQB1nkCBAIEgfUEgfIA
8AB2AKS5CZC0GFgUh7sTosxncAo8NZgE+RvfuON3zQ7IDdwQAAABZvUzN/YAAAQD
AEcwRQIgBATdvSzbd5NwGdtkmJ5SEvEPn6A8hgAsk6GSP6hzWcgCIQDKfHQNtObs
/hHPfLgXsVkcnHIbjlNwmWeiukGtGHZFMgB2AG9Tdqwx8DEZ2JkApFEV/3cVHBHZ
AsEAKQaNsgiaN9kTAAABZvUzN8cAAAQDAEcwRQIgYalEnXtd/fPhjq9SXPoSPRha
MmeDs0IMN5o5Y6QTKfUCIQClR1uj+B56K4tGh/mws4qugG1qSD9zfvmx8roKik3H
HDANBgkqhkiG9w0BAQsFAAOCAQEAUEJyg/AZo+owG5J/LIk8EIDnyOcanmfgvdjM
g8KnpBvh8l3Wb4HmOudluJhIeIbCUMwzEzSGqYQQ78n4wtjLaLwaDgL4WzHOVec2
k+rbfmPT6MUCtdlz1PK5/WY9JQyQq6vy+tm3a6Wijy6M8U/TdrJubK5X03SFfRb0
pDuFdr2fnkctLRnyCb1w0XHwGXjEcGm1LY42YKwdvbj3WIqumeSEuG4MZtquW6NU
RKELSil03G/hRHRAHHGx3zXes/jJcpH2GPX9eY9B+R1oHmCE2QF5Y/Bh+uNA2+2I
uj/6UJAOw/Z/8+qZcnLWWnK2Dwzc34C/AUD+Wb71oUcr60+pPg==
-----END CERTIFICATE-----
  • Thanks @AndrolGenhald for fixing my copy error. :) – distortedsignal Feb 12 at 20:50
5

The openssl command line tools are notoriously bad. They weren't originally intended for use by end users, they're not documented that well, and many of the defaults are insecure. But I digress.


Let's take a look at your first command

cat Root-R3.pem cert.pem | openssl verify -verbose

What verify is doing here is reading Root-R3.pem, noticing that it's self signed (and therefore must be a root certificate), looking at your openssl config to find where trusted certificates are kept, and since it returned OK it must have found one that matched. No further data is read from stdin, cert.pem is completely ignored.

You can override you default configured CApath and see that it fails, as no trusted certificates are provided:

$ cat Root-R3.pem cert.pem | openssl verify -verbose -CApath /dev/null
C = BE, O = GlobalSign nv-sa, OU = Root CA, CN = GlobalSign Root CA
error 18 at 0 depth lookup: self signed certificate
error stdin: verification failed

You can also add whatever data you want after Root-R3.pem and see that it has no effect:

$ { cat Root-R3.pem; head -c 1000 /dev/urandom; } | openssl verify -verbose
stdin: OK

Now your second command

openssl verify -CAfile Root-R3.pem cert.pem

This one fails with unable to get local issuer certificate because you're missing the intermediate that signed cert.pem.


How to verify it correctly

If you run openssl x509 to inspect the certificate you'll see:

$ openssl x509 -in cert.pem -text -noout
Certificate:
    ...
    Signature Algorithm: sha256WithRSAEncryption
        ...
        X509v3 extensions:
            ...
            Authority Information Access: 
                CA Issuers - URI:http://secure.globalsign.com/cacert/gsorganizationvalsha2g2r1.crt
                OCSP - URI:http://ocsp2.globalsign.com/gsorganizationvalsha2g2
    ...

The CA Issuers line is there because the certificate includes the location of its signer. You can download it, and since it's in DER format, convert it from DER to PEM:

$ wget http://secure.globalsign.com/cacert/gsorganizationvalsha2g2r1.crt -O intermediate.crt
...
$ openssl x509 -inform der -in intermediate.crt -out intermediate.pem

Now that you have the intermediate you can verify the certificate.

Verifying against your configured trust store

$ openssl verify -untrusted intermediate.pem cert.pem
cert.pem: OK

Verifying against the root you downloaded

$ openssl verify -CAfile Root-R3.pem -untrusted intermediate.pem cert.pem
cert.pem: OK
  • Yo, thank you so much - you have no idea how frustrating this is for me. This is a great answer. +10 – distortedsignal Feb 12 at 23:03
  • @distortedsignal Not quite sure how I missed that -inform, thanks for the edit! – AndrolGenhald Feb 13 at 0:16
  • you got 95% of the way there - it's teamwork that gets us over the top! :) – distortedsignal Feb 13 at 5:49
1

if we print both certificates using openssl x509 -in Root-R3.pem -text and so on, we can see that Root-R3.pem has subject Subject: C=BE, O=GlobalSign nv-sa, OU=Root CA, CN=GlobalSign Root CA and cert.pem has issuer Issuer: C=BE, O=GlobalSign nv-sa, CN=GlobalSign Organization Validation CA - SHA256 - G2

You can see that they are different and this is the reason openssl says that root certificate can't be used for building certificate chain that starts with the leaf certificate.

  • To clarify - openssl needs all the intermediate certs to be passed in so that the verify command can do its verification on the full chain? Am I getting that right? – distortedsignal Feb 12 at 23:25
  • Yes, openssl needs all certificates in the certificate chain - from the leaf certificate to self-signed root certificate. In your example I saw just two certificates - leaf and root, no intermediate. Do you have them? – Oleg Feb 12 at 23:28
  • Yes - I think that @AndrolGenhald showed how to get the intermediate cert in their answer. I should have assumed that it was more complicated than just passing in the root and leaf files, but I couldn't find documentation on how to format the call. Thanks for the answer! – distortedsignal Feb 12 at 23:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.