WIP: Loadable plugins support for both libcryptsetup and cryptsetup cli

Ondrej Kozina requested to merge oniko/cryptsetup:wip-tpm2 into wip-luks2

Hi all,

I'll start with short recapitulation:

All the work in current wip-luks2 branch + this merge request was initiated by original request to merge TPM2 support by Andreas. We (upstream) didn't want to add HW dependency (of any kind) in cryptsetup project directly, but the use case for TPM2 was clearly significant. After endless discussions and few U-turns later we settled on following API for it to get TPM2 support in cryptsetup project (LUKS2 format only). This should also pave the way for future LUKS2 extensions.

In the end we circled back to (dlopen) loadable plugins support. In fact we plan to support two different types of loadable plugins:

First, libcryptsetup plugin:

It gets loaded automatically during activation and LUKS2 dump.

Whenever activation by token takes place (crypt_activate_by_token()). Libcryptsetup searches system library directory for libcryptsetup-token-.so plugin of selected token (or all in LUKS2 metadata). The is read from LUKS2 token json specification. If it's found library calls in plugin specific crypt_token_open_func or crypt_token_open_pin_func. See crypt_token_handler in libcryptsetup.h for this type of plugin.

(Analogously for LUKS2 crypt_dump() we load libcryptsetup-token... for every LUKS2 token json specified and call in crypt_token_dump_func).

Second type, cryptsetup cli plugin:

Here be dragons! If we support libcryptsetup plugins for tokens we should also provide way to create such plugin managed tokens. Again, after endless discussions we settled on loadable plugins again.

a) We can not maintain dozens of stand alone binaries in cryptsetup project used by (max) units of percents of cryptsetup userbase. We don't have capacity for it in usptream. b) If done right it gives opportunity to anybody to create (and maintain :)) new token plugin.

How it works for cryptsetup token add action (current draft should be visible in this MR):

Unlike libcryptsetup plugins cryptsetup (cli) plugins are not loaded automatically. User needs to request plugin to be loaded explicitly via --plugin argument for token action.

The plugin is supposed to expose list of command line arguments expected from user (see crypt_token_params() in libcryptsetup-token-tpm2.c), plugin specific crypt_token_handle_init() and crypt_token_handle_free(), crypt_token_create(), crypt_token_remove() and validation functions for create and remove cl arguments.

When plugin gets loaded in cryptsetup, cryptsetup first adjusts its internal list of command line arguments according to list exposed in crypt_token_params(). It'll do very basic validation (type based) and later invoke:

crypt_token_hadnle_init() where it'll pass handle to internal context (struct crypt_cli *ctx). The context can be used by plugin to read state and values of all arguments referenced via crypt_token_params() (it can define completely new arguments prefixed with --plugin--<new_arg> or reference existing (core) cryptsetup arguments e.g. --key-slot, --token-id or --cipher.)

Those functions to get cli arguments state and value are:

bool crypt_cli_arg_set(struct crypt_cli *ctx, const char *name);
int crypt_cli_arg_value(struct crypt_cli *ctx, const char *name, void *value);
int crypt_cli_arg_type(struct crypt_cli *ctx, const char *name, crypt_arg_type_info *type);

It's part of new libcryptsetup_cli sub-library (2.4.0 will be probably big release). That library will be used currently by all cryptsetup tools and future plugins should use it mainly for functions above. Plus it exposes other common code for tools like crypt_cli_get_key() for (non)interactive passphrase prompt.

After cryptsetup calls in crypt_token_validate_create_params() if defined. Plugin is expected to validate cl arguments syntax or whether all necessary arguments are specified without need to modify any data yet.

If it passes cryptsetup calls in crypt_token_create() where plugin is supposed to do all the work and create LUKS2 token json.

Token remove action works likewise.

There's a lot to do before final release yet:

  • documentation
  • code polishing
  • API cleanups
  • better --help output with --plugin specified (and loaded)

But I think I have enough code ready so I would like to kindly ask from all interested:

Please look at code in tokens/tpm2/libcryptsetup-token-tpm2.c and following routines in src/cryptsetup.c:

int plugin_load(const char *type, struct poptOption *plugin_options, bool quiet);
int token_plugin_add(void);

That's basically "cryptsetup token add --plugin " code path.

What I would like to hear is if it makes sense to you (at least from high level perspective) and if you think it's viable for tpm2 use case and eventual future plugins.

I'm aware that proper documentation would work better but that's all I have right now and If the code is not easy to understand in current form it would serve me as feedback as well.

Kind regards and many thanks for being patient with me (specially to Andreas). Continuous work from home almost all 2020 so far is not the most comfortable situation for me and others involved.


PS: Actually the most work has been done in wip-luks2 branch but I don't think it's interesting from tpm2 plugin perspective. It's just work that had to be done before we can start merging plugins support.

Merge request reports