From 2ceeb96db51a36ce0ee04db09dce41f144208f7a Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Fri, 18 Nov 2016 15:01:18 +0100 Subject: [PATCH] vici: Add command to load a private key from a token PINs are stored in a "hidden" credential set, so that its shared secrets are not exposed via VICI. Since they are not explicitly loaded as shared secrets via VICI a client might consider them as removed secrets and remove them. --- src/libcharon/plugins/vici/README.md | 18 +++++ src/libcharon/plugins/vici/vici_cred.c | 102 ++++++++++++++++++++++++- 2 files changed, 117 insertions(+), 3 deletions(-) diff --git a/src/libcharon/plugins/vici/README.md b/src/libcharon/plugins/vici/README.md index 5c29ed361..556d05e32 100644 --- a/src/libcharon/plugins/vici/README.md +++ b/src/libcharon/plugins/vici/README.md @@ -491,6 +491,24 @@ including keys found in other backends. ] } +### load-token() ### + +Load a private key located on a token into the daemon. Such keys may be listed +and unloaded using the _get-keys_ and _unload-key_ commands, respectively (based +on the key identifier derived from the public key). + + { + handle = + slot = + module = + pin = + } => { + success = + errmsg = + id = + } + ### load-shared() ### Load a shared IKE PSK, EAP or XAuth secret into the daemon. diff --git a/src/libcharon/plugins/vici/vici_cred.c b/src/libcharon/plugins/vici/vici_cred.c index c8d71138c..6c7c194c2 100644 --- a/src/libcharon/plugins/vici/vici_cred.c +++ b/src/libcharon/plugins/vici/vici_cred.c @@ -56,6 +56,11 @@ struct private_vici_cred_t { */ mem_cred_t *creds; + /** + * separate credential set for token PINs + */ + mem_cred_t *pins; + /** * cache CRLs to disk? */ @@ -255,7 +260,7 @@ CALLBACK(unload_key, vici_message_t*, private_vici_cred_t *this, char *name, u_int id, vici_message_t *message) { chunk_t keyid; - char *hex, *msg = NULL; + char buf[BUF_LEN], *hex, *msg = NULL; hex = message->get_str(message, NULL, "id"); if (!hex) @@ -263,8 +268,13 @@ CALLBACK(unload_key, vici_message_t*, return create_reply("key id missing"); } keyid = chunk_from_hex(chunk_from_str(hex), NULL); - DBG1(DBG_CFG, "unloaded private key with id %+B", &keyid); - if (!this->creds->remove_key(this->creds, keyid)) + snprintf(buf, sizeof(buf), "%+B", &keyid); + DBG1(DBG_CFG, "unloaded private key with id %s", buf); + if (this->creds->remove_key(this->creds, keyid)) + { /* also remove any potential PIN associated with this id */ + this->pins->remove_shared_unique(this->pins, buf); + } + else { msg = "key not found"; } @@ -298,6 +308,87 @@ CALLBACK(get_keys, vici_message_t*, return builder->finalize(builder); } +CALLBACK(load_token, vici_message_t*, + private_vici_cred_t *this, char *name, u_int id, vici_message_t *message) +{ + vici_builder_t *builder; + private_key_t *key; + shared_key_t *shared = NULL; + identification_t *owner; + mem_cred_t *set = NULL; + chunk_t handle, fp; + char buf[BUF_LEN], *hex, *module, *pin, *unique = NULL; + int slot; + + hex = message->get_str(message, NULL, "handle"); + if (!hex) + { + return create_reply("keyid missing"); + } + handle = chunk_from_hex(chunk_from_str(hex), NULL); + slot = message->get_int(message, -1, "slot"); + module = message->get_str(message, NULL, "module"); + pin = message->get_str(message, NULL, "pin"); + + if (pin) + { /* provide the pin in a temporary credential set to access the key */ + shared = shared_key_create(SHARED_PIN, chunk_clone(chunk_from_str(pin))); + owner = identification_create_from_encoding(ID_KEY_ID, handle); + set = mem_cred_create(); + set->add_shared(set, shared->get_ref(shared), owner, NULL); + lib->credmgr->add_local_set(lib->credmgr, &set->set, FALSE); + } + if (slot >= 0) + { + key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_ANY, + BUILD_PKCS11_KEYID, handle, + BUILD_PKCS11_SLOT, slot, + module ? BUILD_PKCS11_MODULE : BUILD_END, module, + BUILD_END); + } + else + { + key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_ANY, + BUILD_PKCS11_KEYID, handle, + module ? BUILD_PKCS11_MODULE : BUILD_END, module, + BUILD_END); + } + if (set) + { + lib->credmgr->remove_local_set(lib->credmgr, &set->set); + set->destroy(set); + } + if (!key) + { + chunk_free(&handle); + DESTROY_IF(shared); + return create_reply("loading private key from token failed"); + } + builder = vici_builder_create(); + builder->add_kv(builder, "success", "yes"); + if (key->get_fingerprint(key, KEYID_PUBKEY_SHA1, &fp)) + { + snprintf(buf, sizeof(buf), "%+B", &fp); + builder->add_kv(builder, "id", "%s", buf); + unique = buf; + } + if (shared && unique) + { /* use the handle as owner, but the key identifier as unique ID */ + owner = identification_create_from_encoding(ID_KEY_ID, handle); + this->pins->add_shared_unique(this->pins, unique, shared, + linked_list_create_with_items(owner, NULL)); + } + else + { + DESTROY_IF(shared); + } + DBG1(DBG_CFG, "loaded %N private key from token", key_type_names, + key->get_type(key)); + this->creds->add_key(this->creds, key); + chunk_free(&handle); + return builder->finalize(builder); +} + CALLBACK(shared_owners, bool, linked_list_t *owners, vici_message_t *message, char *name, chunk_t value) { @@ -474,6 +565,7 @@ static void manage_commands(private_vici_cred_t *this, bool reg) manage_command(this, "load-key", load_key, reg); manage_command(this, "unload-key", unload_key, reg); manage_command(this, "get-keys", get_keys, reg); + manage_command(this, "load-token", load_token, reg); manage_command(this, "load-shared", load_shared, reg); manage_command(this, "unload-shared", unload_shared, reg); manage_command(this, "get-shared", get_shared, reg); @@ -492,6 +584,8 @@ METHOD(vici_cred_t, destroy, void, lib->credmgr->remove_set(lib->credmgr, &this->creds->set); this->creds->destroy(this->creds); + lib->credmgr->remove_set(lib->credmgr, &this->pins->set); + this->pins->destroy(this->pins); free(this); } @@ -516,6 +610,7 @@ vici_cred_t *vici_cred_create(vici_dispatcher_t *dispatcher) }, .dispatcher = dispatcher, .creds = mem_cred_create(), + .pins = mem_cred_create(), ); if (lib->settings->get_bool(lib->settings, "%s.cache_crls", FALSE, lib->ns)) @@ -524,6 +619,7 @@ vici_cred_t *vici_cred_create(vici_dispatcher_t *dispatcher) DBG1(DBG_CFG, "crl caching to %s enabled", CRL_DIR); } lib->credmgr->add_set(lib->credmgr, &this->creds->set); + lib->credmgr->add_set(lib->credmgr, &this->pins->set); manage_commands(this, TRUE);