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 -kis likecatch (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
- if TLS is configured properly except for having a self-signed certificate the command will succeed and
- 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.