How to get the Root CA Certificate Fingerprint using openssl - ssl

By using the following command, I can verify the sha1 fingerprint of the presented certificate:
$ openssl s_client -connect hooks.slack.com:443 -showcerts < /dev/null 2>/dev/null | openssl x509 -in /dev/stdin -sha1 -noout -fingerprint
SHA1 Fingerprint=AB:F0:5B:A9:1A:E0:AE:5F:CE:32:2E:7C:66:67:49:EC:DD:6D:6A:38
But what if I want to get the fingerprint of the Top Level Signing Authority?
$ openssl s_client -connect hooks.slack.com:443 < /dev/null 2>/dev/null
CONNECTED(00000003)
---
Certificate chain
0 s:/C=US/ST=California/L=San Francisco/O=Slack Technologies, Inc/CN=*.slack.com
i:/C=US/O=GeoTrust Inc./CN=GeoTrust SSL CA - G3
1 s:/C=US/O=GeoTrust Inc./CN=GeoTrust SSL CA - G3
i:/C=US/O=GeoTrust Inc./CN=GeoTrust Global CA <- **I WANT THIS SHA1**
In the case that I want to verify this against a Java keystore, to check definitively if it contains the same CA.
geotrustglobalca, 18-Jul-2003, trustedCertEntry,
Certificate fingerprint (SHA1): DE:28:F4:A4:FF:E5:B9:2F:A3:C5:03:D1:A3:49:A7:F9:96:2A:82:12
Since "geotrustglobalca" and "/C=US/O=GeoTrust Inc./CN=GeoTrust Global CA" aren't really comparable.

In a similar situation with a let's encrypt certificate on a shared hosting solution I had success with specifying the servername parameter:
openssl s_client -connect hooks.slack.com:443 -servername hooks.slack.com -showcerts < /dev/null 2>/dev/null | openssl x509 -in /dev/stdin -sha1 -noout -fingerprint

Since "geotrustglobalca" and "/C=US/O=GeoTrust Inc./CN=GeoTrust Global CA" aren't really comparable.
I'll wander into the pool with an answer for "X.509 certificate equivalency" since its not readily apparent or easy to come by.
First, you should be careful comparing certificates for equality. If <certificate bits 1> == <certificate bits 2>, then you can say they are the exact same certificate and equal. However, the converse does not hold.
To understand the converse, you need to know two things. First, CAs sometimes re-issue a certificate with nearly the same parameters. Based on the Subject Name, they are equivalent; but based on the bits they are not equal. Some CAs have done this in the past to bump from SHA-1 to SHA-256.
The second thing to understand is, what are the important bits so you can determine if certificates are equivalent. The IETF does not have an X.509 validation document. The closest is RFC 4158: Internet X.509 Public Key Infrastructure: Certification Path Building, mixed with some other docs, like Issuing rules (which are not the same as Validation rules).
According to RFC 4158, you can uniquely identify a certificate with either:
{Issuer DN, Serial Number} pair
{Authority Key identifier (AKID), Subject Key identifier (SKID)} pair
The corner case of a CA re-issuing a Root CA results in:
the hash changes
the serial number changes
the public key remains
the Distinguished Name remains
Item (3), the public key remains, is significant because it means neither the Authority Key identifier (AKID) nor the Subject Key identifier (SKID) changes. Item (4), the Distinguished Name remains, is significant because its what many people use for the comparison (and its been the cause of many security bugs over the years).
In this case, the Key Identifiers will be the same, so you should consider accepting even though the serial number changed. (The serial number must change according to IETF and CA/B rules).
A very odd corner case that came up in public key pinning recently is, a server presents a Elliptic Curve certificate using domain parameters (the full expansion of p, g, Q, etc), but the client expects a named curve (like secp256r1). Should this key be accepted as equivalent? (The IETF says the certificate must use the named curve).
Given the above information, this information is useless in your comparison:
"geotrustglobalca"
And this information is incomplete for your comparison:
"/C=US/O=GeoTrust Inc./CN=GeoTrust Global CA"
In this case, you should err on the side of caution and reject the comparison for equality or equivalence.

I'm not sure this directly answers your question, but if the server presents the root certificate as part of the chain (this is optional, so it may not), you can use the -showcerts option to show all of them.
I put this together previously (which hopefully someone can improve upon) in order to get the thumbprint for each of the certificates. You can play with the arguments to openssl x509 at the end to get different information if you need.
echo "" | openssl s_client -showcerts -connect eistest.mtsu.edu:443 2>&1 |\
sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p;/-END CERTIFICATE-/a\\x0' |\
sed -e '$ d' |\
xargs -0rl -I% sh -c "echo '%' | openssl x509 -subject -issuer -fingerprint -noout"
Echoing a null string to openssl s_client keeps it from waiting for the connection to time out.
The first sed will output only the PEM formatted certificates, separated by a NUL character.

Related

TLS Mutual Auth: null cert chain (C client -> Java server) unless cafile points to same file as cert

I have an issue with the server rejecting the client certificate in the handshake if I issue openssl call with just the cert (with chain) and private key.
This issue goes away if I also set the cafile param and point it to the same file as the cert.
It seems as if openssl cannot construct the chain without the cafile input even if the information is already in the cert input. I wonder if you guys had experience with this. I just find it a bit odd.
To summarize, this works:
sudo openssl s_client -connect <ip>:<port> -cert cert_with_chain.pem -key privkey.pem -CAfile cert_with_chain.pem
This doesn't work (Server reject with "null cert chain"):
sudo openssl s_client -connect <ip>:<port> -cert cert_with_chain.pem -key privkey.pem
Open SSL version:
OpenSSL 1.0.2k-fips 26 Jan 2017
The problem is not that "openssl cannot construct the chain without the cafile" but that it wasn't the intention in the first place to do so. The intended behavior is well documented in man s_client:
-cert certname The certificate to use, if one is requested by the server.
-CAfile file A file containing trusted certificates to use during server authentication and to use when attempting to build the client
certificate chain.

Generate CRT & KEY ssl files from Let's Encrypt from scratch

I'd like to generate a CRT/KEY couple SSL files with Let's Encrypt (with manual challenge).
I'm trying something like this :
certbot certonly --manual -d mydomain.com
But I only get these files in my /etc/letsencrypt/live/mydomain.com folder :
cert.pem
chain.pem
fullchain.pem
privkey.pem
Did I missed something?
I'm the author of Greenlock, a certbot-compatible Let's Encrypt v2 client, so I've had to learn the ins and outs of all these things as well.
Hopefully this helps:
KEY
privkey.pem is the "key" file
Sometimes it is improperly named as cert.key or example.com.key.
CRT
fullchain.pem is your "crt" file.
Sometimes it is improperly named as example.com.crt.
CRT/KEY Bundle
bundle.pem would be made like so: cat fullchain.pem privkey.pem > bundle.pem
HAProxy is the only server that I know of that uses bundle.pem.
cert.pem
cert.pem contains ONLY your certificate, which can only be used by itself if the browser already has the certificate which signed it, which may work in testing (which makes it seem like it may be the right file), but will actually fail for many of your users in production with a security error of untrusted certificate.
However, you don't generally use the cert.pem by itself. It's almost always coupled with chain.pem as fullchain.pem.
chain.pem
chain.pem is the intermediary signed authority, signed by the root authority - which is what all browsers are guaranteed to have in their pre-built cache.
Checking certs
You can inspect the cert only like so:
openssl x509 -in cert.pem -text -noout
There's a list of useful commands here:
https://www.sslshopper.com/article-most-common-openssl-commands.html

Openssl verify with chained CA and chained Cert

I have a certificate chain as:
root CA -> intermediate CA -> org CA -> client Cert
When I verify the client cert with CA as root CA -> intermediate CA -> org CA, it works:
$ cat org_1_ca/ca_crt.pem intermediate_ca/ca_crt.pem root_ca/ca_crt.pem > /tmp/test123.pem
$ openssl verify -CAfile /tmp/test123.pem client/client_crt.pem
client_crt.pem: OK
But when I chained my client cert with org CA (org CA -> client Cert), and have the rest of the chain as CA (root CA -> intermediate CA), it doesn't:
$ cat intermediate_ca/ca_crt.pem root_ca/ca_crt.pem > /tmp/test12.pem
$ openssl verify -CAfile /tmp/test12.pem client/org1_client_crt.pem
client/org1_client_crt.pem: C = US, ST = CA, L = LA, O = PP, OU = TEST, CN = user
error 20 at 0 depth lookup:unable to get local issuer certificate
Is this something that fundamentally wrong or openssl verify doesn't like that? I tried the same thing with nginx and and openssl connect and there was no luck there. Any help is appreciated.
The openssl commandline verify operation reads only one certificate, the first one, from the file given as operand, or from each file if more than one is given. This differs from the files specified with the -CAfile -trusted -untrusted options which can (and typically do) contain multiple certs.
Your file client/org1_client_crt.pem presumably contains the client cert and the 'org CA' cert, in that order. Only the client cert is used, the 'org CA' cert is ignored, and as a result you do not have a valid chain to verify.
If you want to use commandline to mimic/test the validation that a receiver (for a client cert, the server) would do, supply the leaf cert as the operand and all other transmitted (chain) certs with -untrusted, and the anchor(s) plus any 'known' intermediates in the truststore either explicit or defaulted.
There is no openssl connect operation; I assume you mean openssl s_client with options including -connect since that's one place it would make sense to use a client cert chain. The -cert option to s_client similarly uses only the first cert in the file. There is no option on commandline to specify the client chain except in the most recent version, 1.1.0, and even there it isn't documented so you have to read the help message carefully or the code, although the API/library has long supported this for code you write yourself.
Through 1.0.2 if you want to send a client cert with full chain to the server (as you should per the RFCs), assuming the server requests client authentication which is not usual and not the default for nginx (among others), you have to use a trick: supply all the certs needed for the client chain in the truststore, in addition to the anchor(s) needed to verify the server, either using -CAfile and/or -CApath explicitly, or using (modifying if needed) the default truststore unless your openssl is an older non-RedHat version where the default truststore didn't work in s_client s_server s_time only.
And the same is true about the server cert/chain in s_server except that it is used almost always instead of very rarely.

Problems verifying SSL certificate

For school we are currently studying SSL certificates.
For this week's assignment we had to install Fedora Workstation on VirtualBox and do some SSL-stuff.
One of the assignments was the following:
generate a public/private keypair and a CSR with the openssl command.
I generated a public/private keypair using the following command:
openssl genrsa -out Desktop/mykey.key 2048
After I generated the keypair I had to verify it. But how do you verify a key? What is really meant by that? Just get out the public key and check if it matches the private key? This is the first question.
I generated the CSR using the following command:
openssl req -new -key Desktop/mykey.key -out Desktop/myCSR.csr
This is the right way, right?
Checking/verifying the CSR file was done using this command:
openssl req -text -noout -verify -in Desktop/myCSR.csr
I think that's the right way too.
This was the "easy" part, now comes the harder part:
We had to use xca to create a database and a CA Root Certificate. Then we had to import the csr from above question and sign it. I signed it by right clicking on it and choosing sign. Then we had to export both the CA and the signed key and verify it. But what do they mean exactly? My guess is to verify that the certificate is signed by the CA, but I'm having problems with that.
We have to use openssl x509 for that, but it just isn't working.
When I right click the signed key and export it as a PEM file, in that file is the following:
----- BEGIN CERTIFICATE REQUEST -----
MIIC6......
----- BEGIN CERTIFICATE REQUEST -----
while the assigment says: export the signed certificate. But is this even a certificate?
And how do I verify it?
I used many commands, like
openssl x509 -in Desktop/exported.pem -text -noout
But the output I get is always something like this:
I have tried all sorts of commands and read all google pages, but nothing helps.
this is the second question
Hope you all can help, Thanks!
When you verify a certificate, you are checking whether it's CA is recognised, and it matches the CA's fingerprint. It doesn't look like you are providing the CA cert to the openssl command. Try specifying -CA <your CA cert file:
$ openssl x509 --help
...
-CA arg - set the CA certificate, must be PEM format.

How does the browser deal with missing intermediate certs

I've come across the site https://alpower.com, this site is only providing its own site certificate. Because of this I can't access the site properly with cURL as the cacerts used are only root certsificates.
The site is accessible in Firefox however. How exactly is Firefox able to verify the site's identity where as cURL isn't?
Browsers will cache intermediate certificates. So if the missing certificate was already provided by another site the browser will have it already and will use it. But, if you use a fresh browser profile you might get the same problems as you get with curl, because the intermediate certificate is not cached.
This is at least how it works with Firefox. Other browsers might look into the Authority Information Access section of the certificate and if they find the URL issuer certificate they will download the certificate to continue with the chain verification.
Most browsers are using the AIA information embedded in the certificate (see comment on browsers exceptions).
To expose the URL of the CA Issuer with openssl:
openssl x509 -in "YOUR_CERT.pem" -noout -text
There is a section Authority Information Access with CA Issuers - URI which would be the "parent" certificate (intermediate or root certificate).
This can be reproduced up to the root CA.
In a gist:
ssl_endpoint=<ENDPOINT:443>
# first, get the endpoint cert
echo | openssl s_client -showcerts -connect $ssl_endpoint 2>/dev/null | openssl x509 -outform PEM > endpoint.cert.pem
# then extract the intermediate cert URI
intermediate_cert_uri=$(openssl x509 -in endpoint.cert.pem -noout -text | (grep 'CA Issuers - URI:' | cut -d':' -f2-))
# and get the intermediate cert (convert it from DER to PEM)
curl -s "${intermediate_cert_uri}" | openssl x509 -outform PEM -inform DER > intermediate.cert.pem