OpenSSL generate certificate chain - ssl

I found this service https://whatsmychaincert.com/ that generate a chain (with the root) by pasting a certificate.
There is any way for generate the chain with OpenSSL?
I have found this command:
openssl s_client -connect example.com:443 -showcerts
that show all certificate chain, but requires that the certificate is already online.
there is any way for generate the chain with a local file certificate?

s_client -showcerts shows the chain as provided by the server; this should be the full chain optionally less root, but as that website says some servers aren't configured correctly. It also has a link "How does this work" which as one might expect explains how it works:
mkcertchain is a utility for building a chain of intermediate certificates
for an SSL certificate. It downloads the chain certificate from the URL
specified in the certificate's "CA Issuers" field, recurring until
encountering a root certificate that's trusted in all major browsers.
If multiple certificate chains are found, the shortest one is used.
Given a starting cert in a file, or outputtable by some program (such as perhaps a database query), in either PEM or 'DER' (binary) format, openssl x509 -text [-inform pem|der] outputs all of the cert data including 'CA Issuers'. Any number of text-handling programs like awk, perl, grep, shells such as bash, or PowerShell, should be able to extract that line and its value, and since it is normally http:, any number of HTTP-request programs like curl and wget can fetch the cert. Any scripting language like perl, shell or PowerShell can iterate this process as needed, stopping when a root is hit by comparing Subject and Issuer. If you want to stop at an anchor that is not a root that's a little more complicated, but I don't think any such anchors are currently accepted by major browsers, thus aren't needed for the purpose of building a chain to be accepted by browsers.
FWIW, even if your certs don't have the CA Issuers field in AIA, most public CAs including intermediates have now been captured by the certificate transparency logs, which are easily searchable at https://crt.sh ; you can easily navigate through the chain just by clicking links so I haven't thought about trying to automate it, although presumably the numerous tools that 'drive' or simulate a web browser to interact with a website would work here.
And of course, the CA that issued your cert in the first place should always be able to supply the needed chain certs; it's part of their job.

Related

Is it possible to combine multiple CA certificates into a single CA file?

I have two MQTT server environments: PROD and PILOT. These environments each have their own separate certificate authorities. I have one client which can use either CA certificate to connect to each environment. Is it possible to combine these two CA files into a single file so that the CA file need not be changed in the client when I change the environment?
Sample client:
mosquitto_sub -h server.com --cafile /path/to/ca.file
Please note that the CA files contains intermediate CA as well. Please refer another post where I mention this.
From the man page:
--cafile
Define the path to a file containing PEM encoded CA certificates that are trusted. Used to enable SSL communication.
Note the certificates in plural form :-)
Your file should only contain trust-anchors - the Root CA certificates. The other certificates in the chain should be sent by the server. You should consider reconfiguring your server so that the whole chain is sent in line with the TLS protocol (read certificate_list here).
While it often works, placing intermediate certificates in the trust-anchors store doesn't help matters. If you were to renew the intermediate (which happens more often than the root) then you will need to replace the intermediate in all your clients. Might not be an issue in your case, but in the real-world that is a major headache. Also, depending on the libraries used and how the developers wrote the client, it may not check revocation of the intermediate if it is used as a trust-anchor.
The file pointed to by --cafile should be a concatenation of PEM encoded Root CA certificates.

How does keytool work: privateKeyEntry and trustedCertEntry?

Ok first I'll say what I know about how SSL works.
Most of all I need to understand how the client certificate works, because I was setting up mTls istio gateway and had trouble with it.
So, firstly I need key-pair, private and public. If I understood correctly, i create them next with the following command:
keytool -genkey -alias myKeyPair -keyalg RSA -keysize 2048 store.jks
If I look in the keystore there will be one PrivateKeyEntry. Next I create request for certificate:
keytool -certreq -keyalg RSA -alias myKeyPair -file request.csr -keystore store.jks
After a while, I received a signed client certificate client.cer and certificate trusted CA ca.cer.
Now there are questions:
First, i tried to send request from curl. But curl needs private key which stored in jks. I dont have openssl and cant get it, so i extract private key using java code. But the result was always the same: istio gateway: peer did not return a certificate
Second, I tried using java.net.http.HttpClient with SSLContext setting containing my jks. And it worked. But firstly I had to put ca.cer and client.cer in my jks. And this I cannot understand: why do I need to put ca.cer? Because without ca.cer stored in store.jks i have error certificate validation.
Also when I put client.cer in jks, keytool displays a warning: Certificate already exists in keystore under alias <myKeyPair>. Do you still want to add it? Why does it think privateKeyEntry and trustedCertEntry are the same?
Meta: a poor answer due to the vagueness of the question, but much too long for comments.
First, i tried to send request from curl. But curl needs private key which stored in jks. I dont have openssl and cant get it, so i extract private key using java code. But the result was always the same: istio gateway: peer did not return a certificate
Either your 'extract' was wrong or the way you provided it to curl was wrong, or both, and you described neither. First, to be clear, like any client doing client auth, curl actually needs the privatekey and certificate, and usually any applicable chain certificate(s). What file format(s) you must use, and whether a single combined file or separate files (added:) or none at all as it turns out, depends on the curl build you are using: curl supports seven SSL/TLS implementations, and the ways to provide client-key-and-cert vary among them. Use curl -V (uppercase) to see how it was built, then look at the portions of the man page, on your system or on the web, that apply to that implementation.
Second, I tried using java.net.http.HttpClient with SSLContext setting containing my jks. And it worked. But firstly I had to put ca.cer and client.cer in my jks. And this I cannot understand: why do I need to put ca.cer? Because without ca.cer stored in store.jks i have error certificate validation.
Possibly it is a 'chain' or intermediate CA cert. An SSL/TLS client (like a server) is required by the standard to send any chain cert(s) needed to connect the end-entity (client or server) cert to normally a 'root' in the receiver's truststore. (Since RFC5280, and confirmed by RFC8446, it is actually possible to use an anchor that isn't a root, but it is rare to do so.) Possibly it is even a combination of chain cert(s) and root (or anchor). (Some reliers sometimes can still build the chain to validate a cert when it wasn't correctly sent; browsers especially tend to do this, but most servers not.)
Look at it and see. If it is PEM format you can see with any text display or edit program how many certs it contains. If it is a single cert you can display the details with keytool -printcert -file $file -- or since you already imported it, keytool -list -v -alias name -keystore $ks [-storepass $pw]. If it is multiple certs in PEM format you can break it apart with an editor and display each one separately. If it is multiple certs in DER format you won't be able to handle that easily, but fortunately that format is rarely used. openssl x509 [-inform pem|der] -text -noout is also commonly used to display cert file details, but you say you can't use it.
Also when I put client.cer in jks, keytool displays a warning: Certificate already exists in keystore under alias . Do you still want to add it? Why does it think privateKeyEntry and trustedCertEntry are the same?
If you only did this once, and correctly, it shouldn't. Given separate cert
files, you should keytool -importcert the client cert to the alias of the privatekey entry you created, and used to create the -certreq, which in your example is myKeyPair, after you keytool -importcert any needed chain cert(s), and optionally the root or anchor, (each) to a different alias. (It is often convenient, but not required, to use simple words like root, imed, imed2 etc. as aliases.) Alternatively, if you have the whole chain as a single file, either PEM sequence or DER sequence, or 'p7b' (a dummy PKCS7 SignedData with no data and no signature, commonly used as a container for one or more certs, such as a chain) either PEM or DER, you should import that chain in a single operation.

Can't make Guzzle accept a certificate

I'm trying to have a server A communicate with a server B through HTTPS requests. Server B has a certificate that was issued to me by my employer, and connecting to it through both Safari and Chrome works without any issues.
However, when trying to send a request from A to B through Guzzle, I get the following error:
GuzzleHttp/Exception/RequestException with message 'cURL error 60: SSL certificate problem:
unable to get local issuer certificate (see https://curl.haxx.se/libcurl/c/libcurl-errors.html)'
I've tried setting the cert file as a parameter ( [verify => '/path/to/cert.pem'] ), but, first of all, I only had .crt, .csr and .key files; I tried making a .pem file through these instructions I found somewhere else:
(optional) Remove the password from the Private Key by following the steps listed below:
openssl rsa -in server.key -out nopassword.key
Note: Enter the pass phrase of the Private Key.
Combine the private key, public certificate and any 3rd party intermediate certificate files:
cat nopassword.key > server.pem
cat server.crt >> server.pem
Note: Repeat this step as needed for third-party certificate chain files, bundles, etc:
cat intermediate.crt >> server.pem
This didn't work – the error's the same. The request works with 'verify' set to false, but that's obviously not an option for production.
Certificates are not something I usually work with, so I'm having a lot of trouble just figuring out where the issue might lie, let alone fix it. Any help would be much appreciated.
Edit
I've also tried the solutions suggested in Guzzle Curl Error 60 SSL unable to get local issuer to no avail.
This was happening because the only certificate I had configured on server B was the End User certificate.
I'm new to this, so my explanation will probably be flawed, but from my understanding End User certificates link back to a trusted Certificate Authority (CA) certificate, with zero or more intermediate certificates in-between. Browsers can figure out this certificate chain, and download the required certificates that are missing; cURL does not.
Therefore, the solution was configuring Server B with the missing certificates. How to do this is a whole different issue, so I won't go into it in this answer.

CA certified .cert file on Tomcat 9 (Linux server) , tomcat command not working

The Keytool commands for Tomcat SSL includes self-signed certificates which doesn't work with my CA certified cert. I tried creating keystore and importing it with root, intermediate and server cert. On changing the connector port in Tomcat/conf/server.xml started tomcat server but browser URL not reflecting that URL is safe/certificate chain.
openssl pkcs12 -export -in mycert.crt -inkey mykey.key -out mycert.p12 -name tomcat -CAfile myCA.crt -caname root -chain
This is the command provided in Apache document, but how to import intermediate certificate in this command?
Meta: this isn't really a programming or development question. Plus I'm pretty sure it's partly duplicate because I remember writing most of this answer before, but I can't find it now; if I do later I will add.
First, to be clear, changing the port in a Tomcat <Connector> doesn't enable SSL/TLS (HTTPS). Enabling SSL/TLS requires changing several other attributes and (usually) elements in the <Connector>, and does NOT require changing the port, although you often (probably usually) do change both together.
Also, you need the intermediate cert(s) for a proper SSL/TLS server but you don't need the root cert. All SSL/TLS standards explicitly allow the server to omit the root cert from the chain transmitted in the handshake, most non-Java servers do so, and all clients I have ever seen accept it. The Java KeyStore capability was designed to support multiple applications and not just SSL/TLS, so to be safe keytool encourages you to include the root, but with other tools like OpenSSL it's easy to omit it. OTOH if you want for some reason to include it, that's permitted and does work.
(To be pedantic, it's actually the (trust) anchor not the root. Traditionally the anchor was expected to be the root, but over time it has developed that it might not. RFC8446 for TLS1.3 in 2018 is the first SSL/TLS specification to reflect this, and even there it's extremely rare, so I will ignore it.)
Answer: to include chain and/or root cert(s) in a PKCS12 file created with OpenSSL commandline, there are two approaches:
manually determine the correct/desired cert(s) and supply them in either the -in option (which defaults to stdin, which in turn can be piped from e.g. cat) or -certfile (specifying a file containing one or more cert PEM blocks)
specify -chain and provide in the working truststore at least the correct cert(s). OpenSSL will automatically select the cert(s) that chain from the leaf cert, ignoring any others.
As with nearly all commandline operations, the working truststore can consist of -CAfile which is a file (only one) containing any number of cert PEM blocks; or -CApath which is a directory containing any number of files each containing one cert PEM block and with a name (or symlink) based on the subject hash, as described in the man page for c_rehash(1) on your system ((1ssl) or similar on some) or on the web; or both.
If -CAfile -CApath are not specified, and not suppressed by -no-CAfile -no-CApath (in 1.1.0 up only), they default to a file and directory configured at compile time, but upstream does not supply any contents for such a file and/or directory. Linux distros I am familiar with all build OpenSSL to use locations in /etc somewhere (but they vary as to where) and have a package named something like ca-certificates that provides default contents for the default truststore location(s), and may provide a way to change those contents. For example on RedHat-family see update-ca-trust and on Debian-family see update-ca-certificates.
Alternative: for Tomcat 9 (and 8.5) you don't need a keystore. Older versions of Tomcat required you to match the SSL/TLS implementation to the configuration: Java (JSSE) required a Java keystore while 'tcnative' (aka APR = Apache Portable Runtime) required OpenSSL-style PEM files. Modern Tomcat allows you to use either type of configuration with any SSL/TLS implementation, so you can simply use mykey.key mycert.crt intermediate.crt in the <Connector> or better the now-preferred <SSLHostConfig> and <Certificate> sub-elements; see http://tomcat.apache.org/tomcat-9.0-doc/config/http.html#SSL_Support . If you are going by http://tomcat.apache.org/tomcat-9.0-doc/ssl-howto.html be warned that hasn't been kept up to date and a number of details in it are wrong, although the basic ideas are mostly still valid.

How to generate intermediate and root cert from an existing leaf certificate?

Now i have a X509 leaf certificate. From the certification path to see, there's a intermediate cert and a root cert in it.
I want to generate the intermediate cert(..CA- G3) and the root cert(VerSign). Currently, my way is to double click the intermediate one and then click "Copy to file.." to export it. Do same for the root one too. Is this way to correct to generate intermediate/root certs?
From my test result, it seems the generated root cert with wrong fingerprint. The fingerpring doesn't match the one on server side.
Anyone can help on how to generate intermediate/root certs correctly?
You have fundamental misunderstanding of certificates and certificate chains.
CA and Root certificates are searched for and found, not generated.
Some certificates include location of their CA certificate in the body of the certificate (in special certificate extension). For others you need to look in your CA certificates storage (this is what Windows does). Sometimes chains are sent together with end-entity certificate (depending on data format). Finally, sometimes CA and Root are just not available.
[supply the answer... , maybe this is an alternative approach to get all certs that the SSL server using]
To retrieve the ntermediate and root certs by OpenSSL command:
openssl s_client -showcerts -connect [host]:[port]