How to check certificate name and alias in keystore files?

You can run the following command to list the content of your keystore file (and alias name):

keytool -v -list -keystore .keystore

If you are looking for a specific alias, you can also specify it in the command:

keytool -list -keystore .keystore -alias foo

If the alias is not found, it will display an exception:

keytool error: java.lang.Exception: Alias does not exist

Extracting the CA Certificate using OpenSSL

  1. To create a CA certificate, execute the following command:

    openssl s_client -connect your.dsm.name.com:8443 –showcerts

    The command output appears on the screen. The second block of base-64 encoded text (between the “—–BEGIN CERTIFICATE—–“ and the “—–END CERTIFICATE —–“) is the certificate of interest.

  2. Copy the certificate text into the 1.2.3.4_CA.pem file.
  3. Copy the 1.2.3.4_CA.pem file to CommServe machine.

How to trust self-signed certificate in cURL command line?

Problem:

I’ve created a self-signed certificate for foo.localhost using a Let’s Encrypt recommendation using this Makefile:

include ../.env

configuration = csr.cnf
certificate = self-signed.crt
key = self-signed.key

.PHONY: all
all: $(certificate)

$(certificate): $(configuration)
    openssl req -x509 -out $@ -keyout $(key) -newkey rsa:2048 -nodes -sha256 -subj '/CN=$(HOSTNAME)' -extensions EXT -config $(configuration)

$(configuration):
    printf "[dn]\nCN=$(HOSTNAME)\n[req]\ndistinguished_name = dn\n[EXT]\nsubjectAltName=DNS:$(HOSTNAME)\nkeyUsage=digitalSignature\nextendedKeyUsage=serverAuth" > $@

.PHONY: clean
clean:
    $(RM) $(configuration)

I’ve then assigned that to a web server. I’ve verified that the server returns the relevant certificate:

$ openssl s_client -showcerts -connect foo.localhost:8443 < /dev/null
CONNECTED(00000003)
depth=0 CN = foo.localhost
verify error:num=20:unable to get local issuer certificate
verify return:1
depth=0 CN = foo.localhost
verify error:num=21:unable to verify the first certificate
verify return:1
---
Certificate chain
 0 s:/CN=foo.localhost
   i:/CN=foo.localhost
-----BEGIN CERTIFICATE-----
[…]
-----END CERTIFICATE-----
---
Server certificate
subject=/CN=foo.localhost
issuer=/CN=foo.localhost
---
No client certificate CA names sent
Peer signing digest: SHA512
Server Temp Key: X25519, 253 bits
---
SSL handshake has read 1330 bytes and written 269 bytes
Verification error: unable to verify the first certificate
---
New, TLSv1.2, Cipher is ECDHE-RSA-AES128-GCM-SHA256
Server public key is 2048 bit
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
SSL-Session:
    Protocol  : TLSv1.2
    Cipher    : ECDHE-RSA-AES128-GCM-SHA256
    Session-ID: […]
    Session-ID-ctx: 
    Master-Key: […]
    PSK identity: None
    PSK identity hint: None
    SRP username: None
    TLS session ticket:
    […]

    Start Time: 1529622990
    Timeout   : 7200 (sec)
    Verify return code: 21 (unable to verify the first certificate)
    Extended master secret: no
---
DONE

How do I make cURL trust it without modifying anything in /etc? --cacert does not work, presumably because there is no CA:

$ curl --cacert tls/foo.localhost.crt 'https://foo.localhost:8443/'
curl: (60) SSL certificate problem: unable to get local issuer certificate
More details here: https://curl.haxx.se/docs/sslcerts.html

curl failed to verify the legitimacy of the server and therefore could not
establish a secure connection to it. To learn more about this situation and
how to fix it, please visit the web page mentioned above.

The goal is to enable HTTPS during development:

  • I can’t have a completely production-like certificate without a lot of work to enable DNS verification in all development environments. Therefore I have to use a self-signed certificate.
  • I still obviously want to make my development environment as similar as possible to production, so I can’t simply ignore any and all certificate issues. curl -k is like catch (Exception e) {}in this case – nothing at all like a browser talking to a web server.

In other words, when running curl [something] https://project.local/api/foo I want to be confident that

  1. if TLS is configured properly except for having a self-signed certificate the command will succeed and
  2. if I have any issues with my TLS configuration except for having a self-signed certificate the command will fail.

Using HTTP or --insecure fails the second criterion.

Solution:

Following these steps should solve your issue:

  1. Download and save the self-signed certificate: echo quit | openssl s_client -showcerts -servername "${API_HOST}" -connect "${API_HOST}":443 > cacert.pem
  2. Tell the curl client about it: curl --cacert cacert.pem --location --silent https://${API_HOST}

Also one could use wget and ignore certificates with: wget --no-check-certificate https://${API_HOST}

unable to write ‘random state’

This command attempts to create a file at $HOME/.rnd and you see the error because the file cannot be created.

You must tell openssl which file to use for writing random state and you do so by exporting the $RANDFILE environment variable. On Openshift you can write in $HOME_DIR directory so create the command as follows:

export RANDFILE=$HOME_DIR/.rnd
openssl genrsa -des3 -out $OPENSHIFT_DATA_DIR/myApp.key 2048

SSL Client Certificate Authentication with Apache

Creating CA Certificate

We use this certificate for only signing certificates that we use for the clients and our web servers. It should be kept very secure. If it is disclosed other certificates signed with this certificate will be disclosed as well.

openssl genrsa -des3 -out ca.key 4096
openssl req -new -x509 -days 365 -key ca.key -out ca.crt

Creating a Key and CSR for the Client

Creating a client certificate is the same as creating Server certificate.

openssl req -newkey rsa:2048 -nodes -keyout client.key -out client.csr

Signing the client certificate with previously created CA.

Not: Do not forget to change serial each time you sign new certificate, otherwise may get serial conflict error in the web browsers.

[root@centos7 certs]# openssl x509 -req -days 365 -in client.csr -CA ca.crt -CAkey ca.key -set_serial 01 -out client.crt
Signature ok
subject=/C=TR/L=Default City/O=Client Certificate/CN=Client Certificate
Getting CA Private Key
Enter pass phrase for ca.key:

 

Creating a Key and CSR for the Server(Apache Virtual Host ankara.example.com)

openssl req -newkey rsa:2048 -nodes -keyout ankara.key -out ankara.csr

Signing Server Certificate with previously created CA.

Do not forget to change serial number. As it may conflict with existing one.

openssl x509 -req -days 365 -in ankara.csr -CA ca.crt -CAkey ca.key -set_serial 02 -out ankara.crt

Apache Configuration for the Authentication with Client Certificate

This sample configuration shows how to force server to request client certificate.

<Directory /srv/ankara/www>
	Require all granted
</Directory>

<VirtualHost *:443>
	SSLEngine On
	SSLCertificateFile /etc/httpd/conf.d/certs/ankara.crt
	SSLCertificateKeyFile /etc/httpd/conf.d/certs/ankara.key
	ServerName ankara.example.com
	DocumentRoot /srv/ankara/www 
	SSLVerifyClient require
	SSLVerifyDepth 5
	SSLCACertificateFile "/etc/httpd/conf.d/certs/ca.crt"
</VirtualHost>

The depth actually is the maximum number of intermediate certificate issuers, i.e. the number of CA certificates which are max allowed to be followed while verifying the client certificate. A depth of 0 means that self-signed client certificates are accepted only, the default depth of 1 means the client certificate can be self-signed or has to be signed by a CA which is directly known to the server (i.e. the CA’s certificate is under SSLCACertificatePath), etc.

Reference: https://httpd.apache.org/docs/2.4/mod/mod_ssl.html

Experimenting with Curl

Without specifying the client certificate

gokay@ankara:~/certs$ curl https://ankara.example.com -v
* Rebuilt URL to: https://ankara.example.com/
* Trying 192.168.122.30...
* Connected to ankara.example.com (192.168.122.30) port 443 (#0)
* found 148 certificates in /etc/ssl/certs/ca-certificates.crt
* found 597 certificates in /etc/ssl/certs
* ALPN, offering http/1.1
* gnutls_handshake() failed: Handshake failed
* Closing connection 0
curl: (35) gnutls_handshake() failed: Handshake failed

With client certificate

gokay@ankara:~/certs$ curl https://ankara.example.com --key client.key --cert client.crt --cacert ca.crt -v
* Rebuilt URL to: https://ankara.example.com/
* Trying 192.168.122.30...
* Connected to ankara.example.com (192.168.122.30) port 443 (#0)
* found 1 certificates in ca.crt
* found 597 certificates in /etc/ssl/certs
* ALPN, offering http/1.1
* SSL connection using TLS1.2 / ECDHE_RSA_AES_128_GCM_SHA256
* server certificate verification OK
* server certificate status verification SKIPPED
* common name: ankara.example.com (matched)
* server certificate expiration date OK
* server certificate activation date OK
* certificate public key: RSA
* certificate version: #1
* subject: C=TR,L=Default City,O=Ankara LTD,CN=ankara.example.com
* start date: Sun, 24 Dec 2017 10:00:20 GMT
* expire date: Mon, 24 Dec 2018 10:00:20 GMT
* issuer: C=TR,L=Default City,O=BlueTech CA,OU=CA,CN=BlueTech CA
* compression: NULL
* ALPN, server did not agree to a protocol
> GET / HTTP/1.1
> Host: ankara.example.com
> User-Agent: curl/7.47.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Date: Sun, 24 Dec 2017 10:21:15 GMT
< Server: Apache/2.4.6 (CentOS) OpenSSL/1.0.2k-fips
< Last-Modified: Sun, 24 Dec 2017 10:19:51 GMT
< ETag: "3b-5611363e4a8e0"
< Accept-Ranges: bytes
< Content-Length: 59
< Content-Type: text/html; charset=UTF-8
<
<h1>My Secure Page Ankara</h1>
<h2>ankara.example.com</h2>
* Connection #0 to host ankara.example.com left intact

 

urllib and “SSL: CERTIFICATE_VERIFY_FAILED” Error

in Python 3.6.1 on MacOs Sierra

Entering this in the bash terminal solved the problem:

pip install certifi
/Applications/Python\ 3.6/Install\ Certificates.command

ansible: Failed to validate the SSL certificate

If you get the following error:

“msg”: “Failed to validate the SSL certificate for rpm.nodesource.com:443. Make sure your managed systems have a valid CA certificate installed. If the website serving the url uses SNI you need python >= 2.7.9 on your managed machine (the python executable used (/usr/bin/python) is version: 2.6.6 (r266:84292, Aug 18 2016, 15:13:37) [GCC 4.4.7 20120313 (Red Hat 4.4.7-17)]) or you can install the `urllib3`, `pyOpenSSL`, `ndg-httpsclient`, and `pyasn1` python modules to perform SNI verification in python >= 2.6. You can use validate_certs=False if you do not need to confirm the servers identity but this is unsafe and not recommended. Paths checked for this platform: /etc/ssl/certs, /etc/pki/ca-trust/extracted/pem, /etc/pki/tls/certs, /usr/share/ca-certificates/cacert.org, /etc/ansible. The exception msg was: [Errno 1] _ssl.c:492: error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure.”

It is because the managed node does not have python >= 2.7.10 you can resolve it by executing:

sudo yum install pyOpenSSL -y
sudo pip install urllib3 ndg-httpsclient pyasn1