How to pass custom certificate in openssl command line - ssl

I'm new to "openssl", I had been working with libcurl before. Since we are facing an issue with the connectivity I was asked to check how the ssl connection is happening if we try from the command line.
I'm able to get information about connecting to a server.
Since the connection is a secure one it needs some custom certificate to be added when I try to create the connection.
Can someone tell me how to pass a custom certificate (where I can store them for openssl to use?) during the connection?
Thanks for reading!

Are you talking about a custom CA cert or a client cert?
You provide ca cert to s_client's -CApath or -CAfile options, or if you're talking about a client cert you want -cert (and friends).
See s_client's man page.

Related

openssl s_client -showcerts not showing all the certs

The server certificate on load balancer (with public IP/CNAME) is expiring on 5/31. I ordered a new certificate and uploaded to the load balancer. I kept the old certificate, and didn't delete/remove it from the load balancer
When I run the showcerts command to list all the certificate, I don't see the latest one. Only existing cert that is due on 5/31 is shown.
openssl s_client -showcerts -connect domainname:443
I checked the browser , there also it is same.
How do I verify that certificate are added properly and new certs will be picked up once the existing one expires?
thanks in advance
How do I verify that certificate are added properly and new certs will be picked up once the existing one expires?
That's not how it works. The server will not magically use new certificates once the previous ones expire. It will only use the certificates explicitly configured.
Usually there is some overlap between old and new certificates, so that one can configure the server to use the new certificates as soon as they are valid (see X509 attribute NotBefore) even though the old ones are still valid too.

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.

Openssl Client Certificates [duplicate]

I am developing a client/server application with TLS. My idea is to use a certificate on the client so it is authenticated by the server. Also another certificate on the server so the client is also able to authenticate that it is connecting to the right server.
I want first to test and use openssl s_server and openssl s_client to validate the proposal.
Until now I have created a CA private key on the server, I have created a root certificate. With the root certificate I have signed two CSR, so I get one certificate for the server and one certificate for the client.
I also have installed the client certificate + root certificate on the client, and the server certificate + root certificate on the server.
I want now to try to establish a connection between openssl s_server and openssl s_client and verify that they get both authenticated mutually, but I cannot wrap my mind with the documentation on how to do it. Any help or any guide on that?
Once I have that set up, the next step is to test the own developed client against that server, and our own developed server against the s_client. Can we use that for testing?
Thanks
It looks like you are trying to set up a root of trust with (1) s_client and s_server for testing; and (2) programmatically within your code using OpenSSL.
To ensure openssl s_client (or openssl s_server) uses your root, use the following options:
-CAfile option to specify the root
-cert option for the certificate to use
-key option for the private key of the certificate
See the docs on s_client(1) and s_server(1) for details.
To do the same programmatically on the client, you would use:
SSL_CTX_load_verify_locations to load the trusted root
SSL_CTX_use_certificate to specify the client certificate
SSL_CTX_use_PrivateKey to load the private key for the client certificate
To do the same programmatically on the server, you would use:
SSL_CTX_load_verify_locations to load the trusted root
SSL_CTX_use_certificate_chain_file to specify the server certificate
SSL_CTX_use_PrivateKey to load the private key for the server certificate
SSL_CTX_set_client_CA_list to tell the client to send its client certificate
If you don't want to use the parameters for every connection (i.e. the common context), then set it for each SSL connection with, for example, SSL_use_certificate and SSL_use_PrivateKey.
A lot goes on with SSL_CTX_set_client_CA_list. It (1) loads the CA's to the server uses to verify a client, (2) it causes the server to send a list of CAs it accepts when verifing a client, and (3) it triggers the ClientCertificate message at the client if the client has a certificate that satisfies the server's accepted CAs list.
Also see the docs on SSL_CTX_load_verify_locations(3), SSL_CTX_use_certificate(3), SSL_CTX_set_client_CA_list and friends.
The easiest certificate and key format to use is PEM. PEM is the one that uses, for example, ----- BEGIN CERTIFICATE -----. For the server certificate, be sure the file is a concatenation of the server's certificate and any intermediates needed by the client to build the chain.
Having the server send all required certificates is standard practice for a problem known as the "which directory" problem. Its a well known problem in PKI, and its essentially the problem that clients don't know where to go to fetch missing intermediate certificates.
In general, you now know the functions that you need to use. Download a small server like nginx, and see how a production server uses them in practice. You could even use a SQL server like Postgres since it sets up a SSL/TLS server. Simply search the source files for SSL_CTX_load_verify_locations or SSL_load_verify_locations, and you will find the right place.
Though I don't recommend it, you could even look at s_client.c and s_server.c. They are located in <openssl dir>/apps. But the code can be difficult to read at times.
Generate two pairs of certificates/keys, one for the server and one for the client. Also create test.txt with any content.
To set up an SSL server that checks a client certificate, run the following command:
openssl s_server -cert server_cert.pem -key server_key.pem -WWW -port 12345 -CAfile client_cert.pem -verify_return_error -Verify 1
To test the server with client certificate, run the following command:
echo -e 'GET /test.txt HTTP/1.1\r\n\r\n' | openssl s_client -cert client_cert.pem -key client_key.pem -CAfile server_cert.pem -connect localhost:12345 -quiet
Alternatively you can use curl command:
curl -k --cert client_cert.pem --key client_key.pem https://localhost:12345/test.txt

Browser doesn't apply client certificate: 403.7

I'm trying to set up client certificate authentication. I was able to generate a CA-, server- and client-certificate. As long as I use Fiddler everything works as expected. However, as soon as I start using a browser it doesn't work anymore (HTTP Error 403.7 - Forbidden).
Of course I imported the client certificate in the Personal store and I made sure Client Certificate Negotiation is enabled.
I also tried openssl s_client -connect 127.0.0.1:443 -state -debug but I couldn't really make sense of the result... The only thing what's weird is that my CA doesn't show up in the Acceptable client certificate CA names section.
Anything else I could try?
Update:
I think it doesn't matter but my server certificate is set up for 127.0.0.1. Therefore I'm using https://127.0.0.1/... in my browsers.
Update2:
Using Wireshark I noticed that my servers' response depends on the client:
Fiddler (OK):
Client Hello
Server Hello, Certificate, Server Hello Done
Browser (Not OK):
Client Hello
Server Hello, Change Cipher Spec, Encrypted Handshake Message
Update3:
After enabling clientcertnegotiation the server response is different but still doesn't work:
Server Hello, Certificate
Certificate Request
Certificate, Client Key Exchange, Change Cipher Spec, Encrypted Handshake Message
My self-signed CA doesn't seem to be in the Distinguished Names list...
Update4:
SSL Settings: Checked Require SSL and Client certificates set as Required. Client cert shows up in Personal and the intended purpose is Client Authentication.
I finally found the issue and a workaround:
As mentioned in Update3, Distinguished Names doesn't contain my CA. This is because Distinguished Names has a limit of 2^14 bytes (16384 bytes). Because I do have a lot of CA installed on my machine my CA simply didn't make it in. The TLS standard would allow to send multiple messages but unfortunately Windows doesn't support this!
As mentioned here you have a few possibilities. The simplest one is this:
At your server add a DWORD (not QWORD!) value called SendTrustedIssuerList in your registry under HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL and set it to 0. This will prevent your server from sending a list at all, letting the client choose from any installed client certificate.
Unfortunately I couldn't see any traces in the Event Viewer (as reported elsewhere). Therefore the issue wasn't easy to spot (I had to use Wireshark in order to check Distinguished Names).
Use the Accept option instead of the Require option of the "Client certificates" feature.
In IIS Manager, locate the Web application for which you want to change the SSL setting.
In Features View, double-click SSL Settings.
On the SSL Settings page, select the Accept option under Client certificates.
In the Actions pane, click Apply.
More info here
Client certificate should be imported in CurrentUser\My store with private key (i.e. p12 or pfx file usually).
CA certificate should be in LocalMachine\Root store so that IIS trusts all certificates issued by the CA and the CA is trusted for every user on the computer.
CRL issued by the CA should be either available through URL (specified in every end entity certificate that CA issued) or imported in LocalMachine\My store.
NOTE: openssl doesn't use windows certificate store so this will have no efect on openssl s_client -connect 127.0.0.1:443 -state

Testing SSL/TLS Client Authentication with OpenSSL

I am developing a client/server application with TLS. My idea is to use a certificate on the client so it is authenticated by the server. Also another certificate on the server so the client is also able to authenticate that it is connecting to the right server.
I want first to test and use openssl s_server and openssl s_client to validate the proposal.
Until now I have created a CA private key on the server, I have created a root certificate. With the root certificate I have signed two CSR, so I get one certificate for the server and one certificate for the client.
I also have installed the client certificate + root certificate on the client, and the server certificate + root certificate on the server.
I want now to try to establish a connection between openssl s_server and openssl s_client and verify that they get both authenticated mutually, but I cannot wrap my mind with the documentation on how to do it. Any help or any guide on that?
Once I have that set up, the next step is to test the own developed client against that server, and our own developed server against the s_client. Can we use that for testing?
Thanks
It looks like you are trying to set up a root of trust with (1) s_client and s_server for testing; and (2) programmatically within your code using OpenSSL.
To ensure openssl s_client (or openssl s_server) uses your root, use the following options:
-CAfile option to specify the root
-cert option for the certificate to use
-key option for the private key of the certificate
See the docs on s_client(1) and s_server(1) for details.
To do the same programmatically on the client, you would use:
SSL_CTX_load_verify_locations to load the trusted root
SSL_CTX_use_certificate to specify the client certificate
SSL_CTX_use_PrivateKey to load the private key for the client certificate
To do the same programmatically on the server, you would use:
SSL_CTX_load_verify_locations to load the trusted root
SSL_CTX_use_certificate_chain_file to specify the server certificate
SSL_CTX_use_PrivateKey to load the private key for the server certificate
SSL_CTX_set_client_CA_list to tell the client to send its client certificate
If you don't want to use the parameters for every connection (i.e. the common context), then set it for each SSL connection with, for example, SSL_use_certificate and SSL_use_PrivateKey.
A lot goes on with SSL_CTX_set_client_CA_list. It (1) loads the CA's to the server uses to verify a client, (2) it causes the server to send a list of CAs it accepts when verifing a client, and (3) it triggers the ClientCertificate message at the client if the client has a certificate that satisfies the server's accepted CAs list.
Also see the docs on SSL_CTX_load_verify_locations(3), SSL_CTX_use_certificate(3), SSL_CTX_set_client_CA_list and friends.
The easiest certificate and key format to use is PEM. PEM is the one that uses, for example, ----- BEGIN CERTIFICATE -----. For the server certificate, be sure the file is a concatenation of the server's certificate and any intermediates needed by the client to build the chain.
Having the server send all required certificates is standard practice for a problem known as the "which directory" problem. Its a well known problem in PKI, and its essentially the problem that clients don't know where to go to fetch missing intermediate certificates.
In general, you now know the functions that you need to use. Download a small server like nginx, and see how a production server uses them in practice. You could even use a SQL server like Postgres since it sets up a SSL/TLS server. Simply search the source files for SSL_CTX_load_verify_locations or SSL_load_verify_locations, and you will find the right place.
Though I don't recommend it, you could even look at s_client.c and s_server.c. They are located in <openssl dir>/apps. But the code can be difficult to read at times.
Generate two pairs of certificates/keys, one for the server and one for the client. Also create test.txt with any content.
To set up an SSL server that checks a client certificate, run the following command:
openssl s_server -cert server_cert.pem -key server_key.pem -WWW -port 12345 -CAfile client_cert.pem -verify_return_error -Verify 1
To test the server with client certificate, run the following command:
echo -e 'GET /test.txt HTTP/1.1\r\n\r\n' | openssl s_client -cert client_cert.pem -key client_key.pem -CAfile server_cert.pem -connect localhost:12345 -quiet
Alternatively you can use curl command:
curl -k --cert client_cert.pem --key client_key.pem https://localhost:12345/test.txt