diff --git a/lib/libcryptsetup.h b/lib/libcryptsetup.h index 4f4031fc..50656568 100644 --- a/lib/libcryptsetup.h +++ b/lib/libcryptsetup.h @@ -899,6 +899,43 @@ int crypt_resume_by_volume_key(struct crypt_device *cd, const char *name, const char *volume_key, size_t volume_key_size); +/** + * Resume crypt device using LUKS2 token. + * + * @param cd LUKS2 crypt device handle + * @param name name of device to resume + * @param type restrict type of token, if @e NULL all types are allowed + * @param pin passphrase (or PIN) to unlock token (may be binary data) + * @param pin_size size of @e pin + * @param usrptr provided identification in callback + * + * @return unlocked key slot number or negative errno otherwise. + * + * @note EPERM errno means token provided passphrase successfully, but + * passphrase did not unlock any keyslot associated with the token. + * + * @note ENOENT errno means no token (or subsequently assigned keyslot) was + * eligible to resume LUKS2 device. + * + * @note ENOANO errno means that token is PIN protected and was either missing + * (NULL) or wrong. + * + * @note Negative EAGAIN errno means token handler requires additional hardware + * not present in the system to unlock keyslot. + * + * @note with @param token set to CRYPT_ANY_TOKEN libcryptsetup runs best effort loop + * to resume device using any available token. It may happen that various token handlers + * return different error codes. At the end loop returns error codes in the following + * order (from the most significant to the least) any negative errno except those + * listed below, non negative token id (success), -ENOANO, -EAGAIN, -EPERM, -ENOENT. + */ +int crypt_resume_by_token_pin(struct crypt_device *cd, + const char *name, + const char *type, + int token, + const char *pin, + size_t pin_size, + void *usrptr); /** @} */ /** diff --git a/lib/libcryptsetup.sym b/lib/libcryptsetup.sym index 29407c6b..b845967e 100644 --- a/lib/libcryptsetup.sym +++ b/lib/libcryptsetup.sym @@ -149,4 +149,5 @@ CRYPTSETUP_2.5 { global: crypt_get_label; crypt_get_subsystem; + crypt_resume_by_token_pin; } CRYPTSETUP_2.4; diff --git a/lib/setup.c b/lib/setup.c index c91f4fcd..d55b0f70 100644 --- a/lib/setup.c +++ b/lib/setup.c @@ -3401,6 +3401,40 @@ int crypt_resume_by_volume_key(struct crypt_device *cd, return r; } +int crypt_resume_by_token_pin(struct crypt_device *cd, const char *name, + const char *type, int token, const char *pin, size_t pin_size, + void *usrptr) +{ + struct volume_key *vk = NULL; + int r, keyslot; + + if (!name) + return -EINVAL; + + log_dbg(cd, "Resuming volume %s by token (%s type) %d.", + name, type ?: "any", token); + + if ((r = _onlyLUKS2(cd, CRYPT_CD_QUIET, 0))) + return r; + + r = dm_status_suspended(cd, name); + if (r < 0) + return r; + + if (!r) { + log_err(cd, _("Volume %s is not suspended."), name); + return -EINVAL; + } + + r = LUKS2_token_unlock_volume_key(cd, &cd->u.luks2.hdr, token, type, pin, pin_size, 0, usrptr, &vk); + keyslot = r; + if (r >= 0) + r = resume_by_volume_key(cd, vk, name); + + crypt_free_volume_key(vk); + return r < 0 ? r : keyslot; +} + /* * Keyslot manipulation */ diff --git a/tests/api-test-2.c b/tests/api-test-2.c index 32e6c368..fbeea1bb 100644 --- a/tests/api-test-2.c +++ b/tests/api-test-2.c @@ -1910,6 +1910,7 @@ static void Tokens(void) const char *cipher_mode = "xts-plain64"; char passptr[] = PASSPHRASE; char passptr1[] = PASSPHRASE1; + struct crypt_active_device cad; static const crypt_token_handler th = { .name = "test_token", @@ -2121,6 +2122,13 @@ static void Tokens(void) EQ_(crypt_activate_by_token_pin(cd, NULL, "test_token", 11, NULL, 0, passptr, 0), -ENOENT); EQ_(crypt_activate_by_token_pin(cd, NULL, "test_token", 11, NULL, 0, passptr, CRYPT_ACTIVATE_ALLOW_UNBOUND_KEY), -ENOENT); + // test crypt_resume_by_token_pin + EQ_(crypt_activate_by_token_pin(cd, CDEVICE_1, "test_token", CRYPT_ANY_TOKEN, NULL, 0, passptr, 0), 5); + OK_(crypt_suspend(cd, CDEVICE_1)); + EQ_(crypt_resume_by_token_pin(cd, CDEVICE_1, "test_token", CRYPT_ANY_TOKEN, NULL, 0, passptr), 5); + OK_(crypt_get_active_device(cd, CDEVICE_1, &cad)); + EQ_(0, cad.flags & CRYPT_ACTIVATE_SUSPENDED); + OK_(crypt_deactivate(cd, CDEVICE_1)); CRYPT_FREE(cd); EQ_(crypt_token_max(CRYPT_LUKS2), 32);