ASYMMETRIC-KEY(7)

πŸ’– ASYMMETRIC-KEY(7) πŸ’–

okay so bestie, sit down, hydrate, because we're talking about asymmetric β€” the Asymmetric Kernel Key Type β€” and it's genuinely one of the coolest things in the kernel keyring world. it's a manual page, section 7, so it's all about the concept, not a command. slay. let's go. πŸ¦‹


✨ NAME ✨

asymmetric β€” the kernel key type for holding asymmetric keys. periodt.


🌸 OVERVIEW 🌸

A kernel key of asymmetric type is basically a handle to an asymmetric key, the kind you use for public-key cryptography. The actual key material might be chillin' inside the kernel, or it might live in hardware with the operations being offloaded somewhere else. Either way? you do not get direct user access to the cryptographic material. it's giving locked door, and the door is staying locked. πŸ”’

Keys can be any asymmetric type β€” RSA, ECDSA, ... β€” and they can have both private and public components present, or just the public component. it's flexible like that. πŸ’…

Asymmetric keys get used by both the kernel and userspace, no cap:

  • the kernel can use them for stuff like module signature verification and kexec image verification
  • userspace gets a whole set of keyctl(KEYCTL_PKEY_*) calls for querying and using the key β€” and those are wrapped by libkeyutils as functions named keyctl_pkey_*()

You can load an asymmetric-type key with the keyctl utility using a command line like:

openssl x509 -in key.x509 -outform DER |
keyctl padd asymmetric foo @s

obsessed, honestly. 🌈


πŸŽ€ DESCRIPTION πŸŽ€

Think of the asymmetric-type key as a container made up of a bunch of components. here's the tour:

Parsers

The asymmetric key parsers try to figure out what's inside the payload blob and pull useful data out of it so they can instantiate the key. Key detail (literally): the parser is only used when adding, instantiating or updating a key, and it isn't associated with the key after that. one-time gig, no strings. πŸ™ˆ

Available parsers include ones that can deal with:

  • DER-encoded X.509
  • DER-encoded PKCS#8
  • DER-encoded TPM-wrapped blobs

Public and private keys

These are the cryptographic components of the key pair. The public half should always be available, but the private half might not be. 😭 You can query what operations are available, and you can query the size of the key. Also β€” plot twist β€” the key material may or may not actually reside in the kernel. it's giving mysterious. ✨

Identifiers

On top of the normal key description (which the parser can generate for you), there may be a bunch of supplementary identifiers you can search for. Where do they come from? things like hashing the public key material, or the subjectKeyIdentifier from an X.509 certificate. πŸ’«

Identifier-based searches are selected by passing a string to keyctl_search() as the description, constructed of hex characters prefixed with either "id:" or "ex:".

  • "id:" β€” a partial tail match is permissible
  • "ex:" β€” requires an exact match on the full string

and the hex characters indicate the data to match. iykyk. 🫢

Subtype

This is the driver inside the kernel that accesses the key material and performs operations on it. It might be entirely software-based, or it might offload the operations to a hardware key store, such as a TPM. main character energy for the TPM, honestly. πŸ‘‘

⚠️ Note that expiry times from the payload are ignored, because these patches may be used during boot before the system clock is set. so don't come for the expiry dates, they're not doing anything. πŸ’€

⭐ PARSERS ⭐

The asymmetric key parsers can handle keys in a number of forms:

X.509

DER-encoded X.509 certificates can be accepted. Two identifiers are constructed:

  • one from the certificate issuer and serial number
  • the other from the subjectKeyIdentifier, if present

If left blank, the key description will be filled in from the subject field plus either the subjectKeyIdentifier or the serialNumber. Only the public key is filled in, and only the encrypt and verify operations are supported.

The signature on the X.509 certificate may be checked by the keyring it's being added to β€” and it may also be rejected if the key is blacklisted. 🚫

PKCS#8

Unencrypted DER-encoded PKCS#8 key data containers can be accepted. Currently no identifiers are constructed. The private key and the public key are loaded from the PKCS#8 blobs. Encrypted PKCS#8 is not currently supported. πŸ™…β™€οΈ

TPM-Wrapped keys

DER-encoded TPM-wrapped TSS key blobs can be accepted. Currently no identifiers are constructed. The public key is extracted from the blob, but the private key is expected to be resident in the TPM. Encryption and signature verification is done in software, but decryption and signing are offloaded to the TPM so as not to expose the private key. iconic behaviour. πŸ”₯

This parser only supports:

  • TPM-1.2 wrappings
  • enc=pkcs1 encoding type

It also uses a hard-coded null SRK password β€” password-protected SRKs are not yet supported. sorry bestie, that's just where we're at. 😭


πŸ’… USERSPACE API πŸ’…

In addition to the standard keyutils library functions, such as keyctl_update(), there are five calls specific to the asymmetric key type (though they are open to being used by other key types also):

  • keyctl_pkey_query()
  • keyctl_pkey_encrypt()
  • keyctl_pkey_decrypt()
  • keyctl_pkey_sign()
  • keyctl_pkey_verify()

The query function can be used to retrieve information about an asymmetric key β€” like the key size, the amount of space required by buffers for the other operations, and which operations are actually supported. it's the info desk of this whole situation. 🧚

The other operations form two pairs:

  1. encrypt / decrypt
  2. create / verify signature

Not all of these operations will necessarily be available. Typically:

  • encrypt and verify only require the public key to be available
  • decrypt and sign require the private key as well

All of these operations take an information string parameter that supplies additional info like encoding type/form and the password(s) needed to unlock/unwrap the key. It takes the form of a comma-separated list of "key[=value]" pairs β€” and the exact set depends on the subtype driver used by a particular key. πŸ’–

Available parameters include:

  • enc=<type> β€” the encoding type for use in an encrypted blob or a signature. An example might be "enc=pkcs1".
  • hash=<name> β€” the name of the hash algorithm that was used to digest the data to be signed. Note that this is only used to construct any encoding that is used in a signature. The data to be signed or verified must have been parsed by the caller and the hash passed to keyctl_pkey_sign() or keyctl_pkey_verify() beforehand. An example might be "hash=sha256".
πŸ’­ Note that not all parameters are used by all subtypes.

πŸ¦‹ RESTRICTED KEYRINGS πŸ¦‹

There's another keyutils function, keyctl_restrict_keyring(), that can gate a keyring so that a new key can only be added to the affected keyring if:

  1. it's an asymmetric key
  2. it's validly signed by a key in some appropriate keyring
  3. it's not blacklisted

like a velvet rope but for keys. πŸŽ€

keyctl_restrict_keyring(keyring, "asymmetric",
                        "key_or_keyring:<signing-key>[:chain]");

Where <signing-key> is the ID of a key or a ring of keys that act as the authority to permit a new key to be added to the keyring. The chain flag indicates that keys that have been added to the keyring may also be used to verify new keys. Authorising keys must themselves be asymmetric-type keys that can be used to do a signature verification on the key being added. no shortcuts. πŸ’…

⚠️ Note that there are various system keyrings visible to the root user that may permit additional keys to be added. These are typically gated by keys that already exist, which prevents unauthorised keys from being used for things such as module verification. important!! 🌸

πŸ’€ BLACKLISTING πŸ’€

When an attempt is made to add a key to the kernel, a hash of the public key is checked against the blacklist. This is a system keyring named .blacklist and it contains keys of type blacklist. If the blacklist contains a key whose description matches the hash of the new key, that new key will be rejected with error EKEYREJECTED. rejected, blocked, not today. 🚫

The blacklist keyring may be loaded from multiple sources, including:

  • a list compiled into the kernel
  • the UEFI dbx variable

Further hashes may also be blacklisted by the administrator. But here's the catch bestie: blacklisting is not retroactive β€” so an asymmetric key that is already on the system cannot be blacklisted by adding a matching blacklist entry later. it's giving "you had to be there." 😭


🌟 VERSIONS 🌟

History lesson, but make it cute:

  • the asymmetric key type first appeared in v3.7 of the Linux kernel
  • the restriction function arrived in v4.11
  • the public key operations showed up in v4.20

glow-up timeline fr fr. ✨


πŸ‘‘ SEE ALSO πŸ‘‘


that's the whole page, bestie, you ate it. πŸ’– this was written for Linux, dated 8 Nov 2018, and it's the ASYMMETRIC-KEY(7) page β€” go forth and verify some signatures. mwah. πŸ’…πŸŽ€πŸ¦‹

πŸ“¦ where this page comes from