I have been asking myself, how to interpret the output of openssl regarding certificates, depending on the option (-text or -purpose). Sometimes it is not clear to me, whether - for example - a certificate is meant to be a CA or not.
Example:
openssl x509 -in /path/to/cert1.pem -purpose -noout
Certificate purposes:
SSL client : Yes
SSL client CA : Yes (WARNING code=3)
SSL server : Yes
SSL server CA : Yes (WARNING code=3)
...
But:
openssl x509 -in /path/to/cert1.pem -text -noout | grep CA
This shows no result. However:
openssl x509 -in /path/to/cert2.pem -purpose -noout
Certificate purposes:
SSL client : Yes
SSL client CA : Yes
SSL server : Yes
SSL server CA : Yes
...
And:
openssl x509 -in /path/to/cert2.pem -text -noout | grep CA
CA:TRUE
From the limited output that you provide, it does seem that your cert1.pem is of type X509v1. As such, its -text output does not contain the X509v3 extension that show up in your grep result for cert2.pem.
Some support for this hypothesis starts at the output for cert1.pem, which includes
SSL client CA : Yes (WARNING code=3)
The OpenSSL documentation around the meaning of this warning is limited, but by checking its source code, starting at the apps/x509.c application, traces back to the following function:
static int check_ca(const X509 *x)
{
/* keyUsage if present should allow cert signing */
if (ku_reject(x, KU_KEY_CERT_SIGN))
return 0;
if (x->ex_flags & EXFLAG_BCONS) {
if (x->ex_flags & EXFLAG_CA)
return 1;
/* If basicConstraints says not a CA then say so */
else
return 0;
} else {
/* we support V1 roots for... uh, I don't really know why. */
if ((x->ex_flags & V1_ROOT) == V1_ROOT)
return 3;
/*
* If key usage present it must have certSign so tolerate it
*/
else if (x->ex_flags & EXFLAG_KUSAGE)
return 4;
/* Older certificates could have Netscape-specific CA types */
else if (x->ex_flags & EXFLAG_NSCERT && x->ex_nscert & NS_ANY_CA)
return 5;
/* can this still be regarded a CA certificate? I doubt it */
return 0;
}
}
where you see code value 3 show up.
To verify whether this is the situation, just look at the first line in your text dump of the different certs, which will look like this:
Certificate:
Data:
Version: 1 (0x0)
Going back to the X509 tool documentation page, the following now makes sense:
If the certificate is a V1 certificate (and thus has no extensions)
and it is self signed it is also assumed to be a CA but a warning is
again given: this is to work around the problem of Verisign roots
which are V1 self signed certificates.
From the x509 documentation:
SSL Client CA
The extended key usage extension must be absent or include the "web client authentication" OID. Netscape certificate type must be absent or it must have the SSL CA bit set: this is used as a work around if the basicConstraints extension is absent.
It looks like your certificate has neither x509v3 extensions (basicConstraints nor extendedUsage). As #Reinier-Torenbeek stated, it means that your certificate is of x509 version 1 type.
Related
I am working with a certificate chain with 3 certificates :
ca.crt : Root CA certificate
intermediate.crt : intermediate CA certificate (signed by ca.crt)
cert.crt : the final certificate
I first try to verify with:
openssl verify -CAfile ca.crt -untrusted intermediate.crt cert.crt
I get as result cert.crt: OK
So it's all fine.
But if I create a certificate chain with cat cert.crt intermediate.crt > cert.chain
And then I verify with openssl verify -CAfile ca.crt cert.chain
The result is error 20 at 0 depth lookup:unable to get local issuer certificate
And the cert.chain file is also rejected by a server for the exact same reason.
I don't understand where is the problem.
I first try to verify with: openssl verify -CAfile ca.crt -untrusted intermediate.crt cert.crt
This will take the first certificate out of cert.crt and try to build the trust chain using the given untrusted CA certificates in intermediate.crt up to some root CA certificate in ca.crt.
And then I verify with openssl verify -CAfile ca.crt cert.chain
This will also take the first certificate out of cert.chain. It will ignore remaining certificates in this file. It will then try to build the trust chain to some root CA certificate in ca.crt without using any intermediate CA certificates since none are given. It will thus fail.
And the cert.chain file is also rejected by a server for the exact same reason.
It is unknown what exactly happens here. If it is "rejected by a server" then you likely talk about validating a client certificate by the server. It might simply be that the client application does not send the whole chain to the server but only the first certificate from the file. None is known about this client application though, so this is only speculation.
Thanks to all. Yes, the correct way to verify a chain is with using the "untrusted" parameter of openssl verify to specify the intermediate certificate.
The connection to server was tried with openssl s_client and specifying the certificate chain in the "cert" parameter but it fails. Using a recent openssl version (1.1.0 or newer), it is now possible to add the "cert_chain" parameter to specify the intermediate certificate to use.
Hello you error just related in the fact that you chain is not build correctly.
Normally your verify with untrusted shall not work, that why you're confusing.The correct sequence is below. I invite you to regenerate and recreate your chain.
openssl verify -CAfile ca.crt -untrusted cert.crt intermediate
This will start at the end, (Root > intermediate > cert)
So that, your chain shall be build as following :
cat intermediate.crt cert.crt > chain.crt
Then it shall work.
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.
I'm using boost::asio to establish encrypted connection between client and server applications. I generated a private key file and self signed certificate in the following way:
openssl genrsa -out private_key.pem 2048
openssl req -new -key private_key.pem -out public_key.pem
The generated certificate is:
-----BEGIN CERTIFICATE REQUEST-----
MIICxjCCAa4CAQAwgYAxCzAJBgNVBAYTAkJHMQ4wDAYDVQQIDAVTb2ZpYTEOMAwG
A1UEBwwFU29maWExDDAKBgNVBAoMA0VHVDEMMAoGA1UECwwDU0JTMRMwEQYDVQQD
DApJdmFuIEJvYmV2MSAwHgYJKoZIhvcNAQkBFhFib2JlZmZAZWd0LWJnLmNvbTCC
ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM2OyY0BvtnmtxbPw7tblSc+
2TOopefy1/voELFT+6SCfmmXhIkL7HXcbFekc0z3VtCaSpq64Tk7NMGPtm2XiVt7
Yzftw5pItsgyVwGuCk5sAMZ5qtDVjwTJv6m9TEV4hBA91ypYsXgcYBz4CIIw9Zm9
uSJVznEsnraQE8xFE87D6Z78BLSFej83A7YsGqxPRIbNCtismtj1GeLFegnX/u5l
PeyPa6A4bgXKgtWFoOEfdCQhWxZwxER0la16JAbMPuKmM+ZM0JJOPBhwdDmXEpv4
tvZ+LXgVo8v71jKK1eMTjvQA2e3bBqZFtpPi0gvYTENQE1yXoRE479wPDHqrum8C
AwEAAaAAMA0GCSqGSIb3DQEBCwUAA4IBAQAypIZnsX/C63kdeRoQeMOVJa5CObWr
ALxtQIHdaR83SzY6K1Gg3SybHMnQ3wVUr71/tcuCYri6hJAzFKNYo676EdOxH8X4
IJSNQIHUPBRRvcaB2us+wmAEsHhFytzlBdsYNo1UM+QXgDArV/BeHt9R1GYaN9kz
C8ZSf5IYd/8vjDHRzpoeJ5+n4zMONOtCgXZU2WMEa7n9xbumfTnnZmaYGb3y3VVg
FHtEAFsM1K80zKDW7Nech1vLXnJVi/SS5ABl+jqLOdVVqM+WKaowJY6y+U786by4
q55Eoas7JZQIN+g6LeKywWj59CpYpeMczsp/WygKey6JkQ3qi1FiLaUB
-----END CERTIFICATE REQUEST-----
In my program code, I have the following initialization of SSL context structure:
...
, m_sslContext(ssl::context::sslv23)
...
m_sslContext.set_verify_mode(ssl::verify_peer | ssl::verify_fail_if_no_peer_cert);
m_sslContext.use_rsa_private_key_file("private_key.pem", ssl::context::pem);
m_sslContext.use_certificate_file("public_key.pem", ssl::context::pem);
...
But use_ceritificate_file method throws exception with message:
use_certificate_file: no start line
Why does the function fail and what is the correct way to establish a secure connection with boost::asio wrapper around OpenSSL?
As discussed in the comments, a public-key isn't a certificate. Your public_key.pem however isn't a public-key either. It's a certificate-request which you'd normally send to a certificate-authority to sign it for you. Since you want to sign it yourself, you can check out How to create a self-signed certificate with openssl? to see how to sign your request.
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.
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