"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "lib/luks2/luks2_token.c" between
cryptsetup-2.3.6.tar.xz and cryptsetup-2.4.0.tar.xz

About: cryptsetup is a utility used to conveniently setup disk encryption based on the dm-crypt kernel module. These include plain dm-crypt volumes, LUKS volumes, loop-AES and TrueCrypt compatible format.

luks2_token.c  (cryptsetup-2.3.6.tar.xz):luks2_token.c  (cryptsetup-2.4.0.tar.xz)
skipping to change at line 22 skipping to change at line 22
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/ */
#include <ctype.h>
#include <dlfcn.h>
#include <assert.h> #include <assert.h>
#include "luks2_internal.h" #include "luks2_internal.h"
/* Builtin tokens */ #if USE_EXTERNAL_TOKENS
extern const crypt_token_handler keyring_handler; static bool external_tokens_enabled = true;
#else
static bool external_tokens_enabled = false;
#endif
static token_handler token_handlers[LUKS2_TOKENS_MAX] = { static struct crypt_token_handler_internal token_handlers[LUKS2_TOKENS_MAX] = {
/* keyring builtin token */ /* keyring builtin token */
{ {
.get = token_keyring_get, .version = 1,
.set = token_keyring_set, .u = {
.h = &keyring_handler .v1 = { .name = LUKS2_TOKEN_KEYRING,
}, .open = keyring_open,
.validate = keyring_validate,
.dump = keyring_dump }
}
}
}; };
void crypt_token_external_disable(void)
{
external_tokens_enabled = false;
}
const char *crypt_token_external_path(void)
{
return external_tokens_enabled ? EXTERNAL_LUKS2_TOKENS_PATH : NULL;
}
#if USE_EXTERNAL_TOKENS
static void *token_dlvsym(struct crypt_device *cd,
void *handle,
const char *symbol,
const char *version)
{
char *error;
void *sym;
log_dbg(cd, "Loading symbol %s@%s.", symbol, version);
sym = dlvsym(handle, symbol, version);
error = dlerror();
if (error)
log_dbg(cd, "%s", error);
return sym;
}
#endif
static bool token_validate_v1(struct crypt_device *cd, const crypt_token_handler
*h)
{
if (!h)
return false;
if (!h->name) {
log_dbg(cd, "Error: token handler does not provide name attribute
.");
return false;
}
if (!h->open) {
log_dbg(cd, "Error: token handler does not provide open function.
");
return false;
}
return true;
}
#if USE_EXTERNAL_TOKENS
static bool token_validate_v2(struct crypt_device *cd, const struct crypt_token_
handler_internal *h)
{
if (!h)
return false;
if (!token_validate_v1(cd, &h->u.v1))
return false;
if (!h->u.v2.version) {
log_dbg(cd, "Error: token handler does not provide " CRYPT_TOKEN_
ABI_VERSION " function.");
return false;
}
return true;
}
static bool external_token_name_valid(const char *name)
{
if (!*name || strlen(name) > LUKS2_TOKEN_NAME_MAX)
return false;
while (*name) {
if (!isalnum(*name) && *name != '-' && *name != '_')
return false;
name++;
}
return true;
}
#endif
static int
crypt_token_load_external(struct crypt_device *cd, const char *name, struct cryp
t_token_handler_internal *ret)
{
#if USE_EXTERNAL_TOKENS
struct crypt_token_handler_v2 *token;
void *h;
char buf[PATH_MAX];
int r;
if (!external_tokens_enabled)
return -ENOTSUP;
if (!ret || !name)
return -EINVAL;
if (!external_token_name_valid(name)) {
log_dbg(cd, "External token name (%.*s) invalid.", LUKS2_TOKEN_NA
ME_MAX, name);
return -EINVAL;
}
token = &ret->u.v2;
r = snprintf(buf, sizeof(buf), "%s/libcryptsetup-token-%s.so", crypt_toke
n_external_path(), name);
if (r < 0 || (size_t)r >= sizeof(buf))
return -EINVAL;
assert(*buf == '/');
log_dbg(cd, "Trying to load %s.", buf);
h = dlopen(buf, RTLD_LAZY);
if (!h) {
log_dbg(cd, "%s", dlerror());
return -EINVAL;
}
dlerror();
token->name = strdup(name);
token->open = token_dlvsym(cd, h, CRYPT_TOKEN_ABI_OPEN, CRYPT_TOKEN_ABI_V
ERSION1);
token->buffer_free = token_dlvsym(cd, h, CRYPT_TOKEN_ABI_BUFFER_FREE, CRY
PT_TOKEN_ABI_VERSION1);
token->validate = token_dlvsym(cd, h, CRYPT_TOKEN_ABI_VALIDATE, CRYPT_TOK
EN_ABI_VERSION1);
token->dump = token_dlvsym(cd, h, CRYPT_TOKEN_ABI_DUMP, CRYPT_TOKEN_ABI_V
ERSION1);
token->open_pin = token_dlvsym(cd, h, CRYPT_TOKEN_ABI_OPEN_PIN, CRYPT_TOK
EN_ABI_VERSION1);
token->version = token_dlvsym(cd, h, CRYPT_TOKEN_ABI_VERSION, CRYPT_TOKEN
_ABI_VERSION1);
if (!token_validate_v2(cd, ret)) {
free(CONST_CAST(void *)token->name);
dlclose(h);
memset(token, 0, sizeof(*token));
return -EINVAL;
}
/* Token loaded, possible error here means only debug message fail and ca
n be ignored */
r = snprintf(buf, sizeof(buf), "%s", token->version() ?: "");
if (r < 0 || (size_t)r >= sizeof(buf))
*buf = '\0';
log_dbg(cd, "Token handler %s-%s loaded successfully.", token->name, buf)
;
token->dlhandle = h;
ret->version = 2;
return 0;
#else
return -ENOTSUP;
#endif
}
static int is_builtin_candidate(const char *type) static int is_builtin_candidate(const char *type)
{ {
return !strncmp(type, LUKS2_BUILTIN_TOKEN_PREFIX, LUKS2_BUILTIN_TOKEN_PRE FIX_LEN); return !strncmp(type, LUKS2_BUILTIN_TOKEN_PREFIX, LUKS2_BUILTIN_TOKEN_PRE FIX_LEN);
} }
int crypt_token_register(const crypt_token_handler *handler) static int crypt_token_find_free(struct crypt_device *cd, const char *name, int *index)
{ {
int i; int i;
if (is_builtin_candidate(handler->name)) { if (is_builtin_candidate(name)) {
log_dbg(NULL, "'" LUKS2_BUILTIN_TOKEN_PREFIX "' is reserved prefi log_dbg(cd, "'" LUKS2_BUILTIN_TOKEN_PREFIX "' is reserved prefix
x for builtin tokens."); for builtin tokens.");
return -EINVAL; return -EINVAL;
} }
for (i = 0; i < LUKS2_TOKENS_MAX && token_handlers[i].h; i++) { for (i = 0; i < LUKS2_TOKENS_MAX && token_handlers[i].u.v1.name; i++) {
if (!strcmp(token_handlers[i].h->name, handler->name)) { if (!strcmp(token_handlers[i].u.v1.name, name)) {
log_dbg(NULL, "Keyslot handler %s is already registered." log_dbg(cd, "Keyslot handler %s is already registered.",
, handler->name); name);
return -EINVAL; return -EINVAL;
} }
} }
if (i == LUKS2_TOKENS_MAX) if (i == LUKS2_TOKENS_MAX)
return -EINVAL; return -EINVAL;
token_handlers[i].h = handler; if (index)
*index = i;
return 0; return 0;
} }
static const token_handler int crypt_token_register(const crypt_token_handler *handler)
*LUKS2_token_handler_type_internal(struct crypt_device *cd, const char *type) {
int i, r;
if (!token_validate_v1(NULL, handler))
return -EINVAL;
r = crypt_token_find_free(NULL, handler->name, &i);
if (r < 0)
return r;
token_handlers[i].version = 1;
token_handlers[i].u.v1 = *handler;
return 0;
}
void crypt_token_unload_external_all(struct crypt_device *cd)
{ {
int i; int i;
for (i = 0; i < LUKS2_TOKENS_MAX && token_handlers[i].h; i++) for (i = LUKS2_TOKENS_MAX - 1; i >= 0; i--) {
if (!strcmp(token_handlers[i].h->name, type)) if (token_handlers[i].version < 2)
return token_handlers + i; continue;
log_dbg(cd, "Unloading %s token handler.", token_handlers[i].u.v2
.name);
return NULL; free(CONST_CAST(void *)token_handlers[i].u.v2.name);
if (dlclose(CONST_CAST(void *)token_handlers[i].u.v2.dlhandle))
log_dbg(cd, "%s", dlerror());
}
} }
static const crypt_token_handler static const void
*LUKS2_token_handler_type(struct crypt_device *cd, const char *type) *LUKS2_token_handler_type(struct crypt_device *cd, const char *type)
{ {
const token_handler *th = LUKS2_token_handler_type_internal(cd, type); int i;
for (i = 0; i < LUKS2_TOKENS_MAX && token_handlers[i].u.v1.name; i++)
if (!strcmp(token_handlers[i].u.v1.name, type))
return &token_handlers[i].u;
if (i >= LUKS2_TOKENS_MAX)
return NULL;
if (is_builtin_candidate(type))
return NULL;
if (crypt_token_load_external(cd, type, &token_handlers[i]))
return NULL;
return th ? th->h : NULL; return &token_handlers[i].u;
} }
static const token_handler static const void
*LUKS2_token_handler_internal(struct crypt_device *cd, int token) *LUKS2_token_handler(struct crypt_device *cd, int token)
{ {
struct luks2_hdr *hdr; struct luks2_hdr *hdr;
json_object *jobj1, *jobj2; json_object *jobj1, *jobj2;
if (token < 0) if (token < 0)
return NULL; return NULL;
if (!(hdr = crypt_get_hdr(cd, CRYPT_LUKS2))) if (!(hdr = crypt_get_hdr(cd, CRYPT_LUKS2)))
return NULL; return NULL;
if (!(jobj1 = LUKS2_get_token_jobj(hdr, token))) if (!(jobj1 = LUKS2_get_token_jobj(hdr, token)))
return NULL; return NULL;
if (!json_object_object_get_ex(jobj1, "type", &jobj2)) if (!json_object_object_get_ex(jobj1, "type", &jobj2))
return NULL; return NULL;
return LUKS2_token_handler_type_internal(cd, json_object_get_string(jobj2 return LUKS2_token_handler_type(cd, json_object_get_string(jobj2));
));
}
static const crypt_token_handler
*LUKS2_token_handler(struct crypt_device *cd, int token)
{
const token_handler *th = LUKS2_token_handler_internal(cd, token);
return th ? th->h : NULL;
} }
static int LUKS2_token_find_free(struct luks2_hdr *hdr) static int LUKS2_token_find_free(struct luks2_hdr *hdr)
{ {
int i; int i;
for (i = 0; i < LUKS2_TOKENS_MAX; i++) for (i = 0; i < LUKS2_TOKENS_MAX; i++)
if (!LUKS2_get_token_jobj(hdr, i)) if (!LUKS2_get_token_jobj(hdr, i))
return i; return i;
return -EINVAL; return -EINVAL;
} }
int LUKS2_token_create(struct crypt_device *cd, int LUKS2_token_create(struct crypt_device *cd,
struct luks2_hdr *hdr, struct luks2_hdr *hdr,
int token, int token,
const char *json, const char *json,
int commit) int commit)
{ {
const crypt_token_handler *h; const crypt_token_handler *h;
const token_handler *th;
json_object *jobj_tokens, *jobj_type, *jobj; json_object *jobj_tokens, *jobj_type, *jobj;
enum json_tokener_error jerr; enum json_tokener_error jerr;
char num[16]; char num[16];
if (token == CRYPT_ANY_TOKEN) { if (token == CRYPT_ANY_TOKEN) {
if (!json) if (!json)
return -EINVAL; return -EINVAL;
token = LUKS2_token_find_free(hdr); token = LUKS2_token_find_free(hdr);
} }
skipping to change at line 170 skipping to change at line 355
log_dbg(cd, "Token JSON parse failed."); log_dbg(cd, "Token JSON parse failed.");
return -EINVAL; return -EINVAL;
} }
if (LUKS2_token_validate(cd, hdr->jobj, jobj, num)) { if (LUKS2_token_validate(cd, hdr->jobj, jobj, num)) {
json_object_put(jobj); json_object_put(jobj);
return -EINVAL; return -EINVAL;
} }
json_object_object_get_ex(jobj, "type", &jobj_type); json_object_object_get_ex(jobj, "type", &jobj_type);
if (is_builtin_candidate(json_object_get_string(jobj_type))) { h = LUKS2_token_handler_type(cd, json_object_get_string(jobj_type
th = LUKS2_token_handler_type_internal(cd, json_object_ge ));
t_string(jobj_type));
if (!th || !th->set) { if (is_builtin_candidate(json_object_get_string(jobj_type)) && !h
log_dbg(cd, "%s is builtin token candidate with m ) {
issing handler", json_object_get_string(jobj_type)); log_dbg(cd, "%s is builtin token candidate with missing h
json_object_put(jobj); andler",
return -EINVAL; json_object_get_string(jobj_type));
} json_object_put(jobj);
h = th->h; return -EINVAL;
} else }
h = LUKS2_token_handler_type(cd, json_object_get_string(j
obj_type));
if (h && h->validate && h->validate(cd, json)) { if (h && h->validate && h->validate(cd, json)) {
json_object_put(jobj); json_object_put(jobj);
log_dbg(cd, "Token type %s validation failed.", h->name); log_dbg(cd, "Token type %s validation failed.", h->name);
return -EINVAL; return -EINVAL;
} }
json_object_object_add(jobj_tokens, num, jobj); json_object_object_add(jobj_tokens, num, jobj);
if (LUKS2_check_json_size(cd, hdr)) { if (LUKS2_check_json_size(cd, hdr)) {
log_dbg(cd, "Not enough space in header json area for new token."); log_dbg(cd, "Not enough space in header json area for new token.");
skipping to change at line 207 skipping to change at line 390
return token; return token;
} }
crypt_token_info LUKS2_token_status(struct crypt_device *cd, crypt_token_info LUKS2_token_status(struct crypt_device *cd,
struct luks2_hdr *hdr, struct luks2_hdr *hdr,
int token, int token,
const char **type) const char **type)
{ {
const char *tmp; const char *tmp;
const token_handler *th; const crypt_token_handler *th;
json_object *jobj_type, *jobj_token; json_object *jobj_type, *jobj_token;
if (token < 0 || token >= LUKS2_TOKENS_MAX) if (token < 0 || token >= LUKS2_TOKENS_MAX)
return CRYPT_TOKEN_INVALID; return CRYPT_TOKEN_INVALID;
if (!(jobj_token = LUKS2_get_token_jobj(hdr, token))) if (!(jobj_token = LUKS2_get_token_jobj(hdr, token)))
return CRYPT_TOKEN_INACTIVE; return CRYPT_TOKEN_INACTIVE;
json_object_object_get_ex(jobj_token, "type", &jobj_type); json_object_object_get_ex(jobj_token, "type", &jobj_type);
tmp = json_object_get_string(jobj_type); tmp = json_object_get_string(jobj_type);
if ((th = LUKS2_token_handler_type_internal(cd, tmp))) { if ((th = LUKS2_token_handler_type(cd, tmp))) {
if (type) if (type)
*type = th->h->name; *type = th->name;
return th->set ? CRYPT_TOKEN_INTERNAL : CRYPT_TOKEN_EXTERNAL; return is_builtin_candidate(tmp) ? CRYPT_TOKEN_INTERNAL : CRYPT_T
OKEN_EXTERNAL;
} }
if (type) if (type)
*type = tmp; *type = tmp;
return is_builtin_candidate(tmp) ? CRYPT_TOKEN_INTERNAL_UNKNOWN : CRYPT_T OKEN_EXTERNAL_UNKNOWN; return is_builtin_candidate(tmp) ? CRYPT_TOKEN_INTERNAL_UNKNOWN : CRYPT_T OKEN_EXTERNAL_UNKNOWN;
} }
int LUKS2_builtin_token_get(struct crypt_device *cd, static const char *token_json_to_string(json_object *jobj_token)
struct luks2_hdr *hdr,
int token,
const char *type,
void *params)
{ {
const token_handler *th = LUKS2_token_handler_type_internal(cd, type); return json_object_to_json_string_ext(jobj_token,
JSON_C_TO_STRING_PLAIN | JSON_C_TO_STRING_NOSLASHESCAPE);
// internal error
assert(th && th->get);
return th->get(LUKS2_get_token_jobj(hdr, token), params) ?: token;
} }
int LUKS2_builtin_token_create(struct crypt_device *cd, static int token_is_usable(struct luks2_hdr *hdr, json_object *jobj_token, int s
struct luks2_hdr *hdr, egment, crypt_keyslot_priority minimal_priority)
int token,
const char *type,
const void *params,
int commit)
{ {
const token_handler *th; crypt_keyslot_priority keyslot_priority;
int r; json_object *jobj_array;
json_object *jobj_token, *jobj_tokens; int i, keyslot, len, r = -ENOENT;
th = LUKS2_token_handler_type_internal(cd, type); if (!jobj_token)
return -EINVAL;
// at this point all builtin handlers must exist and have validate fn def if (!json_object_object_get_ex(jobj_token, "keyslots", &jobj_array))
ined return -EINVAL;
assert(th && th->set && th->h->validate);
if (token == CRYPT_ANY_TOKEN) { if (segment < 0 && segment != CRYPT_ANY_SEGMENT)
if ((token = LUKS2_token_find_free(hdr)) < 0)
log_err(cd, _("No free token slot."));
}
if (token < 0 || token >= LUKS2_TOKENS_MAX)
return -EINVAL; return -EINVAL;
r = th->set(&jobj_token, params); /* no assigned keyslot returns -ENOENT even for CRYPT_ANY_SEGMENT */
if (r) { len = json_object_array_length(jobj_array);
log_err(cd, _("Failed to create builtin token %s."), type); if (len <= 0)
return r; return -ENOENT;
}
// builtin tokens must produce valid json for (i = 0; i < len; i++) {
r = LUKS2_token_validate(cd, hdr->jobj, jobj_token, "new"); keyslot = atoi(json_object_get_string(json_object_array_get_idx(j
assert(!r); obj_array, i)));
r = th->h->validate(cd, json_object_to_json_string_ext(jobj_token,
JSON_C_TO_STRING_PLAIN | JSON_C_TO_STRING_NOSLASHESCAPE));
assert(!r);
json_object_object_get_ex(hdr->jobj, "tokens", &jobj_tokens); keyslot_priority = LUKS2_keyslot_priority_get(NULL, hdr, keyslot)
json_object_object_add_by_uint(jobj_tokens, token, jobj_token); ;
if (LUKS2_check_json_size(cd, hdr)) { if (keyslot_priority == CRYPT_SLOT_PRIORITY_INVALID)
log_dbg(cd, "Not enough space in header json area for new %s toke return -EINVAL;
n.", type);
json_object_object_del_by_uint(jobj_tokens, token); if (keyslot_priority < minimal_priority)
return -ENOSPC; continue;
r = LUKS2_keyslot_for_segment(hdr, keyslot, segment);
if (r != -ENOENT)
return r;
} }
if (commit) return r;
return LUKS2_hdr_write(cd, hdr) ?: token; }
return token; static int translate_errno(struct crypt_device *cd, int ret_val, const char *typ
e)
{
if ((ret_val > 0 || ret_val == -EINVAL || ret_val == -EPERM) && !is_built
in_candidate(type)) {
log_dbg(cd, "%s token handler returned %d. Changing to %d.", type
, ret_val, -ENOENT);
ret_val = -ENOENT;
}
return ret_val;
} }
static int LUKS2_token_open(struct crypt_device *cd, static int LUKS2_token_open(struct crypt_device *cd,
struct luks2_hdr *hdr, struct luks2_hdr *hdr,
int token, int token,
json_object *jobj_token,
const char *type,
int segment,
crypt_keyslot_priority priority,
const char *pin,
size_t pin_size,
char **buffer, char **buffer,
size_t *buffer_len, size_t *buffer_len,
void *usrptr) void *usrptr)
{ {
const char *json; const struct crypt_token_handler_v2 *h;
const crypt_token_handler *h; json_object *jobj_type;
int r; int r;
if (!(h = LUKS2_token_handler(cd, token))) assert(token >= 0);
return -ENOENT; assert(jobj_token);
assert(priority >= 0);
if (h->validate) { if (type) {
if (LUKS2_token_json_get(cd, hdr, token, &json)) if (!json_object_object_get_ex(jobj_token, "type", &jobj_type))
return -EINVAL; return -EINVAL;
if (strcmp(type, json_object_get_string(jobj_type)))
return -ENOENT;
}
if (h->validate(cd, json)) { r = token_is_usable(hdr, jobj_token, segment, priority);
log_dbg(cd, "Token %d (%s) validation failed.", token, h- if (r < 0) {
>name); if (r == -ENOENT)
return -EINVAL; log_dbg(cd, "Token %d unusable for segment %d with desire
} d keyslot priority %d.", token, segment, priority);
return r;
}
if (!(h = LUKS2_token_handler(cd, token)))
return -ENOENT;
if (h->validate && h->validate(cd, token_json_to_string(jobj_token))) {
log_dbg(cd, "Token %d (%s) validation failed.", token, h->name);
return -ENOENT;
} }
r = h->open(cd, token, buffer, buffer_len, usrptr); if (pin && !h->open_pin)
r = -ENOENT;
else if (pin)
r = translate_errno(cd, h->open_pin(cd, token, pin, pin_size, buf
fer, buffer_len, usrptr), h->name);
else
r = translate_errno(cd, h->open(cd, token, buffer, buffer_len, us
rptr), h->name);
if (r < 0) if (r < 0)
log_dbg(cd, "Token %d (%s) open failed with %d.", token, h->name, r); log_dbg(cd, "Token %d (%s) open failed with %d.", token, h->name, r);
return r; return r;
} }
static void LUKS2_token_buffer_free(struct crypt_device *cd, static void LUKS2_token_buffer_free(struct crypt_device *cd,
int token, int token,
void *buffer, void *buffer,
size_t buffer_len) size_t buffer_len)
skipping to change at line 341 skipping to change at line 538
const crypt_token_handler *h = LUKS2_token_handler(cd, token); const crypt_token_handler *h = LUKS2_token_handler(cd, token);
if (h && h->buffer_free) if (h && h->buffer_free)
h->buffer_free(buffer, buffer_len); h->buffer_free(buffer, buffer_len);
else { else {
crypt_safe_memzero(buffer, buffer_len); crypt_safe_memzero(buffer, buffer_len);
free(buffer); free(buffer);
} }
} }
static bool break_loop_retval(int r)
{
if (r == -ENOENT || r == -EPERM || r == -EAGAIN || r == -ENOANO)
return false;
return true;
}
static void update_return_errno(int r, int *stored)
{
if (*stored == -ENOANO)
return;
else if (r == -ENOANO)
*stored = r;
else if (r == -EAGAIN && *stored != -ENOANO)
*stored = r;
else if (r == -EPERM && (*stored != -ENOANO && *stored != -EAGAIN))
*stored = r;
}
static int LUKS2_keyslot_open_by_token(struct crypt_device *cd, static int LUKS2_keyslot_open_by_token(struct crypt_device *cd,
struct luks2_hdr *hdr, struct luks2_hdr *hdr,
int token, int token,
int segment, int segment,
crypt_keyslot_priority priority,
const char *buffer, const char *buffer,
size_t buffer_len, size_t buffer_len,
struct volume_key **vk) struct volume_key **vk)
{ {
const crypt_token_handler *h; crypt_keyslot_priority keyslot_priority;
json_object *jobj_token, *jobj_token_keyslots, *jobj; json_object *jobj_token, *jobj_token_keyslots, *jobj_type, *jobj;
unsigned int num = 0; unsigned int num = 0;
int i, r; int i, r = -ENOENT, stored_retval = -ENOENT;
if (!(h = LUKS2_token_handler(cd, token)))
return -ENOENT;
jobj_token = LUKS2_get_token_jobj(hdr, token); jobj_token = LUKS2_get_token_jobj(hdr, token);
if (!jobj_token) if (!jobj_token)
return -EINVAL; return -EINVAL;
if (!json_object_object_get_ex(jobj_token, "type", &jobj_type))
return -EINVAL;
json_object_object_get_ex(jobj_token, "keyslots", &jobj_token_keyslots); json_object_object_get_ex(jobj_token, "keyslots", &jobj_token_keyslots);
if (!jobj_token_keyslots) if (!jobj_token_keyslots)
return -EINVAL; return -EINVAL;
/* Try to open keyslot referenced in token */ /* Try to open keyslot referenced in token */
r = -EINVAL;
for (i = 0; i < (int) json_object_array_length(jobj_token_keyslots) && r < 0; i++) { for (i = 0; i < (int) json_object_array_length(jobj_token_keyslots) && r < 0; i++) {
jobj = json_object_array_get_idx(jobj_token_keyslots, i); jobj = json_object_array_get_idx(jobj_token_keyslots, i);
num = atoi(json_object_get_string(jobj)); num = atoi(json_object_get_string(jobj));
log_dbg(cd, "Trying to open keyslot %u with token %d (type %s).", keyslot_priority = LUKS2_keyslot_priority_get(NULL, hdr, num);
num, token, h->name); if (keyslot_priority == CRYPT_SLOT_PRIORITY_INVALID)
return -EINVAL;
if (keyslot_priority < priority)
continue;
log_dbg(cd, "Trying to open keyslot %u with token %d (type %s).",
num, token, json_object_get_string(jobj_type));
r = LUKS2_keyslot_open(cd, num, segment, buffer, buffer_len, vk); r = LUKS2_keyslot_open(cd, num, segment, buffer, buffer_len, vk);
/* short circuit on fatal error */
if (r < 0 && r != -EPERM && r != -ENOENT)
return r;
/* save -EPERM in case no other keyslot is usable */
if (r == -EPERM)
stored_retval = r;
} }
if (r < 0) if (r < 0)
return r; return stored_retval;
return num; return num;
} }
int LUKS2_token_open_and_activate(struct crypt_device *cd, static bool token_is_blocked(int token, uint32_t *block_list)
struct luks2_hdr *hdr,
int token,
const char *name,
uint32_t flags,
void *usrptr)
{ {
bool use_keyring; /* it is safe now, but have assert in case LUKS2_TOKENS_MAX grows */
int keyslot, r; assert(token >= 0 && (size_t)token < BITFIELD_SIZE(block_list));
char *buffer;
size_t buffer_len;
struct volume_key *vk = NULL;
r = LUKS2_token_open(cd, hdr, token, &buffer, &buffer_len, usrptr); return (*block_list & (1 << token));
if (r < 0) }
return r;
r = LUKS2_keyslot_open_by_token(cd, hdr, token, static void token_block(int token, uint32_t *block_list)
(flags & CRYPT_ACTIVATE_ALLOW_UNBOUND_KEY {
) ? /* it is safe now, but have assert in case LUKS2_TOKENS_MAX grows */
CRYPT_ANY_SEGMENT : CRYPT_DEFAULT_SEGMENT assert(token >= 0 && (size_t)token < BITFIELD_SIZE(block_list));
,
buffer, buffer_len, &vk);
LUKS2_token_buffer_free(cd, token, buffer, buffer_len); *block_list |= (1 << token);
}
if (r < 0) static int token_open_priority(struct crypt_device *cd,
return r; struct luks2_hdr *hdr,
json_object *jobj_tokens,
const char *type,
int segment,
crypt_keyslot_priority priority,
const char *pin,
size_t pin_size,
void *usrptr,
int *stored_retval,
uint32_t *block_list,
struct volume_key **vk)
{
char *buffer;
size_t buffer_size;
int token, r;
keyslot = r; assert(stored_retval);
assert(block_list);
if (!crypt_use_keyring_for_vk(cd)) json_object_object_foreach(jobj_tokens, slot, val) {
use_keyring = false; token = atoi(slot);
else if (token_is_blocked(token, block_list))
use_keyring = ((name && !crypt_is_cipher_null(crypt_get_cipher(cd continue;
))) || r = LUKS2_token_open(cd, hdr, token, val, type, segment, priority
(flags & CRYPT_ACTIVATE_KEYRING_KEY)); , pin, pin_size, &buffer, &buffer_size, usrptr);
if (!r) {
r = LUKS2_keyslot_open_by_token(cd, hdr, token, segment,
priority,
buffer, buffer_size, vk);
LUKS2_token_buffer_free(cd, token, buffer, buffer_size);
}
if (use_keyring) { if (r == -ENOANO)
if (!(r = LUKS2_volume_key_load_in_keyring_by_keyslot(cd, hdr, vk token_block(token, block_list);
, keyslot)))
flags |= CRYPT_ACTIVATE_KEYRING_KEY; if (break_loop_retval(r))
return r;
update_return_errno(r, stored_retval);
} }
if (r >= 0 && name) return *stored_retval;
r = LUKS2_activate(cd, name, vk, flags); }
if (r < 0) static int token_open_any(struct crypt_device *cd, struct luks2_hdr *hdr, const
crypt_drop_keyring_key(cd, vk); char *type, int segment, const char *pin, size_t pin_size, void *usrptr, struct
crypt_free_volume_key(vk); volume_key **vk)
{
json_object *jobj_tokens;
int r, retval = -ENOENT;
uint32_t blocked = 0; /* bitmap with tokens blocked from loop by returnin
g -ENOANO (wrong/missing pin) */
return r < 0 ? r : keyslot; json_object_object_get_ex(hdr->jobj, "tokens", &jobj_tokens);
/* passing usrptr for CRYPT_ANY_TOKEN does not make sense without specifi
c type */
if (!type)
usrptr = NULL;
r = token_open_priority(cd, hdr, jobj_tokens, type, segment, CRYPT_SLOT_P
RIORITY_PREFER, pin, pin_size, usrptr, &retval, &blocked, vk);
if (break_loop_retval(r))
return r;
return token_open_priority(cd, hdr, jobj_tokens, type, segment, CRYPT_SLO
T_PRIORITY_NORMAL, pin, pin_size, usrptr, &retval, &blocked, vk);
} }
int LUKS2_token_open_and_activate_any(struct crypt_device *cd, int LUKS2_token_open_and_activate(struct crypt_device *cd,
struct luks2_hdr *hdr, struct luks2_hdr *hdr,
int token,
const char *name, const char *name,
uint32_t flags) const char *type,
const char *pin,
size_t pin_size,
uint32_t flags,
void *usrptr)
{ {
bool use_keyring;
char *buffer; char *buffer;
json_object *tokens_jobj; size_t buffer_size;
size_t buffer_len; json_object *jobj_token;
int keyslot, token, r = -EINVAL; int keyslot, segment, r = -ENOENT;
struct volume_key *vk = NULL; struct volume_key *vk = NULL;
json_object_object_get_ex(hdr->jobj, "tokens", &tokens_jobj); if (flags & CRYPT_ACTIVATE_ALLOW_UNBOUND_KEY)
segment = CRYPT_ANY_SEGMENT;
else {
segment = LUKS2_get_default_segment(hdr);
if (segment < 0)
return -EINVAL;
}
json_object_object_foreach(tokens_jobj, slot, val) { if (token >= 0 && token < LUKS2_TOKENS_MAX) {
UNUSED(val); if ((jobj_token = LUKS2_get_token_jobj(hdr, token))) {
token = atoi(slot); r = LUKS2_token_open(cd, hdr, token, jobj_token, type, se
gment, CRYPT_SLOT_PRIORITY_IGNORE, pin, pin_size, &buffer, &buffer_size, usrptr
);
if (!r) {
r = LUKS2_keyslot_open_by_token(cd, hdr, token, s
egment, CRYPT_SLOT_PRIORITY_IGNORE,
buffer, buffer_si
ze, &vk);
LUKS2_token_buffer_free(cd, token, buffer, buffer
_size);
}
}
} else if (token == CRYPT_ANY_TOKEN)
/*
* return priorities (ordered form least to most significant):
* ENOENT - unusable for activation (no token handler, invalid to
ken metadata, not assigned to volume segment, etc)
* EPERM - usable but token provided passphrase did not not unlo
ck any assigned keyslot
* EAGAIN - usable but not ready (token HW is missing)
* ENOANO - ready, but token pin is wrong or missing
*
* success (>= 0) or any other negative errno short-circuits toke
n activation loop
* immediately
*/
r = token_open_any(cd, hdr, type, segment, pin, pin_size, usrptr,
&vk);
else
return -EINVAL;
r = LUKS2_token_open(cd, hdr, token, &buffer, &buffer_len, NULL); if (r < 0)
if (r < 0) return r;
continue;
r = LUKS2_keyslot_open_by_token(cd, hdr, token, assert(vk);
(flags & CRYPT_ACTIVATE_ALLOW_UNB
OUND_KEY) ?
CRYPT_ANY_SEGMENT : CRYPT_DEFAULT
_SEGMENT,
buffer, buffer_len, &vk);
LUKS2_token_buffer_free(cd, token, buffer, buffer_len);
if (r >= 0)
break;
}
keyslot = r; keyslot = r;
if (r >= 0 && (name || (flags & CRYPT_ACTIVATE_KEYRING_KEY)) && crypt_use if (!crypt_use_keyring_for_vk(cd))
_keyring_for_vk(cd)) { use_keyring = false;
else
use_keyring = ((name && !crypt_is_cipher_null(crypt_get_cipher(cd
))) ||
(flags & CRYPT_ACTIVATE_KEYRING_KEY));
if (use_keyring) {
if (!(r = LUKS2_volume_key_load_in_keyring_by_keyslot(cd, hdr, vk , keyslot))) if (!(r = LUKS2_volume_key_load_in_keyring_by_keyslot(cd, hdr, vk , keyslot)))
flags |= CRYPT_ACTIVATE_KEYRING_KEY; flags |= CRYPT_ACTIVATE_KEYRING_KEY;
} }
if (r >= 0 && name) if (r >= 0 && name)
r = LUKS2_activate(cd, name, vk, flags); r = LUKS2_activate(cd, name, vk, flags);
if (r < 0) if (r < 0)
crypt_drop_keyring_key(cd, vk); crypt_drop_keyring_key(cd, vk);
crypt_free_volume_key(vk); crypt_free_volume_key(vk);
skipping to change at line 491 skipping to change at line 776
h = LUKS2_token_handler(cd, token); h = LUKS2_token_handler(cd, token);
if (h && h->dump) { if (h && h->dump) {
jobj_token = LUKS2_get_token_jobj(crypt_get_hdr(cd, CRYPT_LUKS2), token); jobj_token = LUKS2_get_token_jobj(crypt_get_hdr(cd, CRYPT_LUKS2), token);
if (jobj_token) if (jobj_token)
h->dump(cd, json_object_to_json_string_ext(jobj_token, h->dump(cd, json_object_to_json_string_ext(jobj_token,
JSON_C_TO_STRING_PLAIN | JSON_C_TO_STRING_NOSLASH ESCAPE)); JSON_C_TO_STRING_PLAIN | JSON_C_TO_STRING_NOSLASH ESCAPE));
} }
} }
int LUKS2_token_json_get(struct crypt_device *cd, struct luks2_hdr *hdr, int LUKS2_token_json_get(struct crypt_device *cd __attribute__((unused)), struct luks2_hdr *hdr,
int token, const char **json) int token, const char **json)
{ {
json_object *jobj_token; json_object *jobj_token;
jobj_token = LUKS2_get_token_jobj(hdr, token); jobj_token = LUKS2_get_token_jobj(hdr, token);
if (!jobj_token) if (!jobj_token)
return -EINVAL; return -EINVAL;
*json = json_object_to_json_string_ext(jobj_token, *json = token_json_to_string(jobj_token);
JSON_C_TO_STRING_PLAIN | JSON_C_TO_STRING_NOSLASHESCAPE);
return 0; return 0;
} }
static int assign_one_keyslot(struct crypt_device *cd, struct luks2_hdr *hdr, static int assign_one_keyslot(struct crypt_device *cd, struct luks2_hdr *hdr,
int token, int keyslot, int assign) int token, int keyslot, int assign)
{ {
json_object *jobj1, *jobj_token, *jobj_token_keyslots; json_object *jobj1, *jobj_token, *jobj_token_keyslots;
char num[16]; char num[16];
log_dbg(cd, "Keyslot %i %s token %i.", keyslot, assign ? "assigned to" : "unassigned from", token); log_dbg(cd, "Keyslot %i %s token %i.", keyslot, assign ? "assigned to" : "unassigned from", token);
skipping to change at line 582 skipping to change at line 866
r = assign_one_token(cd, hdr, keyslot, atoi(key), assign) ; r = assign_one_token(cd, hdr, keyslot, atoi(key), assign) ;
if (r < 0) if (r < 0)
break; break;
} }
} else } else
r = assign_one_token(cd, hdr, keyslot, token, assign); r = assign_one_token(cd, hdr, keyslot, token, assign);
if (r < 0) if (r < 0)
return r; return r;
// FIXME: do not write header in nothing changed
if (commit) if (commit)
return LUKS2_hdr_write(cd, hdr) ?: token; return LUKS2_hdr_write(cd, hdr) ?: token;
return token; return token;
} }
static int token_is_assigned(struct luks2_hdr *hdr, int keyslot, int token) static int token_is_assigned(struct luks2_hdr *hdr, int keyslot, int token)
{ {
int i; int i;
json_object *jobj, *jobj_token_keyslots, json_object *jobj, *jobj_token_keyslots,
skipping to change at line 609 skipping to change at line 892
for (i = 0; i < (int) json_object_array_length(jobj_token_keyslots); i++) { for (i = 0; i < (int) json_object_array_length(jobj_token_keyslots); i++) {
jobj = json_object_array_get_idx(jobj_token_keyslots, i); jobj = json_object_array_get_idx(jobj_token_keyslots, i);
if (keyslot == atoi(json_object_get_string(jobj))) if (keyslot == atoi(json_object_get_string(jobj)))
return 0; return 0;
} }
return -ENOENT; return -ENOENT;
} }
int LUKS2_token_is_assigned(struct crypt_device *cd, struct luks2_hdr *hdr, int LUKS2_token_is_assigned(struct crypt_device *cd __attribute__((unused)), str uct luks2_hdr *hdr,
int keyslot, int token) int keyslot, int token)
{ {
if (keyslot < 0 || keyslot >= LUKS2_KEYSLOTS_MAX || token < 0 || token >= LUKS2_TOKENS_MAX) if (keyslot < 0 || keyslot >= LUKS2_KEYSLOTS_MAX || token < 0 || token >= LUKS2_TOKENS_MAX)
return -EINVAL; return -EINVAL;
return token_is_assigned(hdr, keyslot, token); return token_is_assigned(hdr, keyslot, token);
} }
int LUKS2_tokens_count(struct luks2_hdr *hdr) int LUKS2_tokens_count(struct luks2_hdr *hdr)
{ {
 End of changes. 76 change blocks. 
196 lines changed or deleted 513 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)