Configuring client-server certificates

Create a certificate

We need a certificate signed by a CA, the server will provide it on any request. We on the client side will “trust” with the CA certificate.

CA

  • Generate private key
openssl genrsa -out ca.key 4096
  • create ca.cnf file:
[ req ]
default_bits       = 4096
prompt             = no
default_md         = sha256
distinguished_name = dn
x509_extensions    = v3_ca

[ dn ]
C  = ES
ST = Galicia
L  = Vilalba
O  = mandrewcito Corp
OU = Development
CN = localhost

[ v3_ca ]
basicConstraints = critical, CA:TRUE
keyUsage = critical, digitalSignature, cRLSign, keyCertSign
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer

  • Generate root certificate
openssl req \
  -new \
  -x509 \
  -days 3650 \
  -key ca.key \
  -out ca.crt \
  -config ca.cnf

  • verify certificate
openssl x509 -in ca.crt -noout -text

Create server certificate

  • Generate private key
openssl genrsa -out localhost.key 2048
  • CSR with SAN, create localhost.cnf file: ```ini [ req ] default_bits = 2048 prompt = no default_md = sha256 distinguished_name = dn req_extensions = req_ext

[ dn ] C = ES ST = Galicia L = Local O = Desarrollo OU = Dev CN = localhost

[ req_ext ] subjectAltName = @alt_names

[ alt_names ] DNS.1 = localhost IP.1 = 127.0.0.1 IP.2 = ::1

* Generate CSR:
```sh
openssl req \
  -new \
  -key localhost.key \
  -out localhost.csr \
  -config localhost.cnf
  • Server certificate extensions server.ext ```ìni basicConstraints = CA:FALSE keyUsage = critical, digitalSignature, keyEncipherment extendedKeyUsage = serverAuth subjectAltName = @alt_names

[ alt_names ] DNS.1 = localhost IP.1 = 127.0.0.1 IP.2 = ::1


* Sign server with CA:
```sh
openssl x509 \
  -req \
  -in localhost.csr \
  -CA ca.crt \
  -CAkey ca.key \
  -CAcreateserial \
  -out localhost.crt \
  -days 825 \
  -sha256 \
  -extfile server.ext
  • verify trust chain:
openssl verify -CAfile ca.crt localhost.crt

Krestel certificate (netcore server)

openssl pkcs12 -export \
  -out localhost.pfx \
  -inkey localhost.key \
  -in localhost.crt \
  -name kestrel-cert

password: signalrcore

Configuring server side

Copy certificate (.pfx) on code folder and include it into the solution, add to your krestel the following env variables:

# ... #
ENV ASPNETCORE_Kestrel__Certificates__Default__Password=signalrcore
ENV ASPNETCORE_Kestrel__Certificates__Default__Path=localhost.pfx
# ... #

sample server code here

Client side

Install CA certificate (depends on OS example is debian/ubuntu)

this step is optional

sudo cp ca.crt /usr/local/share/ca-certificates/my-ca-local.crt
sudo update-ca-certificates

Check certificate:

trust list | grep "Mi CA Local"

check with requests

import requests
>>> requests.get("http://localhost:5000")
<Response [200]>
>>> requests.get("https://localhost:5001", verify="ca.crt")
<Response [200]>
>>> requests.get("https://localhost:5001")
raise SSLError(e, request=request)
requests.exceptions.SSLError: HTTPSConnectionPool(host='localhost', port=5001): Max retries exceeded with url: / (Caused by SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1000)')))

now you can take a look to certificates_test.py, here you can see how configure properly ssl_context.

Have fun :)