P11KMIP(1)

πŸ“¦
version 3.27.0 Β· 3 versions
, in centos-stream 10, centos-stream 9, fedora 44, opensuse-leap 16.0, ubuntu stonking

🌸 P11KMIP 🌸

okay bestie, you found it: p11kmip from the openCryptoki family, manual page section 1. it's the lil tool that shuttles your crypto keys back and forth between PKCS #11 land and KMIP land. let's get into it πŸ’…


✨ NAME ✨

p11kmip β€” Transfer cryptographic keys between PKCS #11 and KMIP.


πŸ¦‹ SYNOPSIS πŸ¦‹

p11kmip command [OPTIONS]

p11kmip --help|-h
p11kmip --version|-v

πŸ’– DESCRIPTION πŸ’–

so the p11kmip tool is what you use to move target keys between a PKCS #11 key repository and a KMIP server. those target keys can go either way β€” imported or exported β€” and while they're in transit they get wrapped using public-key cryptography. and plot twist: the keys you use for wrapping can also be sent and received. 🌈

now the limits, bestie, and listen closely:

  • only AES keys are supported as target keys
  • only RSA is supported for key wrapping

that's the vibe. no cap.


πŸ” KMIP CLIENT AUTHENTICATION πŸ”

KMIP checks who you are using the client certificate that gets exchanged during the TLS handshake. so basically, the client must generate a private RSA or EC key and a client certificate. that client certificate then has to be registered with the KMIP server.

and here's the thing β€” that registration is a KMIP server product-specific out-of-band process, and it is not described here. not our department, sorry bestie πŸ™ˆ

your client certificate can be either a self-signed certificate or a CA-signed certificate. but for real, in a production environment: use a CA-signed certificate. periodt.

⚠️ the client private key is what identifies you to the KMIP server, so it has to stay secret. if an attacker steals it, they can identify themselves at the KMIP server and get access to all the keys stored there. like, all of them. protect that thing. πŸ”₯

πŸŽ€ USING A CLEAR CLIENT KEY πŸŽ€

you can generate the client private key with OpenSSL command line tools. in that case your private key is a clear key living in a PEM file. and for security reasons β€” bestie, please β€” store the client private key in a password-protected PEM file.

here's the glow-up recipe for a password-protected client key plus a self-signed certificate, using OpenSSL commands:

openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 \
                -out '/path_to_client_key/client.key' -pass stdin \
                -aes-256-cbc

if you'd rather generate an EC key instead, use -algorithm EC and -pkeyopt ec_paramgen_curve:<curve-name>. ✨

then create a self-signed certificate with the client key you just made, like this:

openssl req -x509 -key '/path_to_client_key/client.key' \
            -out '/path_to_client_certificate/selfsigned_client.crt' \
            -nodes -days 3650 \
            -subj '/CN=www.mydom.com/O=My Company Name LTD./C=US'

when you're using a password-protected client key PEM file, you get prompted for the PEM password. you also get prompted for further information for the certificate you're creating β€” unless you supplied all those details via the OpenSSL config file. for the deets, go read the man page of the openssl req command. iykyk πŸ“–

and if you want a CA-signed certificate instead? just omit the -x509 option. then the command generates a certificate signing request instead, which you hand off to the CA. with that request, you let the CA sign the certificate and issue a CA-signed certificate for you. slay. πŸ‘‘


🧚 USING AN HSM-PROTECTED CLIENT KEY 🧚

a more secure way to protect the client private key is to generate and store it inside a PKCS#11 token. if you use a secure key token β€” like a CCA or EP11 token β€” then the client private key is HSM protected and literally cannot be stolen. iconic.

this requires a PKCS#11 OpenSSL provider (with OpenSSL 3.0.0 or later), that is, the pkcs11-provider from https://github.com/latchset/pkcs11-provider. the PKCS#11 provider has to be installed and configured properly so it can access openCryptoki. use an OpenSSL configuration file similar to this one:

[openssl_init]
providers = provider_sect

[provider_sect]
default = default_sect
pkcs11 = pkcs11_sect

[default_sect]
activate = 1

[pkcs11_sect]
pkcs11-module-path = /path/to/libopencryptoki.so
activate = 1

generate an RSA client key pair in a PKCS#11 token:

p11sak generate-key rsa 2048 --label '<name-of-client-key>' --slot <n>

and if you want to generate an EC key instead, use:

p11sak generate-key EC <curve-name> --label '<name-of-client-key>' --slot <n>

then export the private client key as a URI-PEM file. a URI-PEM file contains a PKCS#11 URI referencing the key in the PKCS#11 token, but no key material. by default, the PKCS#11 URI does not contain the PKCS#11 user PIN. check the man page of p11sak(1) and the --uri-pem option for details on how to include the PKCS#11 user PIN or a PIN source into the URI. πŸ”

p11sak export-key --label '<name-of-client.key>:prv' --uri-pem \
                  --file '/path_to_client_key/client.key' \
                  --slot <n>>

with that private client key as a URI-PEM file, you can create a self-signed certificate using this OpenSSL command:

openssl req -x509 -key '/path_to_client_key/client.key' \
            -out '/path_to_client_certificate/selfsigned_client.crt' \
            -nodes -days 3650 \
            -subj '/CN=www.mydom.com/O=My Company Name LTD./C=US'

you'll be prompted for the PKCS#11 user PIN, unless the user PIN is already contained in the PKCS#11 URI. you'll also get prompted for further information for the certificate you're creating, unless those details came from the OpenSSL config file. again, the man page of the openssl req command has all of that. 🫢

want a CA-signed certificate instead? same deal β€” omit the -x509 option, and the command generates a certificate signing request instead, which you pass to the CA. with this request, you let the CA sign the certificate and issue a CA-signed certificate for you.

instead of using a URI-PEM file, you can also use the PKCS#11 URI directly. use the p11sak list-key command with the --long option to display the PKCS#11 URI of the client private key object. then specify this URI as-is at the -key option of the openssl req command from above:

openssl req -x509 -key 'pkcs11:....;type=private' \
            -out '/path_to_client_certificate/selfsigned_client.crt' \
            -nodes -days 3650 \
            -subj '/CN=www.mydom.com/O=My Company Name LTD./C=US'

in this case, there's no need to export the client private key as a URI-PEM file. one less step, we love to see it. πŸ’…


πŸ’œ USING THE CLIENT KEY AND CERTIFICATE WITH P11KMIP πŸ’œ

use the private client key as a URI-PEM ('/path_to_client_key/client.key') or as a PKCS#11 URI ('pkcs11:....;type=private'), together with the client certificate ('/path_to_client_certificate/selfsigned_client.crt'), with the p11kmip commands described below. πŸ¦‹

you can hand over the client key and client certificate in three ways:

  1. using the options --kmip-client-key and --kmip-client-cert
  2. in the /etc/opencryptoki/p11kmip.conf configuration file
  3. via environment variables

when you use a URI-PEM file, or a password-protected PEM file, as the client key, then you get prompted for the PKCS#11 user PIN or the PEM password when the p11kmip tool reads the client key PEM file β€” unless the PEM password is specified using the --pem-password option. the prompt looks like this:

Please enter PEM password for '/path_to_client_key/client.key':
🌸 heads up: the prompt message is the same when you're using a URI-PEM file, and it's actually prompting for the PKCS#11 user PIN. for a URI-PEM file, the PEM password is the PKCS#11 user PIN required to access the PKCS#11 token that holds the key the URI is pointing at.

and if you specify a PKCS#11 URI directly as the client private key, then you get explicitly prompted for the PKCS#11 user PIN for the URI you specified. straightforward, bestie. ✨


pssst… there's more. keep scrolling, part 2 incoming 🌈

πŸ’… COMMANDS πŸ’…

The p11kmip tool is literally built to import and export keys between a PKCS #11 token repository and a KMIP server. It's giving secure key courier, no cap. πŸ’–


πŸŽ€ Importing target keys πŸŽ€

p11kmip import-key|import|imp --targkey-label|-t TARGKEY-LABEL
--wrapkey-label|-w WRAPKEY-LABEL [--unwrapkey-label|-u UNWRAPKEY-LABEL]
[--send-wrapkey] [--targkey-attrs TARGKEY-ATTRS] [--targkey-id ID]
[--gen-targkey] [--targkey-length LENGTH] [OPTIONS]

Use the import-key command to import a target key located on a KMIP server to a PKCS #11 token repository. Importing a key from a KMIP server requires a wrapping key present on the server with its corresponding unwrapping key present in a local PKCS #11 token repository. Currently RSA is supported for wrapping and unwrapping keys and AES is supported for target keys. πŸ”₯

  • --targkey-label|-t TARGKEY-LABEL β€” specifies the KMIP name attribute of the target key to be imported. Once imported into the PKCS #11 token repository, the CKA_LABEL attribute of the target key will be set to the same value as TARGKEY-LABEL.
  • --wrapkey-label|-w WRAPKEY-LABEL β€” specifies the KMIP name attribute of the key to be used for wrapping. This wrapping key must already be present on the KMIP server, unless the --send-wrapkey option is specified.
  • --unwrapkey-label|-u UNWRAPKEY-LABEL β€” the imported key will be unwrapped using a corresponding unwrapping key located in the PKCS #11 token repository with a CKA_LABEL attribute value that is the same as WRAPKEY-LABEL, unless this option identifies a different private key instead.
  • --send-wrapkey β€” when specified, the --wrapkey-label|-w WRAPKEY-LABEL option will instead be used to identify a public key located in the PKCS #11 token repository, with a CKA_LABEL attribute value that is the same as specified by WRAPKEY-LABEL. This public key is sent and registered on the KMIP server with a KMIP name specified by --wrapkey-label. The public key will then be used for wrapping.
  • --targkey-attrs TARGKEY-ATTRS β€” can be used to set the boolean attributes of the imported target key (see below for detailed description of the attributes).
  • --targkey-id ID β€” may be used to set the value of the CKA_ID attribute of the target key.
  • --gen-targkey β€” when specified, the target key will first be generated on the KMIP server. In this case, the value of the --targkey-label|-t TARGKEY-LABEL option will be used as the KMIP name attribute of the generated key. Currently, only AES symmetric keys may be generated in this way.
  • --targkey-length LENGTH β€” may be used to specify the length of the generated with the --gen-targkey option, and is only valid when specified with that option. LENGTH must be one of 128, 192, or 256. The default is 256.

After the import operation has been completed successfully, information will be displayed about the keys involved. This includes the CKA_LABEL attribute values of the imported target key and wrapping key, the KMIP UID attributes of both keys, and a SHA-256 digest of the imported target key from both the KMIP server and the PKCS #11 token repository. πŸ‘‘

Example:
  Target Key
     PKCS#11 Label...TARGET_KEY_LABEL
     PKCS#11 Digest..FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
     KMIP UID........TARGET_KEY_UUID
     KMIP Digest.....AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
  Wrapping Key
     PKCS#11 Label...WRAPPING_KEY_LABEL
     KMIP UID........WRAPPING_KEY_UUID

See below for a detailed description of OPTIONS. The --help|-h option will also show the arguments and options available. ✨


πŸ¦‹ Exporting target keys πŸ¦‹

p11kmip export-key|export|exp --targkey-label|-t TARGKEY-LABEL
--wrapkey-label|-w WRAPKEY-LABEL [--retr-wrapkey] [--wrapkey-attrs
WRAPKEY-ATTRS] [--wrapkey-id ID] [OPTIONS]

Use the export-key command to export a target key located in a PKCS #11 token repository to a KMIP server. Exporting a key from a PKCS #11 slot to a KMIP server requires an unwrapping key to be present on the server with a corresponding wrapping key present in the PKCS #11 slot. Currently only RSA is supported for wrapping and unwrapping keys and AES for target keys. πŸ’«

  • --targkey-label|-t TARGKEY-LABEL β€” specifies the CKA_LABEL attribute value of the target key to be exported. Once exported to the KMIP server, the KMIP name attribute of the target key will be set to the same value as TARGKEY-LABEL.
  • --wrapkey-label|-w WRAPKEY-LABEL β€” specifies the CKA_LABEL attribute value of key to be used for wrapping the exported key. The wrapping key must already be present in the PKCS #11 token repository, unless the --retr-wrapkey option is specified.
  • --retr-wrapkey β€” when specified, the --wrapkey-label|-w WRAPKEY-LABEL option will instead be used to identify a wrapping key located on the KMIP server with a KMIP name attribute that is the same as WRAPKEY-LABEL. This wrapping key will be retrieved from the KMIP server and imported into the PKCS #11 token repository, with a CKA_LABEL attribute value of WRAPKEY-LABEL, and used to wrap the exported key.
  • --wrapkey-attrs WRAPKEY-ATTRS β€” when the wrapping key is being retrieved from the KMIP server, this option can be used to set the boolean attributes of the retrieved wrapping key (see below for detailed description of the attributes).
  • --wrapkey-id ID β€” may be used to set the value of the CKA_ID attribute of the public key.

The exported key will be unwrapped using a corresponding unwrapping key located on the KMIP server with a KMIP name attribute that is the same as WRAPKEY-LABEL. 🫢

After the export operation has been completed successfully, information will be displayed about the keys involved. This includes the CKA_LABEL attribute values of the exported target key and public key, the KMIP UID attributes of both keys, and a SHA-256 digest of the exported target key from both the KMIP server and the PKCS #11 token repository. πŸ’…

Example:
  Target Key
     PKCS#11 Label...TARGET_KEY_LABEL
     PKCS#11 Digest..FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
     KMIP UID........TARGET_KEY_UUID
     KMIP Digest.....AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
  Wrapping Key
     PKCS#11 Label...WRAPPING_KEY_LABEL
     KMIP UID........WRAPPING_KEY_UUID

See below for a detailed description of OPTIONS. The --help|-h option will also show the arguments and options available. 🌈

✨ OPTIONS ✨

  • --wrapkey-attrs-a WRAPKEY-ATTRS | --targkey-attrs-a TARGKEY-ATTRS β€” okay so for the export-key command, this is where you say which PKCS #11 boolean attributes get set on the wrapping key you're grabbing. And for import-key, it's the PKCS #11 boolean attributes that get set on the target key you're importing. πŸ’…

Heads up bestie: not every boolean attribute applies to every key type and/or command, and if it doesn't apply it just gets silently ignored. No drama, no error, just vibes.

So the way it works: an attribute becomes TRUE when you write its letter in UPPERCASE, and FALSE when you write it in lowercase. Any attribute you don't mention (except CKA_TOKEN and CKA_SENSITIVE, more on them below) gets whatever default the PKCS #11 standard says, or whatever the PKCS #11 token implementation picks when it's generating keys β€” or, if you're setting attributes on a key that already exists, it just doesn't get touched at all. πŸ™ˆ

CKA_TOKEN is always set to TRUE for imported symmetric keys, and defaults to TRUE for public keys. Why? Because session keys aren't persistent, so the moment the session that the p11kmip tool opened gets closed, they'd simply stop existing. 😭 For public keys only, you can override this by putting the uppercase or lowercase letter for the CKA_TOKEN attribute in your attribute string, whichever you want.

When you import or receive a key with the p11kmip tool, CKA_SENSITIVE defaults to TRUE for symmetric keys. But you can override that too, by specifying the uppercase or lowercase letter for the CKA_SENSITIVE attribute in the attribute string. Your call, your rules. πŸ‘‘

Note: the default for CKA_SENSITIVE is set by the p11kmip tool itself, and it might be different from the default the PKCS #11 implementation you're using would have chosen. Don't get caught out. 🫢

These are the letters that map to each CK_ATTRIBUTE:

  • H - CKA_TOKEN
  • P - CKA_PRIVATE
  • M - CKA_MODIFIABLE
  • B - CKA_COPYABLE
  • Y - CKA_DESTROYABLE
  • S - CKA_SENSITIVE
  • X - CKA_EXTRACTABLE
  • K - CKA_IBM_PROTKEY_EXTRACTABLE (IBM specific, not all tokens support this)

Want multiple attributes? Just slam the letters together with no blanks in between, like 'MlD'. Uppercase = TRUE, lowercase = FALSE. So from the example above, 'MbS' means: CKA_MODIFIABLE=TRUE, CKA_COPYABLE=FALSE, CKA_SENSITIVE=TRUE. Slay. ✨

  • --slot | -s SLOT β€” tells it which PKCS #11 token slot number to use.

You can also set the slot number with the PKCS11_SLOT_ID environment variable or the p11kmip.conf configuration file. Peep p11kmip.conf(5) for the deets on using the config file. Priority order, and this is strict: the option wins first, the environment variable is second, and the configuration file is last. If none of them are set, it's an error. πŸ’€

  • --pin | -p PIN β€” the PKCS #11 token user PIN to log in with.

Or you can hand over the token user PIN with the PKCS11_USER_PIN environment variable. If you don't specify this option and the environment variable isn't set, you'll get prompted for the PIN.

  • --force-pin-prompt β€” makes the p11kmip tool prompt for the token user PIN no matter what, even if it's been specified somewhere else. 😌
  • --kmip-host HOSTNAME β€” the hostname of the KMIP server you're connecting to.

You can also set the hostname with the KMIP_HOSTNAME environment variable or the p11kmip.conf configuration file. See p11kmip.conf(5) for more on that. Priority: option first, environment variable second, config file last. None of them set? Error. πŸ™ƒ

  • --kmip-client-cert CERT-PATH β€” a path to the TLS client certificate to use for the KMIP connection.

You can also set the client certificate path with the KMIP_CLIENT_CERT environment variable, or the p11kmip.conf configuration file. Check p11kmip.conf(5) for more about the config file. Priority again: option > environment variable > config file. Nothing set at all? Error. πŸ’…

  • --kmip-client-key KEY-PATH β€” a path to the TLS client private key to use for the KMIP connection.

You can also set the client private key path with the KMIP_CLIENT_KEY environment variable or the p11kmip.conf configuration file. See p11kmip.conf(5) for more more details about using the configuration file. Priority: option highest, environment variable second highest, config file least. When none are set, an error occurs. πŸ”₯

  • --pem-password PEM-PASSWORD β€” the password to use for the TLS client key PEM file, if it's password-protected.

You can also set the PEM password with the KMIP_PEM_PASSWORD environment variable. If both are set, the option wins. If neither is set, you get prompted for the password.

  • --force-pem-password-prompt β€” forces the p11kmip tool to prompt for the TLS client key PEM password, regardless of whether it's been specified elsewhere. πŸŽ€
  • --tls-verify-hostname β€” enforces verification of the KMIP server hostname. Stay safe out there. πŸ¦‹
  • --tls-no-verify-certificate β€” skips verification of the KMIP server TLS certificate.
bestie. be so serious rn. this one skips certificate verification. know what you're doing before you use it. 😭
  • --tls-trust-server-cert β€” does verify the KMIP server TLS certificate, but doesn't prompt you for trust of this server. (So it checks, it just doesn't ask. Different vibe from the one above.) ✨
  • --debug | -d β€” increase debug information.
  • --quiet | -q β€” suppress messages.
  • --short | -r β€” print shortened results.

Example:

SECRET_KEY_LABEL:FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
SECRET_KEY_UUID:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
  • --help | -h β€” prints help for the usage of the p11kmip tool and/or the respective command, then exits. Iconic behaviour, honestly.
  • --version | -v β€” prints the version of the p11kmip tool and then exits. πŸ‘‘

πŸ“ FILES πŸ“

/etc/opencryptoki/p11kmip.conf

This configuration file is where you stash persistent settings for p11kmip β€” both for connecting to KMIP servers and for interacting with PKCS #11 token repositories. If you want a custom file path, set the environment variable P11KMIP_DEFAULT_CONF_FILE. If that environment variable isn't set, then the global /etc/opencryptoki/p11kmip.conf config file gets read instead. And if that file isn't available, you get an error message. πŸ™ˆ


🌈 ENVIRONMENT VARIABLES 🌈

P11KMIP_DEFAULT_CONF_FILE

You can set a custom path for the p11kmip.conf config file with the environment variable P11KMIP_DEFAULT_CONF_FILE. If the environment variable isn't set, then the global /etc/opencryptoki/p11kmip.conf config file is read. If this file is unavailable, an error message is displayed. πŸ’…

PKCS11_USER_PIN

The PKCS #11 token user PIN can be specified via the environment variable PKCS11_USER_PIN. If this environment variable isn't set, and the option --pin|-p PIN isn't specified either, p11kmip will prompt for the token user PIN interactively. 🫢

PKCS11_SLOT_ID

The PKCS #11 token slot number can be specified via the environment variable PKCS11_SLOT_ID. If this environment variable isn't set, and the option --pin|-p PIN isn't specified, the value will be read from the p11kmip.conf configuration file. πŸ‘€

PKCSLIB

An alternative PKCS #11 library name can be specified with the PKCSLIB environment variable. If this environment variable isn't set, then the default PKCS #11 library libopencryptoki.so is used.

KMIP_HOSTNAME

The hostname of the KMIP server with which to connect can be specified using the KMIP_HOSTNAME environment variable. If this environment variable isn't set, and the option --kmip-host OSTNAME isn't specified, the value will be read from the p11kmip.conf configuration file.

KMIP_CLIENT_CERT

The path to the TLS client certificate to use for the KMIP connection can be specified using the KMIP_CLIENT_CERT environment variable. If this environment variable isn't set, and the option --kmip-client-cert ERT-PATH

KMIP_CLIENT_KEY

The path to the TLS client key to use for the KMIP connection can be specified using the KMIP_CLIENT_KEY environment variable. If this environment variable isn't set, and the option --kmip-client-key KEY-PATH

KMIP_PEM_PASSWORD

The PEM file used for the TLS client key may be password protected. The PEM password can be specified via the environment variable KMIP_PEM_PASSWORD. If this environment variable isn't set, and the option --pem-password EM-PASSWORD isn't specified, p11kmip will prompt for the PEM password interactively. 😌


πŸšͺ EXIT STATUS πŸšͺ

The p11kmip tool returns error codes as defined by the PKCS #11 standard β€” aka the CKR_nnn errors. On success, CKR_OK (which is zero) is returned. Zero = slay. ✨

Those PKCS #11 error codes can come from a PKCS #11 function the p11kmip tool called, or from the p11kmip tool itself. Like these:

CKR_ARGUMENTS_BAD (0x00000007):

An argument, option or keyword is not valid.

CKR_DATA_INVALID (0x00000020):

The p11kmip.conf cannot be parsed or its syntax is invalid.

CKR_MECHANISM_INVALID (0x00000070):

The token does not support the key generation mechanism for the specified key type.

CKR_KEY_SIZE_RANGE (0x00000062):

The token does not support the key size for the specified key type.

CKR_HOST_MEMORY (0x00000002):

Allocating memory has failed.

CKR_FUNCTION_FAILED (0x00000006):

A subfunction or library call has failed.


πŸ‘€ SEE ALSO πŸ‘€


and that's the whole page bestie, you're officially a p11kmip girlie now πŸ’– this was version 3.27.0, dated August 2023 β€” go forth and manage your keys, no cap. πŸŽ€βœ¨