OpenPGP Part3: Create Your Subkeys
In this post we’re going to create our subkeys which will be our daily workhorses for accomplishing security-related tasks such as signing, encrypting, and authenticating to other services. If you landed directly here you may want to check out the first two parts of this series.
Part 2 shows how you can following along at home in Docker.
I am not, and do not claim to be a security expert. I’ve just spent a lot of time researching this and trying to implement best practices. I have made my best effort to ensure this information is accurate and up to date at the time of writing with all references provided. If you find a mistake whether small or egregious please let me know so I can improve this content.
A Brief Note On Subkeys
During my research I found many people ask “why subkeys”? Well, the good folks at Debian have done an incredible job of explaining it so I won’t repeat those keystrokes here. Head on over there and learn about them.
TL;DR Subkeys allow you to have fine-grained control of your keys and capabilities and are easily revoked and changed without affecting your root chain of trust (Primary Key).
Create Signing Subkeys
Signing keys are used for signing…well…pretty much anything. You can sign files, messages, emails, software packages, etc. SecureBoot on the ESP32 requires a signing key to sign the firmware binaries. The signing operation is performed with the private key portion of a key pair which can then be validated by anyone who has the public key portion. It allows you to validate a digital asset originated from who you think it originated from. Here is where the argument of ECC and RSA comes back up. Remember, ECC produces smaller signatures but RSA is more backward compatible with online services. Since these are subkeys we don’t have to choose. Let’s make one of each!
RSA Signing Subkey
1
gpg --edit-key {primary key id}
This will launch you into a gpg
command prompt that looks like this:
1
2
3
4
5
6
7
8
9
10
Secret key is available.
sec rsa4096/FCB1C79A7216CD97
created: 2024-01-11 expires: never usage: SC
trust: ultimate validity: ultimate
ssb rsa4096/C1E932AAAE361CD6
created: 2024-01-11 expires: never usage: E
[ultimate] (1). Fake McFakerton <me@fake.com>
gpg>
From here you will be entering commands in the gpg
prompt to create your subkeys. I’ve annotated it so you can see my selections.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
gpg> addkey <------------------------------ Command to add key
Please select what kind of key you want:
(3) DSA (sign only)
(4) RSA (sign only)
(5) Elgamal (encrypt only)
(6) RSA (encrypt only)
(14) Existing key from card
Your selection? 4 <------------------------ RSA signing key
RSA keys may be between 1024 and 4096 bits long.
What keysize do you want? (3072) 4096 <---- 4096 bit key size
Requested keysize is 4096 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) 2y <---------------- 2 year expiration
Key expires at Sun Jan 11 05:22:30 2026 UTC
Is this correct? (y/N) y
Really create? (y/N) y
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, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.
sec rsa4096/FCB1C79A7216CD97
created: 2024-01-11 expires: never usage: SC
trust: ultimate validity: ultimate
ssb rsa4096/C1E932AAAE361CD6
created: 2024-01-11 expires: never usage: E
ssb rsa4096/184C04B07DD988A5
created: 2024-01-12 expires: 2026-01-11 usage: S <------- Our new RSA key
[ultimate] (1). Fake McFakerton <me@fake.com>
gpg> save <------------------ DON'T FORGET TO SAVE THE CHANGES
During the creation process you will be prompted to enter your Primary Key passphrase to create the subkey. Enter the passphrase you created while generating your Primary Key.
Notice above that we have an additional ssb (secret subkey) entry which indicates it is RSA 4096, expires on January 11th 2026 (two years from now) and has the (S)igning capability. Perfect!
ECC Signing Subkey
To create an ECC signing key we need to add the --expert
parameter when we launch gpg
. This allows the ECC option to show in the menu of key options.
1
gpg --expert --edit-key {primary key id}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
gpg> addkey <------------------------------ Command to add key
Please select what kind of key you want:
(3) DSA (sign only)
(4) RSA (sign only)
(5) Elgamal (encrypt only)
(6) RSA (encrypt only)
(7) DSA (set your own capabilities)
(8) RSA (set your own capabilities)
(10) ECC (sign only)
(11) ECC (set your own capabilities)
(12) ECC (encrypt only)
(13) Existing key
(14) Existing key from card
Your selection? 10 <----------------------- ECC signing only
Please select which elliptic curve you want:
(1) Curve 25519
(3) NIST P-256
(4) NIST P-384
(5) NIST P-521
(6) Brainpool P-256
(7) Brainpool P-384
(8) Brainpool P-512
(9) secp256k1
Your selection? 1 <------------------------ Curve 25519 is fast and secure
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) 2y <----------------- 2 year expiration
Key expires at Sun Jan 11 05:32:21 2026 UTC
Is this correct? (y/N) y
Really create? (y/N) y
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, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.
sec rsa4096/FCB1C79A7216CD97
created: 2024-01-11 expires: never usage: SC
trust: ultimate validity: ultimate
ssb rsa4096/C1E932AAAE361CD6
created: 2024-01-11 expires: never usage: E
ssb rsa4096/184C04B07DD988A5
created: 2024-01-12 expires: 2026-01-11 usage: S
ssb ed25519/0AD26FEE266F3076
created: 2024-01-12 expires: 2026-01-11 usage: S <---- Our new ECC key
[ultimate] (1). Fake McFakerton <me@fake.com>
gpg> save <------------------- Don't forget to save your changes
We created the ECC signing key in mostly the same manner. We just change a few options. We’re going to use this subkey later on for signing Git commits. Git supports ECC and the smaller sizes are nice for saving on bandwidth.
You’ll notice at the bottom of the output we now have 2 signing keys. One RSA, and one ECC (ed25519). For the ECC subkey we chose the Curve 25519 elliptic curve which provides 128 bit encryption strength and is good enough for our intended primary use of signing Git commits.1
Create Authentication Subkey
The last type of key we need to create is an authentication subkey which we’ll use for things like SSH. At this point you should be getting familiar with the drill. We open our key for editing in gpg, run addkey
and select some options. So let’s do it.
1
gpg --expert --edit-key {primary key id}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
gpg> addkey <------------------------------- Command to add key
Please select what kind of key you want:
(3) DSA (sign only)
(4) RSA (sign only)
(5) Elgamal (encrypt only)
(6) RSA (encrypt only)
(7) DSA (set your own capabilities)
(8) RSA (set your own capabilities)
(10) ECC (sign only)
(11) ECC (set your own capabilities)
(12) ECC (encrypt only)
(13) Existing key
(14) Existing key from card
Your selection? 8 <------------------------ RSA where we set the capabilities
Possible actions for a RSA key: Sign Encrypt Authenticate
Current allowed actions: Sign Encrypt
(S) Toggle the sign capability
(E) Toggle the encrypt capability
(A) Toggle the authenticate capability
(Q) Finished
Your selection? A <------------------------ Turn on Authentication
Possible actions for a RSA key: Sign Encrypt Authenticate
Current allowed actions: Sign Encrypt Authenticate
(S) Toggle the sign capability
(E) Toggle the encrypt capability
(A) Toggle the authenticate capability
(Q) Finished
Your selection? S <------------------------ Turn off Signing
Possible actions for a RSA key: Sign Encrypt Authenticate
Current allowed actions: Encrypt Authenticate
(S) Toggle the sign capability
(E) Toggle the encrypt capability
(A) Toggle the authenticate capability
(Q) Finished
Your selection? E <------------------------ Turn off Encryption
Possible actions for a RSA key: Sign Encrypt Authenticate
Current allowed actions: Authenticate
(S) Toggle the sign capability
(E) Toggle the encrypt capability
(A) Toggle the authenticate capability
(Q) Finished
Your selection? Q <------------------------ Finished setting capabilities
RSA keys may be between 1024 and 4096 bits long.
What keysize do you want? (3072) 4096 <---- Key size of 4096
Requested keysize is 4096 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) 2y <----------------- 2 year expiration
Key expires at Sun Jan 11 06:00:54 2026 UTC
Is this correct? (y/N) y
Really create? (y/N) y
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, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.
sec rsa4096/FCB1C79A7216CD97
created: 2024-01-11 expires: never usage: SC
trust: ultimate validity: ultimate
ssb rsa4096/C1E932AAAE361CD6
created: 2024-01-11 expires: never usage: E
ssb rsa4096/184C04B07DD988A5
created: 2024-01-12 expires: 2026-01-11 usage: S
ssb ed25519/0AD26FEE266F3076
created: 2024-01-12 expires: 2026-01-11 usage: S
ssb rsa4096/586B09EBFAA4A68A
created: 2024-01-12 expires: 2026-01-11 usage: A <------ Our new subkey
[ultimate] (1). Fake McFakerton <me@fake.com>
gpg> save
The trickiest part about creating the authentication key is toggling the capabilities off. If you’re unsure, examine the output above carefully. We want our authentication subkey to have only the A usage.
Time for a Break
You’ve earned it. While key creation may seem daunting at first I hope now you feel a little more comfortable with it. At this point we have a robust, secure, baseline identity with subkeys for signing, encrypting/decrypting, and authentication. We’re almost ready to start using them. But before we do that we need to make sure they are backed up properly and securely. That’s what we’ll cover next in the series.
References
NIST SP 800-186 contains NIST recommendations for choosing elliptic curves. While Curve 25519 is not recommend for general use it is acknowledged in the document as “included for implementation flexibility” and is good enough for my intended usage of signing Github commits quickly and efficiently ↩
Comments powered by Disqus.