OpenSSL CA Configuration
Before creating my self signed certificate, I create a folder to store everything and configuration file
Create a folder with:
mkdir ggallCA
cd ggallCA
Then create an openssl.cnf
file to configure OpenSSL.
####################################
[ ca ]
default_ca = CA_default # Go to default CA section
[ CA_default ]
dir = /mnt/d/ggallCA # Where everything is kept
certificate = $dir/CA/cacert.pem # The CA certificate
database = $dir/CA/index.txt # The database
new_certs_dir = $dir/CA/certs # default place for new certs.
private_key = $dir/CA/privkey.pem # The CA private key
serial = $dir/CA/serial.txt # The current serial number for certificates
policy = policy_default
x509_extensions = certificate_extensions
# defaults for CA
default_days = 90 # how long to certify for
default_crl_days= 30 # how long before next CRL
default_md = sha512 # use public key default MD
preserve = no # keep passed DN ordering
[ policy_default]
countryName = optional
stateOrProvinceName = optional
organizationName = optional
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[ certificate_extensions ]
basicConstraints = CA:false
####################################
[ req ]
default_bits = 2048
default_keyfile = privkey.pem
distinguished_name = req_dn
x509_extensions = v3_ext
attributes = req_attributes
# extensions to add to certificate request
[ req_dn ]
countryName = Country Name (2 letter code)
countryName_default = US
countryName_min = 2
countryName_max = 2
stateOrProvinceName = State or Province Name (full name)
stateOrProvinceName_default = Iowa
localityName = Locality Name (eg, city)
localityName_default = Iowa CIty
0.organizationName = Organization Name (eg, company)
0.organizationName_default = Greg Gallardo
organizationalUnitName = Organizational Unit Name (eg, section)
commonName = Common Name (e.g. server FQDN or YOUR name)
commonName_max = 64
emailAddress = greg@greggallardo.com
emailAddress_max = 64
# request attributes
[ req_attributes ]
challengePassword = A challenge password
challengePassword_min = 4
challengePassword_max = 20
[ v3_ext ]
basicConstraints = critical,CA:true
keyUsage = critical,digitalSignature, cRLSign, keyCertSign
[ v3_client ]
basicConstraints = CA:false
keyUsage = digitalSignature, keyEncipherment extendedKeyUsage = clientAuth
CA Certs
Now that a base directory and configuration file exist, the next thing we need is the CA certificates for signing our client and server certificates.
Create a new folder to store the CA certificate files.
mkdir CA
cd CA
Next we create the folders files specified in openssl.cnf
touch index.txt
echo "01" > serial.txt
mkdir certs private
Run the following command to create the CA certificate and private key
openssl req -x509 -config ../openssl.cnf -newkey rsa:2048 -days 365 -out cacert.pem -outform PEM -subj /CN=GGAwsCA/ -nodes
-days
means this one lasts a year
Certificate Creation
One your CA files exist you can use them to self-sign certificates. ## Server Certificate Creation Make a folder for your server certificates
cd /mnt/d/ggallCA
mkdir server
cd server
Next use openssl to make a signing request:
openssl genrsa -out serverkey.pem 2048
openssl req -new -key serverkey.pem -out req.pem -outform PEM -subj /CN=test.myfakeserver.local/ -nodes -config ../openssl.cnf
Then sign the request with your CA files.
cd ../CA
openssl ca -config ../openssl.cnf -in ../server/req.pem -out ../server/servercert.pem -notext
If all went well openssl will ask you if you want to sign the cert (just say yes) and commit (also say yes)
Using configuration from ../openssl.cnf
Check that the request matches the signature
Signature ok
The Subject's Distinguished Name is as follows
commonName :ASN.1 12:'testserver'
Certificate is to be certified until May 13 21:51:26 2023 GMT (365 days)
Sign the certificate? [y/n]:y
1 out of 1 certificate requests certified, commit? [y/n]y
Write out database with 1 new entries
Data Base Updated
This will create new server certificate files. One in the CA/certs folder and one named serversert.pem in the server folder.
PKCS12
The server certificates are PEM files. You might need other formats. I often work with Microsoft Windows, so I sometimes need to convert PEM files to PKCS12 files. This can be done with OpenSSL.
openssl pkcs12 -export -out servercert.p12 -in servercert.pem -inkey serverkey.pem -passout pass:somepassword
Validity Period
When signing a request, you can use the -days
flag to set the validity period of the request you’re signing.
openssl genrsa -out serverkey_2.pem 2048
openssl req -new -key serverkey_2.pem -out serverreq_2.pem -outform PEM -subj /CN=test.myfakeserver.local/ -nodes -config ../openssl.cnf
Then sign the request with your CA files.
cd ../CA
openssl ca -config ../openssl.cnf -in ../server/serverreq_2.pem -out ../server/servercert_2.pem -notext -days 10
Client Certificate Creation
Make a folder for your client certificates
cd /mnt/d/ggallCA
mkdir client
cd client
Make client certificate signing requests with OpenSSL:
openssl genrsa -out clientkey.pem 2048
openssl req -new -key clientkey.pem -out req.pem -outform PEM -subj /CN=www.greggallardo.com/O=client/OU=test -nodes -config ../openssl.cnf
Then sign the client request with your CA files.
cd ../CA
openssl ca -config ../openssl.cnf -in ../client/req.pem -out ../client/clientcert.pem -notext -batch -extensions v3_client
You will get copies of the certificate files in the CA/certs folder and clients folder
Password Protection
Adding -des3
to the command will add a password to the key.
openssl genrsa -des3 -out clientkey_pw.pem 2048
openssl req -new -key clientkey_pw.pem -out clientreq_pw.pem -outform PEM -subj /CN=www.greggallardo.com/O=client/OU=testpw -config ../openssl.cnf
Then sign the client request with your CA files.
cd ../CA
openssl ca -config ../openssl.cnf -in ../client/clientreq_pw.pem -out ../client/clientcert_pw.pem -notext -batch -extensions v3_client
PKCS12 Format
If you want PKCS12 files, you can convert your PEM files with:
openssl pkcs12 -export -out clientcert.p12 -in clientcert.pem -inkey clientkey.pem -passout pass:clientpassword
Certificate Testing
You can look at the contents of your certificates with openssl x509
openssl x509 -in <PEM FILE> -text
For example, dumping the client lets me verify the dates and Subject fields I specified.
openssl x509 -in ./client/clientcert.pem -text | head
$ Certificate:
Data:
Version: 3 (0x2)
Serial Number: 2 (0x2)
Signature Algorithm: sha512WithRSAEncryption
Issuer: CN = GGAwsCA
Validity
Not Before: Mar 13 15:15:06 2023 GMT
Not After : Jun 11 15:15:06 2023 GMT
Subject: O = client, OU = test, CN = www.greggallardo.com
Testing Server Certificates
The following python script can be used to test out the server certificate
from http.server import HTTPServer, SimpleHTTPRequestHandler
import ssl
class SecureHTTPRequestHandler(SimpleHTTPRequestHandler):
def do_GET(self):
self.send_response(200)
self.send_header('Content-type', 'text/html')
self.end_headers()
self.wfile.write(b'Hello, secure world!')
= ('172.19.120.67', 8443) # Replace with your own IP and Port values
server_address = HTTPServer(server_address, SecureHTTPRequestHandler)
httpd
# Set up the SSL context:
= ssl.wrap_socket(
httpd.socket
httpd.socket,=True,
server_side='/path/to/servercert.pem', # Replace this with the path to your server certificate
certfile='/path/to/serverkey.pem', # Replace this with the path to your private key
keyfile=ssl.PROTOCOL_TLS,
ssl_version="/path/to/cacert.pem", # Replace this with the path to your CA certificate
ca_certs# cert_reqs=ssl.CERT_REQUIRED # Enable this to test client certificates
)
print('Serving HTTPS on port', server_address[1])
httpd.serve_forever()
You can use --resolve
with curl
to test against the server.
curl --cacert ./cacert.pem --resolve test.myfakeserver.local:8443:172.1ps://test.myfakeserver.local:8443
adding -v
to the command will give you more information
> curl --cacert ./cacert.pem --resolve test.myfakeserver.local:8443:172.19.120.67 https://test.myfakeserver.local:8443 -v
* Added test.myfakeserver.local:8443:172.19.120.67 to DNS cache
* Hostname test.myfakeserver.local was found in DNS cache
* Trying 172.19.120.67:8443...
* Connected to test.myfakeserver.local (172.19.120.67) port 8443 (#0)
* ALPN: offers h2,http/1.1
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* CAfile: ./cacert.pem
* CApath: none
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384
* ALPN: server did not agree on a protocol. Uses default.
* Server certificate:
* subject: CN=test.myfakeserver.local
* start date: Mar 13 14:49:51 2023 GMT
* expire date: Jun 11 14:49:51 2023 GMT
* common name: test.myfakeserver.local (matched)
* issuer: CN=GGAwsCA
* SSL certificate verify ok.
* using HTTP/1.x
> GET / HTTP/1.1
> Host: test.myfakeserver.local:8443
> User-Agent: curl/8.0.1
> Accept: */*
>
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* old SSL session ID is stale, removing
* HTTP 1.0, assume close after body
< HTTP/1.0 200 OK
< Server: SimpleHTTP/0.6 Python/3.10.12
< Date: Thu, 16 Mar 2023 15:46:45 GMT
< Content-type: text/html
<
* Closing connection 0
* TLSv1.3 (OUT), TLS alert, close notify (256):
Hello world!
If the common name for the certificate were wrong, you’d get a warning like this:
curl --cert ./client/clientcert.pem --key ./client/clientkey.pem --cacert ./CA/cacert.pem --resolve test.myfake.local:8443:172.19.120.67 https://test.myfake.local:8443
curl: (60) SSL: certificate subject name 'test.myfakeserver.local' does not match target host name 'test.myfake.local'
More details here: https://curl.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.
Testing Client Certificates
To test if the client certificate is valid, enable the ssl.CERT_REQUIRED
option in the python server script
with your CA files.
Then sign the client request
```bash/CA
cd ..-config ../openssl.cnf -in ../client/req.pem -out ../client/clientcert.pem -notext -batch -extensions v3_client openssl ca
cert_reqs=ssl.CERT_REQUIRED # Enable this to test client certificates
You can specify the client key and certificate with the `--key` and `--cert` options.
```bash
curl --cert ./client/clientcert.pem --key ./client/clientkey.pem --cacert ./CA/cacert.pem --resolve test.myfakeserver.local:8443:172.19.120.67 https://test.myfakeserver.local:8443
Hello world!