TLS by Hand
Certificate Authority
The root CA needs a private key for its certs.
This generates the CA cert using its private key.
openssl req \
-x509 -new \
-key ca.key \
-noenc \
-sha512 \
-days 3650 \
-out ca.crt \
-subj "/CN=Homelab-Test"
openssl-req command explained
This command generates a certificate signing request (CSR) and signs it with a private key to create the certificate.
- -x509
- Output the signed certificate (skip outputting the CSR)
- -new
- Generate a new certificate request
- -key ca.key
- Path to the private key used to sign the request
- -noenc
- Do not encrypt the private key (not recommended, only used for example)
- -sha512
- Use SHA-512 as the message digest algorithm, may as well for the minimal overhead.
- -days 3650
- Number of days the certificate is valid for (10 years)
- -out ca.crt
- Path to the output file for the certificate
- -subj "/CN=Homelab-Test"
- Set certificate subject directly without prompting. Only uses
CN(common name) in this case.
Example output
The CA cert is self-signed, so the Issuer and Subject match.
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
3a:10:80:35:78:1c:0d:0d:89:a7:21:fd:22:3c:9e:94:c9:5e:4b:cc
Signature Algorithm: ED25519
Issuer: CN=Homelab-Test
Validity
Not Before: Dec 13 02:57:00 2025 GMT
Not After : Dec 11 02:57:00 2035 GMT
Subject: CN=Homelab-Test
Subject Public Key Info:
Public Key Algorithm: ED25519
ED25519 Public-Key:
pub:
02:81:24:a0:f9:6b:ee:18:13:8c:a3:96:c2:fa:fe:
03:34:73:85:f8:10:31:7e:01:4d:1d:dc:68:7d:46:
66:fa
X509v3 extensions:
X509v3 Subject Key Identifier:
F4:BE:0F:25:44:FC:F6:DA:9E:94:56:71:61:71:3E:80:39:7A:20:CE
X509v3 Authority Key Identifier:
F4:BE:0F:25:44:FC:F6:DA:9E:94:56:71:61:71:3E:80:39:7A:20:CE
X509v3 Basic Constraints: critical
CA:TRUE
Signature Algorithm: ED25519
Signature Value:
dd:e0:4c:1e:a4:7e:70:89:79:77:df:c2:d3:b6:2b:33:2d:c1:
9d:f0:03:b2:e1:ec:5c:ce:05:63:19:32:cc:4b:0e:e2:11:8a:
8b:10:40:a2:46:63:67:fa:04:2c:40:3e:3f:09:84:f6:55:c0:
f4:24:e9:05:d4:18:74:86:08:0a
Clients
Each client also needs a private key for its certs.
To get a signed certificate, the clients must first generate a certificate signing request (CSR). This example request uses app.internal.lan for the CN.
Transfer the CSR file to the system with the CA private key. This does not have to be done securely because the CSR is considered public. Then sign it using the CA private key and CA cert to produce the cert for the client.
openssl x509 -req \
-in client.csr \
-CA ca.crt \
-CAkey ca.key \
-CAcreateserial \
-sha512 \
-days 3650 \
-out client.crt
openssl-x509 command explained
- -req
- By default a certificate is expected on input. With this option a PKCS#10 certificate request is expected instead, which must be correctly self-signed.
- -in client.csr
- Path to the client CSR to be signed.
- -CA ca.crt
- Path to the CA certificate to use for signing.
- -CAkey
- Sets the CA private key to sign a certificate with. The private key must match the public key of the certificate given with
-CA. - -CAcreateserial
- With this option and the
-CAoption the CA serial number file is created if it does not exist. - -sha512
- Use SHA-512 as the message digest algorithm, may as well for the minimal overhead.
- -days 3650
- Number of days the certificate is valid for (10 years)
- -out client.crt
- Path to the output file of the certificate
Example client cert content
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
1b:5e:05:be:31:6e:a8:56:cc:96:d6:45:1e:bf:27:f1:44:d8:01:9a
Signature Algorithm: ED25519
Issuer: CN=Homelab-Test
Validity
Not Before: Dec 13 02:59:19 2025 GMT
Not After : Dec 11 02:59:19 2035 GMT
Subject: CN=app.internal.lan
Subject Public Key Info:
Public Key Algorithm: ED25519
ED25519 Public-Key:
pub:
c3:62:05:9c:28:2d:f6:2d:44:da:3a:b7:8a:2c:e1:
ce:6e:ae:bd:e8:af:15:bd:49:dd:46:be:e0:2c:9c:
01:bd
X509v3 extensions:
X509v3 Subject Key Identifier:
E6:D7:94:19:9F:C2:6B:20:62:21:F9:DF:DF:86:83:17:15:19:E3:3B
X509v3 Authority Key Identifier:
F4:BE:0F:25:44:FC:F6:DA:9E:94:56:71:61:71:3E:80:39:7A:20:CE
Signature Algorithm: ED25519
Signature Value:
ee:c8:e0:c0:4d:3b:b5:d1:75:f1:f5:b8:e2:9b:37:65:f2:7c:
e7:95:a9:92:20:56:06:e0:d7:0e:c6:29:20:2d:86:18:58:69:
10:16:a1:32:74:2a:9d:89:6b:89:62:a1:29:71:ac:9a:07:23:
3b:3c:18:85:ed:de:a2:c0:21:01
In order to be installed into browsers, the client private key and (public) cert need to be encoded into a single file in the pkcs12 format.
openssl pkcs12 -export \
-in client.crt \
-inkey client.key \
-certfile ca.crt \
-out client.p12 \
-name "Test Client Certificate" \
-passout pass:
openssl-pkcs12 command explained
- -export
- Specifies that a PKCS#12 file will be created rather than parsed.
- -in client.crt
- Path to the signed client cert to include in the bundle.
- -inkey client.key
- Path to the client private key to include in the bundle.
- -certfile ca.crt
- Path to additional certs to be included
- -out client.p12
- Path to the bundled output file
- -name "Test Client Certificate"
- This specifies the "friendly name" for the certificates and private key. This name is typically displayed in list boxes by software importing the file.
- -password pass:
-
Creates the bundle with an empty password (which is different than having no password).
This is only done for simplicity in the demo. Use a password in a real situation
This creates the bundle with an empty password
PKCS#12 is not a text format, so the file contents aren't human-readable with cat.
Example cert content in pkcs12 file
The data section should exactly match the one from checking the cert file itself (above).
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
1b:5e:05:be:31:6e:a8:56:cc:96:d6:45:1e:bf:27:f1:44:d8:01:9a
Signature Algorithm: ED25519
Issuer: CN=Homelab-Test
Validity
Not Before: Dec 13 02:59:19 2025 GMT
Not After : Dec 11 02:59:19 2035 GMT
Subject: CN=app.internal.lan
Subject Public Key Info:
Public Key Algorithm: ED25519
ED25519 Public-Key:
pub:
c3:62:05:9c:28:2d:f6:2d:44:da:3a:b7:8a:2c:e1:
ce:6e:ae:bd:e8:af:15:bd:49:dd:46:be:e0:2c:9c:
01:bd
X509v3 extensions:
X509v3 Subject Key Identifier:
E6:D7:94:19:9F:C2:6B:20:62:21:F9:DF:DF:86:83:17:15:19:E3:3B
X509v3 Authority Key Identifier:
F4:BE:0F:25:44:FC:F6:DA:9E:94:56:71:61:71:3E:80:39:7A:20:CE
Signature Algorithm: ED25519
Signature Value:
ee:c8:e0:c0:4d:3b:b5:d1:75:f1:f5:b8:e2:9b:37:65:f2:7c:
e7:95:a9:92:20:56:06:e0:d7:0e:c6:29:20:2d:86:18:58:69:
10:16:a1:32:74:2a:9d:89:6b:89:62:a1:29:71:ac:9a:07:23:
3b:3c:18:85:ed:de:a2:c0:21:01
No Trusted Uses.
No Rejected Uses.
Alias: Test Client Certificate
Key Id: C0:4A:11:83:9A:6F:9F:E7:FC:09:42:F6:DC:AE:02:32:B5:38:80:C8
Example encoded pkcs12 file content
MAC: sha256, Iteration 2048
MAC length: 32, salt length: 8
PKCS7 Encrypted data: PBES2, PBKDF2, AES-256-CBC, Iteration 2048, PRF hmacWithSHA256
Certificate bag
Bag Attributes
localKeyID: C0 4A 11 83 9A 6F 9F E7 FC 09 42 F6 DC AE 02 32 B5 38 80 C8
friendlyName: Test Client Certificate
subject=CN=app.internal.lan
issuer=CN=Homelab-Test
-----BEGIN CERTIFICATE-----
MIIBNTCB6KADAgECAhQbXgW+MW6oVsyW1kUevyfxRNgBmjAFBgMrZXAwFzEVMBMG
A1UEAwwMSG9tZWxhYi1UZXN0MB4XDTI1MTIxMzAyNTkxOVoXDTM1MTIxMTAyNTkx
OVowGzEZMBcGA1UEAwwQYXBwLmludGVybmFsLmxhbjAqMAUGAytlcAMhAMNiBZwo
LfYtRNo6t4os4c5urr3orxW9Sd1GvuAsnAG9o0IwQDAdBgNVHQ4EFgQU5teUGZ/C
ayBiIfnf34aDFxUZ4zswHwYDVR0jBBgwFoAU9L4PJUT89tqelFZxYXE+gDl6IM4w
BQYDK2VwA0EA7sjgwE07tdF18fW44ps3ZfJ855WpkiBWBuDXDsYpIC2GGFhpEBah
MnQqnYlriWKhKXGsmgcjOzwYhe3eosAhAQ==
-----END CERTIFICATE-----
Certificate bag
Bag Attributes: <No Attributes>
subject=CN=Homelab-Test
issuer=CN=Homelab-Test
-----BEGIN CERTIFICATE-----
MIIBQjCB9aADAgECAhQ6EIA1eBwNDYmnIf0iPJ6UyV5LzDAFBgMrZXAwFzEVMBMG
A1UEAwwMSG9tZWxhYi1UZXN0MB4XDTI1MTIxMzAyNTcwMFoXDTM1MTIxMTAyNTcw
MFowFzEVMBMGA1UEAwwMSG9tZWxhYi1UZXN0MCowBQYDK2VwAyEAAoEkoPlr7hgT
jKOWwvr+AzRzhfgQMX4BTR3caH1GZvqjUzBRMB0GA1UdDgQWBBT0vg8lRPz22p6U
VnFhcT6AOXogzjAfBgNVHSMEGDAWgBT0vg8lRPz22p6UVnFhcT6AOXogzjAPBgNV
HRMBAf8EBTADAQH/MAUGAytlcANBAN3gTB6kfnCJeXffwtO2KzMtwZ3wA7Lh7FzO
BWMZMsxLDuIRiosQQKJGY2f6BCxAPj8JhPZVwPQk6QXUGHSGCAo=
-----END CERTIFICATE-----
PKCS7 Data
Shrouded Keybag: PBES2, PBKDF2, AES-256-CBC, Iteration 2048, PRF hmacWithSHA256
Bag Attributes
localKeyID: C0 4A 11 83 9A 6F 9F E7 FC 09 42 F6 DC AE 02 32 B5 38 80 C8
friendlyName: Test Client Certificate
Key Attributes: <No Attributes>
-----BEGIN ENCRYPTED PRIVATE KEY-----
MIGjMF8GCSqGSIb3DQEFDTBSMDEGCSqGSIb3DQEFDDAkBBDUJfsK0aRbxXvsJbbH
jQIaAgIIADAMBggqhkiG9w0CCQUAMB0GCWCGSAFlAwQBKgQQXLdguXFiSd1hx7k7
9KsrKARARkp3r5YAq4kDjxBd63PtrOagY8+9yAoWNsjVl2Lh78Ps3EOLgjSYOEgQ
0uLlSongFRtg1SKiYa2fBOK9G6AlXA==
-----END ENCRYPTED PRIVATE KEY-----
These keys are not real and only shown for demo purposes. Never reveal a private key like this in practice, and store it securely.
Example unencoded pkcs12 file content
MAC: sha256, Iteration 2048
MAC length: 32, salt length: 8
PKCS7 Encrypted data: PBES2, PBKDF2, AES-256-CBC, Iteration 2048, PRF hmacWithSHA256
Certificate bag
Bag Attributes
localKeyID: C0 4A 11 83 9A 6F 9F E7 FC 09 42 F6 DC AE 02 32 B5 38 80 C8
friendlyName: Test Client Certificate
subject=CN=app.internal.lan
issuer=CN=Homelab-Test
-----BEGIN CERTIFICATE-----
MIIBNTCB6KADAgECAhQbXgW+MW6oVsyW1kUevyfxRNgBmjAFBgMrZXAwFzEVMBMG
A1UEAwwMSG9tZWxhYi1UZXN0MB4XDTI1MTIxMzAyNTkxOVoXDTM1MTIxMTAyNTkx
OVowGzEZMBcGA1UEAwwQYXBwLmludGVybmFsLmxhbjAqMAUGAytlcAMhAMNiBZwo
LfYtRNo6t4os4c5urr3orxW9Sd1GvuAsnAG9o0IwQDAdBgNVHQ4EFgQU5teUGZ/C
ayBiIfnf34aDFxUZ4zswHwYDVR0jBBgwFoAU9L4PJUT89tqelFZxYXE+gDl6IM4w
BQYDK2VwA0EA7sjgwE07tdF18fW44ps3ZfJ855WpkiBWBuDXDsYpIC2GGFhpEBah
MnQqnYlriWKhKXGsmgcjOzwYhe3eosAhAQ==
-----END CERTIFICATE-----
Certificate bag
Bag Attributes: <No Attributes>
subject=CN=Homelab-Test
issuer=CN=Homelab-Test
-----BEGIN CERTIFICATE-----
MIIBQjCB9aADAgECAhQ6EIA1eBwNDYmnIf0iPJ6UyV5LzDAFBgMrZXAwFzEVMBMG
A1UEAwwMSG9tZWxhYi1UZXN0MB4XDTI1MTIxMzAyNTcwMFoXDTM1MTIxMTAyNTcw
MFowFzEVMBMGA1UEAwwMSG9tZWxhYi1UZXN0MCowBQYDK2VwAyEAAoEkoPlr7hgT
jKOWwvr+AzRzhfgQMX4BTR3caH1GZvqjUzBRMB0GA1UdDgQWBBT0vg8lRPz22p6U
VnFhcT6AOXogzjAfBgNVHSMEGDAWgBT0vg8lRPz22p6UVnFhcT6AOXogzjAPBgNV
HRMBAf8EBTADAQH/MAUGAytlcANBAN3gTB6kfnCJeXffwtO2KzMtwZ3wA7Lh7FzO
BWMZMsxLDuIRiosQQKJGY2f6BCxAPj8JhPZVwPQk6QXUGHSGCAo=
-----END CERTIFICATE-----
PKCS7 Data
Shrouded Keybag: PBES2, PBKDF2, AES-256-CBC, Iteration 2048, PRF hmacWithSHA256
Bag Attributes
localKeyID: C0 4A 11 83 9A 6F 9F E7 FC 09 42 F6 DC AE 02 32 B5 38 80 C8
friendlyName: Test Client Certificate
Key Attributes: <No Attributes>
-----BEGIN PRIVATE KEY-----
MC4CAQAwBQYDK2VwBCIEIP2gM3spbjAAWUumu0GkDghgT/bXY+tlarZjvP8HK9kg
-----END PRIVATE KEY-----