Graduate Program KB

SSL/TLS

Introduction

In this talk I will discuss some of the history of securing information on the internet. We'll look at systems used before the web and then at SSL/TLS used to wrap http (among other protocols). We'll sign and encrypt messages, as well as creating our own certificate authority and wrapping a web server with TLS.

CIA triad

There are three main properties that a secure communication should have

  • Confidentiality
    • Messages have not been red by an eavesdropper
  • Integrity
    • Messages have not been tampered with
  • Availability
    • Messages can be accessed by authorized parties

Hashing

A cryptographic hash function applied to a message H(m) should have the following properties

  • Deterministic
    • The same input should always result in the same output
  • Preimage resistance
    • One way
    • There is no better method for recovering the message other than brute force
  • Second preimage resistance (weak collision resistance)
    • Given a particular message it is difficult to find another message with the same hash
  • Collision resistance
    • It's difficult to find any two messages with the same hash

Example of a sha1 hash

lachlan@lachlan-thinkpad:~ > echo "some message" | sha1sum
4e176cf0b84557da9d31539b5c5d13ae792b9160  -

Symmetric encryption

In symmetric encryption both parties have a shared key used to encrypt the message. For Alice to send a Message to Bob they need to agree on a key beforehand to use to encrypt the message.

Examples

  • DES
  • AES
  • RC4
  • ChaCha20

Symmetric message authentication

We can combine a symmetric encryption algorithm with a hash function to determine if a message has been tampered with. This leads to an algorithm called hash-based message authentication (HMAC), written

HMAC(k,m)

It acts like a hash which also takes a key. When you receive the message you are also given the sender's HMAC of the message with the key. You then recompute the HMAC, if it matches what your were given, then the message was not tampered with.

Asymmetric encryption

Asymmetric encryption is also called public key cryptography. Both parties have a public key and a private key. Messages encrypted with the public key can only be decrypted with the private key associated with it. If Alice wants to send a message to Bob, they can both generate public/private key pairs. Alice can then encrypt the message with Bob's public key, now only Bob's private key can decrypt it.

Examples

  • DSA
  • RSA
  • DH
  • ECDH

Example - RSA

For the function

R(m, k, n) = m^k mod n

It is difficult to find the value for m given the output, k and n, when n is the product of large primes. i.e. n = p*q where p, q are large primes However, knowing the primes it is easy to find two numbers e, and d such that

R(R(m, e, n), d, n) = m

The RSA encryption algorithm relies on the fact that it is hard to factorise n back into p and q. If it were, it would be easy to calculate d from e. This is called a one-way trapdoor function, since it acts as a one-way function unless you have access to the trapdoor to go back in the other direction. Typically, everyone uses a common value of e (smaller values are faster) and then derive d using p and q (which are kept secret).

For encryption and decryption we can define the public key as the pair pk = (e, n), and the private (secret) key as the pair sk = (d, n) and write

E(m, sk) = R(m, pk.e, pk.n) D(m, pk) = R(m, sk.d, sk.n)

This is commonly referred to as "textbook" RSA encryption, because many explanation stop here (like I will). However, in practice, there are many issues with this implementation For example

  • This implementation can't encrypt messages longer than n
    • We can address this by e.g. extending it into a block cipher
    • Or we could use a faster symmetric algorithm instead
  • Encrypting the same plaintext twice results in the same ciphertext
    • Knowing the same message was sent twice is information the attacker shouldn't have
  • There is a more efficient algorithm for attacking the encryption of short messages
  • Some choices of primes create numbers which are easier to factor
  • For more attacks see Twenty Years of Attacks on the RSA Cryptosystem

Session key

Asymmetric encryption is around 100 to 1000x slower than symmetric encryption. For this reason it is typically used to share a randomly generated session key between the two recipients. After a common secret (session key) has been established a symmetric encryption algorithm like AES can be used. A session key also allows the message to be encrypted once for multiple recipients, only the small session key needs to be sent to each recipient.

Signing

Alice and Bob can now send messages to each other without deciding on a key in advance. However, what if Alice wants to make a public post that people can verify was written by her.

E(m, pk) = R(m, pk.e, pk.n) D(m, sk) = R(m, sk.d, sk.n)

Notice the symmetry in encryption and decryption. What if Alice encrypted the post with her private key, and visitors decrypted it with her public key. If the decryption is successful it could have only be encrypted by Alice's private key, which only she has.

We can define functions for signing and verifying

S(m, sk) = R(m, sk.e, sk.n) V(m, pk) = R(m, pk.e, pk.n) == m

Notice that the definitions look like D, and E. In practice these are actually different. Encryption and decryption need additional mechanisms to wrap the message to address some of the issues I outlined in the previous section. What I will address here is that RSA can't handle large messages and is slow. We can address this by hashing our post

S(m, sk) = R(H(m), sk.e, sk.n) V(m, pk) = R(H(m), pk.e, pk.n) == H(m)

If we use a good cryptographic hash then the hash value can be considered unique for that message. An attacker trying to use the signature for another message would have to create a message with the same hash, which violates the properties of the hashing algorithm.

GPG

People seem to forget how new the web is, being predated by older protocols such as irc, email, and ftp. Before the web people were concerned about the privacy and authenticity of email and files which were being sent all around the internet between clients and servers in plain text. The Pretty Good Privacy (PGP) program was released in 1991 (the same year the web was made public) to provide tools for encrypting and signing files. The initial standard released was RFC 1991, while the current version is RFC 4880. GNU Privacy Guard (GPG) is an open source replacement program which follows the standard.

Let's create two docker containers for Alice and Bob, we'll also create a bind mount they can use to communicate

mkdir ~/talk
docker run -itv ~/talk:/talk --name alice --hostname alice ubuntu bash
docker run -itv ~/talk:/talk --name bob --hostname bob ubuntu bash

We also need to install gpg in both containers

root@alice:/# apt update && apt install gpg

We can create a new key using sensible defaults with

gpg --gen-key

However, we are going to look at the full generation dialogue

root@alice:/# gpg --full-generate-key
gpg (GnuPG) 2.2.27; Copyright (C) 2021 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Please select what kind of key you want:
   (1) RSA and RSA (default)
   (2) DSA and Elgamal
   (3) DSA (sign only)
   (4) RSA (sign only)
  (14) Existing key from card
Your selection? 1
RSA keys may be between 1024 and 4096 bits long.
What keysize do you want? (3072)
Requested keysize is 3072 bits
Please specify how long the key should be valid.
         0 = key does not expire
      <n>  = key expires in n days
      <n>w = key expires in n weeks
      <n>m = key expires in n months
      <n>y = key expires in n years
Key is valid for? (0)
Key does not expire at all
Is this correct? (y/N) y

You need a user ID to identify your key; the software constructs the user ID
from the Real Name, Comment and Email Address in this form:
    "Heinrich Heine (Der Dichter) <heinrichh@duesseldorf.de>"

Real name: Alice
E-mail address: alice@alice.com
Comment:
You selected this USER-ID:
    "Alice <alice@alice.com>"

Change (N)ame, (C)omment, (E)-mail or (O)kay/(Q)uit? O
We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilise the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.
We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilise the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.
gpg: key C1B7D9DE31A43E88 marked as ultimately trusted
gpg: revocation certificate stored as '/home/lachlan/.gnupg/openpgp-revocs.d/5BBE980AAC52FACB2BD97EC0C1B7D9DE31A43E88.rev'
public and secret key created and signed.

pub   rsa3072 2023-06-08 [SC]
      5BBE980AAC52FACB2BD97EC0C1B7D9DE31A43E88
uid                      Alice <alice@alice.com>
sub   rsa3072 2023-06-08 [E]

We have selected the use of the RSA algorithm for both signing and encrypting. We then chose a keysize of 3072 this specifies the range of values that n can be within. Larger values of n take more time to brute force p and q. We then specified that the key does mot expire. When validating a signature or decrypting a message the software will check if the date is after the key's expiry. If it is the key is considered invalid. The passphrase is used to encrypt the private key on disk

The software generated a private and public key pair. The keys are identified by fingerprints which is a hash of the public key.

The public key can be exported to our shared directory for Bob to access

root@alice:/# gpg --export 5BBE980AAC52FACB2BD97EC0C1B7D9DE31A43E88 > /talk/alice.pub

And imported by Bob

root@bob:/# gpg --import /talk/alice.pub
gpg: key C1B7D9DE31A43E88: public key "alice <alice@alice.com>" imported
gpg: Total number processed: 1
gpg:               imported: 1

We can look at the structure of this key using pgpdump

lachlan@lachlan-thinkpad:~/talk > pgpdump alice.pub
Old: Public Key Packet(tag 6)(397 bytes)
	Ver 4 - new
	Public key creation time - Thu Jun  8 11:12:49 AWST 2023
	Pub alg - RSA Encrypt or Sign(pub 1)
	RSA n(3072 bits) - ...
	RSA e(17 bits) - ...
Old: User ID Packet(tag 13)(23 bytes)
	User ID - Alice <alice@alice.com>
Old: Signature Packet(tag 2)(462 bytes)
	Ver 4 - new
	Sig type - Positive certification of a User ID and Public Key packet(0x13).
	Pub alg - RSA Encrypt or Sign(pub 1)
	Hash alg - SHA512(hash 10)
	Hashed Sub: issuer fingerprint(sub 33)(21 bytes)
	 v4 -	Fingerprint - 5b be 98 0a ac 52 fa cb 2b d9 7e c0 c1 b7 d9 de 31 a4 3e 88
	Hashed Sub: signature creation time(sub 2)(4 bytes)
		Time - Thu Jun  8 11:12:49 AWST 2023
	Hashed Sub: key flags(sub 27)(1 bytes)
		Flag - This key may be used to certify other keys
		Flag - This key may be used to sign data
	Hashed Sub: preferred symmetric algorithms(sub 11)(4 bytes)
		Sym alg - AES with 256-bit key(sym 9)
		Sym alg - AES with 192-bit key(sym 8)
		Sym alg - AES with 128-bit key(sym 7)
		Sym alg - Triple-DES(sym 2)
	Hashed Sub: preferred hash algorithms(sub 21)(5 bytes)
		Hash alg - SHA512(hash 10)
		Hash alg - SHA384(hash 9)
		Hash alg - SHA256(hash 8)
		Hash alg - SHA224(hash 11)
		Hash alg - SHA1(hash 2)
	Hashed Sub: preferred compression algorithms(sub 22)(3 bytes)
		Comp alg - ZLIB <RFC1950>(comp 2)
		Comp alg - BZip2(comp 3)
		Comp alg - ZIP <RFC1951>(comp 1)
	Hashed Sub: features(sub 30)(1 bytes)
		Flag - Modification detection (packets 18 and 19)
	Hashed Sub: key server preferences(sub 23)(1 bytes)
		Flag - No-modify
	Sub: issuer key ID(sub 16)(8 bytes)
		Key ID - 0xC1B7D9DE31A43E88
	Hash left 2 bytes - e0 1b
	RSA m^d mod n(3072 bits) - ...
		-> PKCS-1
Old: Public Subkey Packet(tag 14)(397 bytes)
	Ver 4 - new
	Public key creation time - Thu Jun  8 11:12:49 AWST 2023
	Pub alg - RSA Encrypt or Sign(pub 1)
	RSA n(3072 bits) - ...
	RSA e(17 bits) - ...
Old: Signature Packet(tag 2)(438 bytes)
	Ver 4 - new
	Sig type - Subkey Binding Signature(0x18).
	Pub alg - RSA Encrypt or Sign(pub 1)
	Hash alg - SHA512(hash 10)
	Hashed Sub: issuer fingerprint(sub 33)(21 bytes)
	 v4 -	Fingerprint - 5b be 98 0a ac 52 fa cb 2b d9 7e c0 c1 b7 d9 de 31 a4 3e 88
	Hashed Sub: signature creation time(sub 2)(4 bytes)
		Time - Thu Jun  8 11:12:49 AWST 2023
	Hashed Sub: key flags(sub 27)(1 bytes)
		Flag - This key may be used to encrypt communications
		Flag - This key may be used to encrypt storage
	Sub: issuer key ID(sub 16)(8 bytes)
		Key ID - 0xC1B7D9DE31A43E88
	Hash left 2 bytes - 4a 57
	RSA m^d mod n(3071 bits) - ...
		-> PKCS-1

GPG has actually created a key and a subkey. Our key file starts with a public key packet with the algorithm, n, and e for out signing key. That is followed by a user id packet containing the ID of the key's owner. The user id packet is followed by a signature packet The subkey is our encryption key. The reason we have a key with multiple subkeys is mostly due to how we share keys and verify identities, which will be discussed next.

There are different kinds of signature packets for signing different types of data. The one above is signing a key. The public key along with all the data prefixed by hashed is hashed and the resulting hash is signed using the parent key.

We can repeat this process to make a key for Bob. And export it for alice

root@bob:/# gpg --gen-key
root@bob:/# gpg --export CC1E67A3297125583BED0790C9CA616944858D47 > /talk/bob.pub

Alice can then impot the key

root@alice:/# gpg --import /talk/bob.pub
gpg: key C9CA616944858D47: public key "bob bobson <bob@bob.com>" imported
gpg: Total number processed: 1
gpg:               imported: 1

Let's make a message

root@alice:/# echo "Hi bob" > ~/message.txt

We can then encrypt this message for Bob

root@alice:/# gpg --output /talk/message.gpg --encrypt --recipient bob@bob.com ~/message.txt
gpg: checking the trustdb
gpg: marginals needed: 3  completes needed: 1  trust model: pgp
gpg: depth: 0  valid:   1  signed:   0  trust: 0-, 0q, 0n, 0m, 0f, 1u
gpg: next trustdb check due at 2025-06-10
gpg: 522F269EE0C495A8: There is no assurance this key belongs to the named user

sub  rsa3072/522F269EE0C495A8 2023-06-11 bob bobson <bob@bob.com>
 Primary key fingerprint: CC1E 67A3 2971 2558 3BED  0790 C9CA 6169 4485 8D47
      Subkey fingerprint: F5F1 7C49 B678 C285 2C53  C5A7 522F 269E E0C4 95A8

It is NOT certain that the key belongs to the person named
in the user ID.  If you *really* know what you are doing,
you may answer the next question with yes.

Use this key anyway? (y/N) y

We get a warning that the key is not trusted, we'll talk about trust in the next section.

We can also take a look at the format of the encrypted message with pgpdump

lachlan@lachlan-thinkpad:~/talk > pgpdump message.gpg
Old: Public-Key Encrypted Session Key Packet(tag 1)(396 bytes)
	New version(3)
	Key ID - 0x522F269EE0C495A8
	Pub alg - RSA Encrypt or Sign(pub 1)
	RSA m^e mod n(3066 bits) - ...
		-> m = sym alg(1 byte) + checksum(2 bytes) + PKCS-1 block type 02
New: Symmetrically Encrypted and MDC Packet(tag 18)(77 bytes)
	Ver 1
	Encrypted data [sym alg is specified in pub-key encrypted session key]
		(plain text + MDC SHA1(20 bytes))

First we have a packet for a session key encrypted with Bob's public key. This session key is used to encrypt the actual message in the second packet using a symmetric algorithm

Since Bob has his private key, he can decrypt the message.

root@bob:/# gpg --decrypt /talk/message.gpg
gpg: encrypted with 3072-bit RSA key, ID 522F269EE0C495A8, created 2023-06-11
      "bob bobson <bob@bob.com>"
Hi bob

We could also sign a message from alice. For example, a public blog post

root@alice:/# echo "Alice's post" > /talk/public.txt
root@alice:/# gpg --output /talk/public.sig --sign /talk/public.txt

Bob can verify the signature, since he has Alice's public key

root@bob:/# gpg --verify /talk/public.sig
gpg: Signature made Sun Jun 11 05:52:48 2023 UTC
gpg:                using RSA key 2417C358DE6834391A4DBC763A5B036C79D9345D
gpg: checking the trustdb
gpg: marginals needed: 3  completes needed: 1  trust model: pgp
gpg: depth: 0  valid:   1  signed:   0  trust: 0-, 0q, 0n, 0m, 0f, 1u
gpg: next trustdb check due at 2025-06-10
gpg: Good signature from "alice <alice@alice.com>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg:          There is no indication that the signature belongs to the owner.
Primary key fingerprint: 2417 C358 DE68 3439 1A4D  BC76 3A5B 036C 79D9 345D

We get a message saying the signature is good, but also a warning about trusting Alice's key.

We did not specify the original file, and it has not been compared. Instead, by default gpg encrypts the document into the signature, and it needs to be recovered by decrypting Since it was encrypted with Alice's private key, to be decrypted by the public. Bob can decrypt

root@bob:/# gpg --decrypt /talk/public.sig
Alice's post
gpg: Signature made Sun Jun 11 05:52:48 2023 UTC
gpg:                using RSA key 2417C358DE6834391A4DBC763A5B036C79D9345D
gpg: Good signature from "alice <alice@alice.com>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg:          There is no indication that the signature belongs to the owner.
Primary key fingerprint: 2417 C358 DE68 3439 1A4D  BC76 3A5B 036C 79D9 345D

Instead of modifying the message gpg allows you to make a detached signature

root@alice:/# gpg --output /talk/detached.sig --detach-sig /talk/public.txt

This time we need to specify the file to verify the signature for

root@bob:/# gpg --verify /talk/detached.sig /talk/public.txt
gpg: Signature made Sun Jun 11 05:55:21 2023 UTC
gpg:                using RSA key 2417C358DE6834391A4DBC763A5B036C79D9345D
gpg: Good signature from "alice <alice@alice.com>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg:          There is no indication that the signature belongs to the owner.
Primary key fingerprint: 2417 C358 DE68 3439 1A4D  BC76 3A5B 036C 79D9 345D

Key exchange

We have a problem, how do Alice and Bob trade public keys. An attacker, Mallory, could intercept the transmission of Bob's key and replace it with one she generated. It would then be possible to decrypt Alice's message, read it, and then re-encrypt it for Bob with no one noticing.

Web of Trust

The Web of Trust is a decentralised system for verifying the ownership of keys. While someone can send you a key, keys are typically located by searching a key server which is a repository of keys. Users can sign each other's keys to say that they have verified that person's identity. The signatures form a web. People would meet up at key signing parties to check people's IDs and provide them a signature if it matches the name on their key. Deciding what key to trust is similar to six degrees of separation, after searching for someone's key, you can check if there is a (or multiple) chain of signatures to that key starting from the keys you trust.

SSl/TLS

The secure sockets layer protocol was developed by netscape in 1995 to create https in order to encrypt communications between a web server and a browser. While the cryptography using similar building blocks it encrypts streams instead of files, sitting on a layer above http (or any protocol). In 1999 SSL was standardised by the IETF and renamed Transport Layer Security (TLS). The current version is TLS 1.3 defined in RFC 8446

TLS handshake

Before we can transmit encrypted data through TLS we need to set up the protocol with a handshake. We need to decide on what version of TLS we are using, what algorithms to use, as well as establish a shared key for the encryption.

TLS 1.3 shortened the handshake as well as removing older encryption algorithms (such as RSA). The TLS 1.3 handshake is as follows:

  1. The client sends a hello message containing
    1. TLS version
    2. Algorithms that will be used
    3. Random bytes, the client random
  2. The server uses the client random as well as its own randomness to generate the master secret
  3. The server sends a hello and finished message with
    1. The server random
    2. The server's certificate
    3. A signature of this message signed by the server's public key
  4. The client validates the server's certificate
  5. The client calculates the master secret
  6. The client sends a finished message

The master secret is used to derive the required session keys for the symmetric encryption. The algorithm used to generate the master secret is Diffie-Hellman key exchange. Note that the random numbers sent by the server and client are not directly the numbers they generated, but transformed versions.

Also note that this description is simplified, and doesn't include e.g. backwards compatibility.

Certificate validation

Similar to GPG we use certificates to determine whether the server's public key is real or an impersonation. However, with TLS we don't typically use WoT. Instead, the browser and OS come with preinstalled lists of trusted root Certificate Authorities which are responsible for issuing certificates. These authorities are the root in a chain of trust.

The client has to check a few things to validate the certificate

  • Check that the signature is valid
  • Check that the certificate hasn't expired
  • Check that the certificate hasn't been revoked
  • Check what domains the certificate is valid for
  • Check the key is valid for this usage (e.g. server, code signing, etc...)

Chain of trust

Of course, validating identity on the internet is an important task to get right. But,

Let's encrypt

You can request a free SSL certificate from Let's Encrypt. let's encrypt uses an automated tool called certbot for requesting certificates. In order to validate that you own the domain you are requesting the certificate for different kinds of challenges are provided. For example, to make a certificate for a web server let's encrypt can give you a specific file to serve under .well-known/acme-challenge/<TOKEN> and then check if that file is there. if you can serve that file it assumes you own the domain.

Creating a certificate authority with Easy RSA

We are now going to create our own public key infrastructure (PKI) using EasyRSA. EasyRSA was created by the OpenVPN developers to make it easier for users of OpenVPN to issue certificates to servers and clients in order to authenticate them to each other.

You can install easyrsa from apt, however the package won't add it to your path (ikr)

sudo apt install easy-rsa
export PATH=/usr/share/easy-rsa:$PATH

We'll make two directories, ca, and consumer

mkdir ca consumer

These represent different systems. consumer represents us, who would like to issue certificates for our different servers under our domain. ca represents the certificate authority (e.g. VeriSign) we will request our root certificate from.

We'll create the ca first

cd ca
lachlan@lachlan-thinkpad:~/talk/ca > easyrsa init-pki

init-pki complete; you may now create a CA or requests.
Your newly created PKI dir is: /home/lachlan/talk/ca/pki

lachlan@lachlan-thinkpad:~/talk/ca > easyrsa build-ca
Using SSL: openssl OpenSSL 3.0.2 15 Mar 2022 (Library: OpenSSL 3.0.2 15 Mar 2022)

Enter New CA Key Passphrase:
Re-Enter New CA Key Passphrase:
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Common Name (eg: your user, host, or server name) [Easy-RSA CA]:

CA creation complete and you may now import and sign cert requests.
Your new CA certificate file for publishing is at:
/home/lachlan/talk/ca/pki/ca.crt

We now have a pki directory with some content

lachlan@lachlan-thinkpad:~/talk/ca > ls pki
ca.crt  certs_by_serial  index.txt  index.txt.attr  issued  openssl-easyrsa.cnf  private  renewed  reqs  revoked  safessl-easyrsa.cnf  serial

We have a bunch of files. The main important ones are

  • ca.crt - our self-signed ca certificate
  • issued - directory for certificates we issue
  • openssl-easyrsa.cnf - configuration for how to generate certificates
  • private - our private keys
  • reqs - certificate requests (later)
  • revoked - revoked certificates

ca.crt is a self-signed certificate for our certificate authority. self-signed means that the certificate is signed by the public key it is supposed to validate, i.e. it just needs to be trusted, the trust does not come from anywhere. The records defined in a certificate is specified in the X.509 standard. The data is stores in a binary format called ASN.1. Because binary data can be difficult to transfer through some mediums (e.g. email), the PEM (privacy enhanced mail) format was created which encodes the ASN.1 in base64 and wraps the result in a header and footer.

ca.crt is an X.509 certificate in a PEM container, we can view it as follows

lachlan@lachlan-thinkpad:~/talk/ca > openssl x509 -in pki/ca.crt -text
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            3c:f3:c3:0d:c9:1a:02:78:49:0c:43:bb:42:68:56:ec:11:b2:07:29
        Signature Algorithm: sha256WithRSAEncryption
        Issuer: CN = Easy-RSA CA
        Validity
            Not Before: Jun  8 14:49:43 2023 GMT
            Not After : Jun  5 14:49:43 2033 GMT
        Subject: CN = Easy-RSA CA
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)
                Modulus:
                    00:99:d5:45:ee:fc:60:eb:e0:3c:ab:c4:57:8d:e0:
                    ef:a0:20:b5:f9:90:30:74:e9:55:68:d9:59:23:5b:
                    b9:84:2e:74:a4:f8:36:74:18:b8:f7:2c:1b:03:f5:
                    3f:8a:2c:9b:05:d0:33:36:38:c7:56:72:2e:e0:8c:
                    6e:47:90:c9:12:03:df:1a:f0:77:84:4b:b7:10:68:
                    09:ed:41:87:ce:c0:e5:67:95:62:c0:ab:a1:05:40:
                    57:45:2c:24:cc:e8:3f:65:c8:38:98:db:62:69:a4:
                    55:74:8c:a7:08:26:51:a6:d2:c6:08:d2:09:f4:69:
                    6d:27:01:34:6d:a1:72:06:02:17:a7:6f:5e:d6:65:
                    7b:25:bc:77:b3:ca:89:a0:47:2a:41:02:63:7d:1d:
                    b7:f3:b7:01:30:eb:c7:43:6f:3f:55:e2:be:08:87:
                    4b:20:5d:93:39:c6:ea:65:da:7d:d5:48:36:2b:a4:
                    3a:08:19:95:db:46:51:c9:6f:40:4f:99:60:1f:1c:
                    40:0c:9e:d9:ba:df:b4:0e:06:e2:c5:5d:07:3d:38:
                    d1:4f:b1:31:a4:5c:0b:b3:4c:f2:bf:33:e8:9c:af:
                    c4:50:a8:04:e1:75:20:3b:1b:d4:2c:dd:4d:ad:af:
                    3d:f7:18:05:0f:50:a7:f1:ca:65:e7:65:26:30:63:
                    13:15
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Subject Key Identifier:
                1C:73:87:C8:34:29:37:ED:45:98:78:9B:84:55:AC:EF:D7:DF:9B:BD
            X509v3 Authority Key Identifier:
                keyid:1C:73:87:C8:34:29:37:ED:45:98:78:9B:84:55:AC:EF:D7:DF:9B:BD
                DirName:/CN=Easy-RSA CA
                serial:3C:F3:C3:0D:C9:1A:02:78:49:0C:43:BB:42:68:56:EC:11:B2:07:29
            X509v3 Basic Constraints:
                CA:TRUE
            X509v3 Key Usage:
                Certificate Sign, CRL Sign
    Signature Algorithm: sha256WithRSAEncryption
    Signature Value:
        04:00:0e:bd:eb:db:e8:7b:f4:d6:bb:b9:c4:90:73:ad:0d:63:
        bb:01:e7:28:9e:4d:0d:76:13:29:ae:82:62:dd:54:b7:3c:5f:
        37:1d:af:df:d7:c7:49:fb:06:ff:39:78:49:1f:ea:03:81:4b:
        08:9a:93:db:6d:a3:ac:47:0e:84:cb:88:6f:70:1d:43:4e:98:
        93:2f:bc:4e:63:b9:1e:db:fa:65:a8:38:bb:5a:48:76:86:37:
        c3:9d:62:65:6b:8a:25:52:cc:49:c8:a5:e9:e1:38:2b:02:f8:
        2f:70:15:90:0a:4b:0e:42:fc:c8:c3:24:20:58:bc:e3:5a:c7:
        cd:1e:a7:70:42:cd:c4:1d:53:41:e1:6c:8a:4c:90:cb:40:ee:
        de:c7:42:4e:be:91:43:2f:c1:40:03:97:ae:52:28:c0:84:64:
        30:b3:96:cb:b5:f0:43:dd:10:08:9c:ed:92:2e:67:12:64:1c:
        14:1c:d8:0f:b3:13:ad:89:60:0a:91:f7:fd:d2:4c:ce:88:c3:
        57:d6:d1:77:9b:72:99:fc:bc:69:b3:fc:94:4c:2a:9e:18:3b:
        d8:35:cb:af:83:f1:cf:de:62:3d:f2:1c:76:c2:b4:64:fb:d7:
        f6:8a:db:a6:97:26:74:c3:db:e6:1e:ba:b2:66:d9:8a:f9:ba:
        f9:c4:da:74
-----BEGIN CERTIFICATE-----
MIIDSzCCAjOgAwIBAgIUPPPDDckaAnhJDEO7QmhW7BGyBykwDQYJKoZIhvcNAQEL
BQAwFjEUMBIGA1UEAwwLRWFzeS1SU0EgQ0EwHhcNMjMwNjA4MTQ0OTQzWhcNMzMw
NjA1MTQ0OTQzWjAWMRQwEgYDVQQDDAtFYXN5LVJTQSBDQTCCASIwDQYJKoZIhvcN
AQEBBQADggEPADCCAQoCggEBAJnVRe78YOvgPKvEV43g76AgtfmQMHTpVWjZWSNb
uYQudKT4NnQYuPcsGwP1P4osmwXQMzY4x1ZyLuCMbkeQyRID3xrwd4RLtxBoCe1B
h87A5WeVYsCroQVAV0UsJMzoP2XIOJjbYmmkVXSMpwgmUabSxgjSCfRpbScBNG2h
cgYCF6dvXtZleyW8d7PKiaBHKkECY30dt/O3ATDrx0NvP1XivgiHSyBdkznG6mXa
fdVINiukOggZldtGUclvQE+ZYB8cQAye2brftA4G4sVdBz040U+xMaRcC7NM8r8z
6JyvxFCoBOF1IDsb1CzdTa2vPfcYBQ9Qp/HKZedlJjBjExUCAwEAAaOBkDCBjTAd
BgNVHQ4EFgQUHHOHyDQpN+1FmHibhFWs79ffm70wUQYDVR0jBEowSIAUHHOHyDQp
N+1FmHibhFWs79ffm72hGqQYMBYxFDASBgNVBAMMC0Vhc3ktUlNBIENBghQ888MN
yRoCeEkMQ7tCaFbsEbIHKTAMBgNVHRMEBTADAQH/MAsGA1UdDwQEAwIBBjANBgkq
hkiG9w0BAQsFAAOCAQEABAAOvevb6Hv01ru5xJBzrQ1juwHnKJ5NDXYTKa6CYt1U
tzxfNx2v39fHSfsG/zl4SR/qA4FLCJqT222jrEcOhMuIb3AdQ06Yky+8TmO5Htv6
Zag4u1pIdoY3w51iZWuKJVLMScil6eE4KwL4L3AVkApLDkL8yMMkIFi841rHzR6n
cELNxB1TQeFsikyQy0Du3sdCTr6RQy/BQAOXrlIowIRkMLOWy7XwQ90QCJztki5n
EmQcFBzYD7MTrYlgCpH3/dJMzojDV9bRd5tymfy8abP8lEwqnhg72DXLr4Pxz95i
PfIcdsK0ZPvX9orbppcmdMPb5h66smbZivm6+cTadA==
-----END CERTIFICATE-----

You can see it contains:

  • version
  • serial number
  • issuer (ourselves)
  • the time range it is valid between
  • the public key
  • and a signatur​e

We can also look at our private key in pki/private/ca.key

lachlan@lachlan-thinkpad:~/talk/ca > openssl rsa -in pki/private/ca.key -text | xclip -selection clipboard
Enter pass phrase for pki/private/ca.key:
writing RSA key
Private-Key: (2048 bit, 2 primes)
modulus:
    00:99:d5:45:ee:fc:60:eb:e0:3c:ab:c4:57:8d:e0:
    ef:a0:20:b5:f9:90:30:74:e9:55:68:d9:59:23:5b:
    b9:84:2e:74:a4:f8:36:74:18:b8:f7:2c:1b:03:f5:
    3f:8a:2c:9b:05:d0:33:36:38:c7:56:72:2e:e0:8c:
    6e:47:90:c9:12:03:df:1a:f0:77:84:4b:b7:10:68:
    09:ed:41:87:ce:c0:e5:67:95:62:c0:ab:a1:05:40:
    57:45:2c:24:cc:e8:3f:65:c8:38:98:db:62:69:a4:
    55:74:8c:a7:08:26:51:a6:d2:c6:08:d2:09:f4:69:
    6d:27:01:34:6d:a1:72:06:02:17:a7:6f:5e:d6:65:
    7b:25:bc:77:b3:ca:89:a0:47:2a:41:02:63:7d:1d:
    b7:f3:b7:01:30:eb:c7:43:6f:3f:55:e2:be:08:87:
    4b:20:5d:93:39:c6:ea:65:da:7d:d5:48:36:2b:a4:
    3a:08:19:95:db:46:51:c9:6f:40:4f:99:60:1f:1c:
    40:0c:9e:d9:ba:df:b4:0e:06:e2:c5:5d:07:3d:38:
    d1:4f:b1:31:a4:5c:0b:b3:4c:f2:bf:33:e8:9c:af:
    c4:50:a8:04:e1:75:20:3b:1b:d4:2c:dd:4d:ad:af:
    3d:f7:18:05:0f:50:a7:f1:ca:65:e7:65:26:30:63:
    13:15
publicExponent: 65537 (0x10001)
privateExponent:
    46:e4:6c:58:18:62:aa:11:2a:a4:95:d5:2b:83:2f:
    ab:01:a8:1b:1c:81:d8:3e:f7:a7:5c:12:a2:22:d1:
    39:c3:16:ea:37:a1:10:9b:9c:11:fc:77:6e:b9:84:
    d0:ae:81:ba:8a:1a:2f:b0:b6:dc:75:be:78:a8:fe:
    e1:68:2d:e1:69:7b:55:b4:df:bf:4e:0d:4d:38:44:
    ea:db:ba:34:63:dc:d4:81:99:82:e5:15:4d:90:3b:
    27:9b:92:52:03:ed:c3:80:23:e4:fd:a5:3a:be:0a:
    cb:ad:4e:04:89:74:33:87:0a:d0:61:cb:48:a1:95:
    35:d6:6e:4c:df:8b:e6:8c:35:51:39:ca:2d:bf:ef:
    5e:e4:a2:f6:ca:96:64:ee:f0:f8:8b:8d:a3:71:e5:
    c5:69:2a:b0:bc:aa:12:fa:03:c0:de:7d:63:43:10:
    d6:d6:83:27:a0:ed:87:c4:b2:4f:d2:3d:89:f0:1d:
    7d:19:64:27:bc:e0:c6:fe:e7:85:d8:55:c3:1a:2f:
    af:1b:6d:40:6c:0b:9e:56:62:ba:bf:b6:de:51:77:
    b6:8d:43:0e:ec:6c:54:c0:36:07:b7:2c:d6:88:57:
    85:3b:e6:a9:8b:e3:74:c2:c1:35:e0:da:3b:e6:63:
    ed:ff:c0:f4:14:2a:44:3c:f3:ad:58:d9:9c:f4:40:
    79
prime1:
    00:c0:98:e6:4c:2d:d7:9d:08:31:94:69:b5:be:55:
    30:a1:12:29:88:32:71:72:a1:d8:65:40:ed:3e:51:
    f4:4d:e6:6c:f0:17:25:d6:1d:25:0a:b5:4a:e2:1e:
    65:fe:7f:51:7c:5d:7b:96:f1:1d:cd:3b:54:91:a4:
    cb:7b:42:db:af:2d:f2:76:f4:61:4e:02:2d:0c:c2:
    6c:f5:59:20:28:45:80:51:73:48:c7:7e:7f:55:54:
    a4:fb:6b:b7:48:0c:fe:ea:4c:3d:74:4f:7d:a2:09:
    0d:89:8d:22:03:62:2b:fc:c0:7e:97:08:83:46:06:
    b3:83:72:17:36:e1:a0:c0:bb
prime2:
    00:cc:79:87:c5:c8:5b:2b:8c:28:5c:6b:83:f1:15:
    a4:72:3b:cf:b3:60:82:ff:7f:8c:74:d4:2e:3f:d8:
    d8:f4:a1:c5:ef:d5:45:02:88:74:c8:57:b1:fb:7d:
    b3:82:5d:ac:28:37:2e:ba:56:9d:a7:15:47:ea:75:
    2a:b9:6e:52:25:d1:46:a6:25:03:60:ef:41:cc:db:
    dd:ff:ec:e2:fd:f0:8c:04:0a:23:33:68:19:9c:b5:
    ec:4f:e2:ff:23:d3:be:c4:ea:3a:c2:6e:a6:66:8a:
    90:2a:3d:40:fe:68:bb:ca:f7:55:d0:a8:62:5b:ba:
    2b:c9:ab:cd:64:84:df:66:6f
exponent1:
    1c:9e:dc:22:57:f1:a1:a1:55:14:d3:fc:b1:13:21:
    cd:dd:d0:14:30:42:d1:a1:21:72:32:8a:ce:e7:08:
    e2:06:ab:0b:a6:b4:f5:b3:91:0c:9d:52:4a:75:ef:
    fc:38:d9:58:1c:e0:3f:d7:06:f1:b7:ae:62:92:55:
    b6:b4:81:c6:ef:92:07:81:5b:70:67:3c:60:98:07:
    ef:11:d6:88:85:83:83:17:19:aa:a3:ae:b2:74:88:
    ab:e0:1e:f5:73:10:f2:aa:6f:bb:78:10:98:62:b6:
    03:49:d8:d3:1d:e4:a1:83:cd:8c:0e:34:cb:d4:35:
    1b:04:7a:54:aa:84:e3:ff
exponent2:
    52:70:81:4c:3d:ce:7c:4d:43:0c:98:10:97:47:e9:
    88:61:13:09:b8:54:b8:9c:7d:4d:b1:2a:80:75:76:
    6b:93:39:d1:cb:83:ca:54:a7:f9:0a:5a:69:12:32:
    28:d2:89:91:a1:46:06:bc:db:4d:3d:28:44:a0:3e:
    bc:8a:7d:36:60:1d:02:e9:93:66:26:b0:b9:de:bf:
    af:ea:9b:4e:55:08:ae:ac:43:aa:fb:42:b0:4b:2c:
    de:bc:9f:af:9b:34:a4:01:e7:f4:f2:55:c6:ac:01:
    19:f6:9e:58:b4:73:5a:8e:c4:1b:9f:78:20:91:7c:
    0c:10:67:7c:2a:92:43:a3
coefficient:
    6a:29:b1:df:af:1a:32:66:30:d5:e0:41:6e:be:70:
    b4:4d:24:68:ee:b5:45:7b:70:dc:20:e2:8e:00:dc:
    f8:43:c6:ee:b5:e2:a1:c3:b6:c9:c3:a7:cb:0c:88:
    d2:73:84:81:27:f6:48:3f:d6:f2:90:cc:8f:cb:3e:
    bf:de:82:db:66:a7:2b:f3:5c:e5:6d:e0:ca:a6:c8:
    07:49:dc:71:ba:b7:cd:2f:a2:5a:f3:a3:64:19:1d:
    e0:9d:d7:ee:30:27:ad:7c:b6:d5:86:20:28:46:b0:
    72:b0:14:1c:cd:27:c9:d6:37:e4:90:29:c5:65:cd:
    34:14:62:3d:a1:e4:08:42
-----BEGIN PRIVATE KEY-----
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCZ1UXu/GDr4Dyr
xFeN4O+gILX5kDB06VVo2VkjW7mELnSk+DZ0GLj3LBsD9T+KLJsF0DM2OMdWci7g
jG5HkMkSA98a8HeES7cQaAntQYfOwOVnlWLAq6EFQFdFLCTM6D9lyDiY22JppFV0
jKcIJlGm0sYI0gn0aW0nATRtoXIGAhenb17WZXslvHezyomgRypBAmN9HbfztwEw
68dDbz9V4r4Ih0sgXZM5xupl2n3VSDYrpDoIGZXbRlHJb0BPmWAfHEAMntm637QO
BuLFXQc9ONFPsTGkXAuzTPK/M+icr8RQqAThdSA7G9Qs3U2trz33GAUPUKfxymXn
ZSYwYxMVAgMBAAECggEARuRsWBhiqhEqpJXVK4MvqwGoGxyB2D73p1wSoiLROcMW
6jehEJucEfx3brmE0K6BuooaL7C23HW+eKj+4Wgt4Wl7VbTfv04NTThE6tu6NGPc
1IGZguUVTZA7J5uSUgPtw4Aj5P2lOr4Ky61OBIl0M4cK0GHLSKGVNdZuTN+L5ow1
UTnKLb/vXuSi9sqWZO7w+IuNo3HlxWkqsLyqEvoDwN59Y0MQ1taDJ6Dth8SyT9I9
ifAdfRlkJ7zgxv7nhdhVwxovrxttQGwLnlZiur+23lF3to1DDuxsVMA2B7cs1ohX
hTvmqYvjdMLBNeDaO+Zj7f/A9BQqRDzzrVjZnPRAeQKBgQDAmOZMLdedCDGUabW+
VTChEimIMnFyodhlQO0+UfRN5mzwFyXWHSUKtUriHmX+f1F8XXuW8R3NO1SRpMt7
QtuvLfJ29GFOAi0Mwmz1WSAoRYBRc0jHfn9VVKT7a7dIDP7qTD10T32iCQ2JjSID
Yiv8wH6XCINGBrODchc24aDAuwKBgQDMeYfFyFsrjChca4PxFaRyO8+zYIL/f4x0
1C4/2Nj0ocXv1UUCiHTIV7H7fbOCXawoNy66Vp2nFUfqdSq5blIl0UamJQNg70HM
293/7OL98IwECiMzaBmctexP4v8j077E6jrCbqZmipAqPUD+aLvK91XQqGJbuivJ
q81khN9mbwKBgBye3CJX8aGhVRTT/LETIc3d0BQwQtGhIXIyis7nCOIGqwumtPWz
kQydUkp17/w42Vgc4D/XBvG3rmKSVba0gcbvkgeBW3BnPGCYB+8R1oiFg4MXGaqj
rrJ0iKvgHvVzEPKqb7t4EJhitgNJ2NMd5KGDzYwONMvUNRsEelSqhOP/AoGAUnCB
TD3OfE1DDJgQl0fpiGETCbhUuJx9TbEqgHV2a5M50cuDylSn+QpaaRIyKNKJkaFG
BrzbTT0oRKA+vIp9NmAdAumTZiawud6/r+qbTlUIrqxDqvtCsEss3ryfr5s0pAHn
9PJVxqwBGfaeWLRzWo7EG594IJF8DBBnfCqSQ6MCgYBqKbHfrxoyZjDV4EFuvnC0
TSRo7rVFe3DcIOKOANz4Q8buteKhw7bJw6fLDIjSc4SBJ/ZIP9bykMyPyz6/3oLb
Zqcr81zlbeDKpsgHSdxxurfNL6Ja86NkGR3gndfuMCetfLbVhiAoRrBysBQczSfJ
1jfkkCnFZc00FGI9oeQIQg==
-----END PRIVATE KEY-----

The first 5 values should seem familiar (n, e, d, p ,q). The last 3 are precomputed values to make the calculations faster.

Next we'll set up our consumer and create a signing request. I'll make a request for localhost since we'll use this later to encrypt connections to localhost for the browser

cd ../consumer
lachlan@lachlan-thinkpad:~/talk/consumer > easyrsa init-pki

init-pki complete; you may now create a CA or requests.
Your newly created PKI dir is: /home/lachlan/talk/consumer/pki


lachlan@lachlan-thinkpad:~/talk/consumer > easyrsa gen-req localhost
Using SSL: openssl OpenSSL 3.0.2 15 Mar 2022 (Library: OpenSSL 3.0.2 15 Mar 2022)
.....+.+........+.+.........+.........+...+.....+.......+...........+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*....+...+..+.+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*........+...........+....+..+...+.......+..+...+...+......+.........+..........+.....+.+.....+.+............+........+............+...+....+...+......+.....................+........+.+......+.....+...+...+...+.+...........+....+......+............+..+...+.......+..............+.........+.+.........+.....+.+.....+.........+.+......+.....+...+..................+...+.........+.+..+.........+....+............+............+...+..+.+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
....+....+.........+..............+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*...............+.+..+.......+..+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*.+.+.........+...........+..........+...+...........+...+..........+...+..+.+...........+.+...............+........+....+..+......+.............+.....+..........+..+....+..................+...+..+.+..+...+.+...+..+...............+.+...+......+.....+...+...+.............+.....+....+.....+..........+..+....+..+.......+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Common Name (eg: your user, host, or server name) [localhost]:

Keypair and certificate request completed. Your files are:
req: /home/lachlan/talk/consumer/pki/reqs/localhost.req
key: /home/lachlan/talk/consumer/pki/private/localhost.key

The certificate signing request is a wrapper around our public key we can use to request a certificate from a CA. We can also inspect this with the openssl tools

lachlan@lachlan-thinkpad:~/talk/consumer > openssl req -in pki/reqs/localhost.req -text
Certificate Request:
    Data:
        Version: 1 (0x0)
        Subject: CN = localhost
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)
                Modulus:
                    00:88:8f:85:82:53:73:cd:7b:6d:8c:4f:44:91:94:
                    f0:14:70:37:fe:fd:df:f7:f5:8a:b6:d4:17:34:30:
                    84:7c:87:d5:8d:0b:45:e9:59:14:fa:5a:d8:d1:4c:
                    0c:5b:84:29:b9:a7:a4:7d:4a:6d:98:73:0a:95:d2:
                    f8:f2:32:46:c0:76:4a:9c:74:c1:3c:09:10:c4:e3:
                    bb:89:0f:87:72:57:ec:77:b9:9b:16:34:18:28:9b:
                    f9:e3:ce:f8:4e:da:d3:b5:10:13:74:31:cb:24:3e:
                    37:e2:ec:2f:06:60:cf:25:50:43:3a:f0:92:7a:e2:
                    cd:3d:4e:54:aa:f5:a5:a2:12:39:6d:8f:3c:e4:65:
                    9f:57:4d:71:3e:1b:61:db:d0:84:9e:b0:37:7c:4b:
                    de:82:1e:fb:b1:22:74:b7:07:e1:d0:a8:bb:bc:75:
                    f9:dc:ab:59:11:ab:fb:f1:61:1f:04:ee:08:c6:e6:
                    39:67:9e:2f:c6:6f:65:04:38:fe:76:0a:a1:06:f6:
                    fb:c9:c4:a0:e1:83:19:9a:db:ac:ac:ab:18:de:ae:
                    03:6b:1b:a4:a1:4d:ce:1a:63:ec:18:3f:9d:58:d8:
                    fa:79:81:e8:e8:fd:82:aa:7b:8a:01:cc:71:ce:0d:
                    ed:5a:d3:1b:07:6f:f9:4e:08:bf:18:39:0d:46:f6:
                    d4:99
                Exponent: 65537 (0x10001)
        Attributes:
            (none)
            Requested Extensions:
    Signature Algorithm: sha256WithRSAEncryption
    Signature Value:
        37:65:6b:f8:54:a7:6c:e6:17:b8:de:cd:6a:f1:aa:5c:1b:21:
        c8:9b:a0:7c:db:54:31:c9:4a:6f:36:8b:3f:47:f7:9c:fc:e2:
        70:7a:14:b0:f6:6d:72:86:9c:51:b7:78:e4:87:ce:86:9e:04:
        a8:9c:5b:f9:3e:01:7c:eb:db:92:26:64:ad:76:ad:1e:f3:9e:
        71:5c:9e:bf:d4:86:a6:f0:8b:a8:28:84:6b:cd:5e:0c:70:ce:
        34:0a:0d:6f:69:f5:e4:6c:cc:29:14:b9:ef:ba:be:ee:19:76:
        08:66:a1:94:f8:c9:c4:f3:d6:be:97:bc:d8:ee:73:c9:59:17:
        9b:92:7e:67:8d:fd:3c:16:95:44:42:86:86:c1:db:46:9f:b8:
        08:52:a5:d5:0a:98:94:52:91:5a:85:dd:51:45:eb:23:89:d7:
        76:02:1b:f7:1e:48:65:df:ed:48:ba:1b:05:24:5b:8b:b2:4b:
        cf:b6:f0:1b:62:8f:2b:a2:d9:d4:23:b6:11:9b:31:4d:4b:c0:
        77:36:98:97:a6:cc:be:af:bf:ca:35:ef:be:73:17:3a:e4:a2:
        d5:0f:72:d2:b5:16:a8:9c:9f:d2:ed:db:35:7d:51:1d:7a:26:
        83:36:a7:59:10:6e:00:e7:b2:cd:d7:ec:66:b7:7b:15:23:b2:
        87:61:c8:a2
-----BEGIN CERTIFICATE REQUEST-----
MIICWDCCAUACAQAwEzERMA8GA1UEAwwIQ29uc3VtZXIwggEiMA0GCSqGSIb3DQEB
AQUAA4IBDwAwggEKAoIBAQCIj4WCU3PNe22MT0SRlPAUcDf+/d/39Yq21Bc0MIR8
h9WNC0XpWRT6WtjRTAxbhCm5p6R9Sm2YcwqV0vjyMkbAdkqcdME8CRDE47uJD4dy
V+x3uZsWNBgom/njzvhO2tO1EBN0McskPjfi7C8GYM8lUEM68JJ64s09TlSq9aWi
EjltjzzkZZ9XTXE+G2Hb0ISesDd8S96CHvuxInS3B+HQqLu8dfncq1kRq/vxYR8E
7gjG5jlnni/Gb2UEOP52CqEG9vvJxKDhgxma26ysqxjergNrG6ShTc4aY+wYP51Y
2Pp5gejo/YKqe4oBzHHODe1a0xsHb/lOCL8YOQ1G9tSZAgMBAAGgADANBgkqhkiG
9w0BAQsFAAOCAQEAN2Vr+FSnbOYXuN7NavGqXBshyJugfNtUMclKbzaLP0f3nPzi
cHoUsPZtcoacUbd45IfOhp4EqJxb+T4BfOvbkiZkrXatHvOecVyev9SGpvCLqCiE
a81eDHDONAoNb2n15GzMKRS577q+7hl2CGahlPjJxPPWvpe82O5zyVkXm5J+Z439
PBaVREKGhsHbRp+4CFKl1QqYlFKRWoXdUUXrI4nXdgIb9x5IZd/tSLobBSRbi7JL
z7bwG2KPK6LZ1CO2EZsxTUvAdzaYl6bMvq+/yjXvvnMXOuSi1Q9y0rUWqJyf0u3b
NX1RHXomgzanWRBuAOeyzdfsZrd7FSOyh2HIog==
-----END CERTIFICATE REQUEST-----

Next we need to give this request to the CA, and sign it

lachlan@lachlan-thinkpad:~/talk/ca > easyrsa import-req ../consumer/pki/reqs/localhost.req localhost
Using SSL: openssl OpenSSL 3.0.2 15 Mar 2022 (Library: OpenSSL 3.0.2 15 Mar 2022)

The request has been successfully imported with a short name of: localhost
You may now use this name to perform signing operations on this request.

lachlan@lachlan-thinkpad:~/talk/ca > easyrsa sign-req server localhost
Using SSL: openssl OpenSSL 3.0.2 15 Mar 2022 (Library: OpenSSL 3.0.2 15 Mar 2022)


You are about to sign the following certificate.
Please check over the details shown below for accuracy. Note that this request
has not been cryptographically verified. Please be sure it came from a trusted
source or that you have verified the request checksum with the sender.

Request subject, to be signed as a server certificate for 825 days:

subject=
    commonName                = localhost


Type the word 'yes' to continue, or any other input to abort.
  Confirm request details: yes
Using configuration from /home/lachlan/talk/ca/pki/easy-rsa-422007.7HiEeT/tmp.oic53D
Enter pass phrase for /home/lachlan/talk/ca/pki/private/ca.key:
40D766BE7B7F0000:error:0700006C:configuration file routines:NCONF_get_string:no value:../crypto/conf/conf_lib.c:315:group=<NULL> name=unique_subject
Check that the request matches the signature
Signature ok
The Subject's Distinguished Name is as follows
commonName            :ASN.1 12:'localhost'
Certificate is to be certified until Sep 10 15:19:02 2025 GMT (825 days)

Write out database with 1 new entries
Data Base Updated

Certificate created at: /home/lachlan/talk/ca/pki/issued/localhost.crt

We can sign the certificate for a client or a server, I'm going to use this for a server. So I have speicified that. We now have a certificate under pki/issued/localhost.crt

SSL tunnelling with stunnel

Let's make and serve a simple website

lachlan@lachlan-thinkpad:~/talk > mkdir mysite
lachlan@lachlan-thinkpad:~/talk > cd mysite
lachlan@lachlan-thinkpad:~/talk/mysite > echo "<html><body><p>Hi</p></body></html>" > index.html
lachlan@lachlan-thinkpad:~/talk/mysite > python3 -m http.server
Serving HTTP on 0.0.0.0 port 9000 (http://0.0.0.0:8000/) ...

I'm just going to remove the passphrase from the key so stunnel can read it easier

lachlan@lachlan-thinkpad:~/talk/mysite > openssl rsa -in /home/lachlan/talk/consumer/pki/private/localhost.key > localhost.key
Enter pass phrase for /home/lachlan/talk/consumer/pki/private/localhost.key:
writing RSA key

We can now wrap this connection with a proxy that will add an ssl layer

cat  <<EOF > stunnel.conf
foreground = yes
[server]
accept = localhost:443
connect = localhost:8000
cert = /home/lachlan/talk/ca/pki/issued/localhost.crt
key = /home/lachlan/talk/mysite/localhost.key
EOF

This configuration will start a server on localhost:443 which proxies connections to localhost:8000 using the provided certificate and private key.

We need to run stunnel as root so it can bind to port 443

lachlan@lachlan-thinkpad:~/talk/mysite > sudo stunnel stunnel.conf

Chrome will tell us that the certificate is invalid with an error

NET::ERR_CERT_AUTHORITY_INVALID

Because it doesn't recognise the CA. We can add our CA in settings -> privacy & security -> security -> advanced -> manage certificates -> authorities. After adding the CA and refreshing the page you will see that our site's certificate signed by that authority is accepted.

If you do this you should probably delete it later.