1220922Spjd/*- 2220922Spjd * Copyright (c) 2011 Pawel Jakub Dawidek <pawel@dawidek.net> 3220922Spjd * All rights reserved. 4220922Spjd * 5220922Spjd * Redistribution and use in source and binary forms, with or without 6220922Spjd * modification, are permitted provided that the following conditions 7220922Spjd * are met: 8220922Spjd * 1. Redistributions of source code must retain the above copyright 9220922Spjd * notice, this list of conditions and the following disclaimer. 10220922Spjd * 2. Redistributions in binary form must reproduce the above copyright 11220922Spjd * notice, this list of conditions and the following disclaimer in the 12220922Spjd * documentation and/or other materials provided with the distribution. 13220922Spjd * 14220922Spjd * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 15220922Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16220922Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17220922Spjd * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 18220922Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19220922Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20220922Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21220922Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22220922Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23220922Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24220922Spjd * SUCH DAMAGE. 25220922Spjd */ 26220922Spjd 27220922Spjd#include <sys/cdefs.h> 28220922Spjd__FBSDID("$FreeBSD: releng/10.3/sys/geom/eli/g_eli_key_cache.c 239184 2012-08-10 18:43:29Z pjd $"); 29220922Spjd 30220922Spjd#include <sys/param.h> 31220922Spjd#include <sys/kernel.h> 32220922Spjd#include <sys/malloc.h> 33220922Spjd#include <sys/queue.h> 34220922Spjd#include <sys/sysctl.h> 35220922Spjd#include <sys/systm.h> 36220922Spjd#include <sys/tree.h> 37220922Spjd 38220922Spjd#include <geom/geom.h> 39220922Spjd 40220922Spjd#include <geom/eli/g_eli.h> 41220922Spjd 42220922SpjdMALLOC_DECLARE(M_ELI); 43220922Spjd 44220922SpjdSYSCTL_DECL(_kern_geom_eli); 45220922Spjd/* 46220922Spjd * The default limit (8192 keys) will allow to cache all keys for 4TB 47220922Spjd * provider with 512 bytes sectors and will take around 1MB of memory. 48220922Spjd */ 49220922Spjdstatic u_int g_eli_key_cache_limit = 8192; 50220922SpjdTUNABLE_INT("kern.geom.eli.key_cache_limit", &g_eli_key_cache_limit); 51220922SpjdSYSCTL_UINT(_kern_geom_eli, OID_AUTO, key_cache_limit, CTLFLAG_RDTUN, 52220922Spjd &g_eli_key_cache_limit, 0, "Maximum number of encryption keys to cache"); 53220922Spjdstatic uint64_t g_eli_key_cache_hits; 54220922SpjdSYSCTL_UQUAD(_kern_geom_eli, OID_AUTO, key_cache_hits, CTLFLAG_RW, 55220922Spjd &g_eli_key_cache_hits, 0, "Key cache hits"); 56220922Spjdstatic uint64_t g_eli_key_cache_misses; 57220922SpjdSYSCTL_UQUAD(_kern_geom_eli, OID_AUTO, key_cache_misses, CTLFLAG_RW, 58220922Spjd &g_eli_key_cache_misses, 0, "Key cache misses"); 59220922Spjd 60221624Spjd#define G_ELI_KEY_MAGIC 0xe11341c 61221624Spjd 62220922Spjdstruct g_eli_key { 63220922Spjd /* Key value, must be first in the structure. */ 64220922Spjd uint8_t gek_key[G_ELI_DATAKEYLEN]; 65221624Spjd /* Magic. */ 66221624Spjd int gek_magic; 67220922Spjd /* Key number. */ 68220922Spjd uint64_t gek_keyno; 69220922Spjd /* Reference counter. */ 70220922Spjd int gek_count; 71220922Spjd /* Keeps keys sorted by most recent use. */ 72220922Spjd TAILQ_ENTRY(g_eli_key) gek_next; 73220922Spjd /* Keeps keys sorted by number. */ 74220922Spjd RB_ENTRY(g_eli_key) gek_link; 75220922Spjd}; 76220922Spjd 77220922Spjdstatic int 78220922Spjdg_eli_key_cmp(const struct g_eli_key *a, const struct g_eli_key *b) 79220922Spjd{ 80220922Spjd 81220922Spjd if (a->gek_keyno > b->gek_keyno) 82220922Spjd return (1); 83220922Spjd else if (a->gek_keyno < b->gek_keyno) 84220922Spjd return (-1); 85220922Spjd return (0); 86220922Spjd} 87220922Spjd 88220922SpjdRB_PROTOTYPE(g_eli_key_tree, g_eli_key, gek_link, g_eli_key_cmp); 89220922SpjdRB_GENERATE(g_eli_key_tree, g_eli_key, gek_link, g_eli_key_cmp); 90220922Spjd 91220922Spjdstatic void 92220922Spjdg_eli_key_fill(struct g_eli_softc *sc, struct g_eli_key *key, uint64_t keyno) 93220922Spjd{ 94238116Spjd const uint8_t *ekey; 95220922Spjd struct { 96220922Spjd char magic[4]; 97220922Spjd uint8_t keyno[8]; 98220922Spjd } __packed hmacdata; 99220922Spjd 100238116Spjd if ((sc->sc_flags & G_ELI_FLAG_ENC_IVKEY) != 0) 101238116Spjd ekey = sc->sc_mkey; 102238116Spjd else 103238116Spjd ekey = sc->sc_ekey; 104238116Spjd 105220922Spjd bcopy("ekey", hmacdata.magic, 4); 106220922Spjd le64enc(hmacdata.keyno, keyno); 107238116Spjd g_eli_crypto_hmac(ekey, G_ELI_MAXKEYLEN, (uint8_t *)&hmacdata, 108220922Spjd sizeof(hmacdata), key->gek_key, 0); 109220922Spjd key->gek_keyno = keyno; 110220922Spjd key->gek_count = 0; 111221624Spjd key->gek_magic = G_ELI_KEY_MAGIC; 112220922Spjd} 113220922Spjd 114220922Spjdstatic struct g_eli_key * 115220922Spjdg_eli_key_allocate(struct g_eli_softc *sc, uint64_t keyno) 116220922Spjd{ 117220922Spjd struct g_eli_key *key, *ekey, keysearch; 118220922Spjd 119220922Spjd mtx_assert(&sc->sc_ekeys_lock, MA_OWNED); 120220922Spjd mtx_unlock(&sc->sc_ekeys_lock); 121220922Spjd 122220922Spjd key = malloc(sizeof(*key), M_ELI, M_WAITOK); 123220922Spjd g_eli_key_fill(sc, key, keyno); 124220922Spjd 125220922Spjd mtx_lock(&sc->sc_ekeys_lock); 126220922Spjd /* 127220922Spjd * Recheck if the key wasn't added while we weren't holding the lock. 128220922Spjd */ 129220922Spjd keysearch.gek_keyno = keyno; 130220922Spjd ekey = RB_FIND(g_eli_key_tree, &sc->sc_ekeys_tree, &keysearch); 131220922Spjd if (ekey != NULL) { 132220922Spjd bzero(key, sizeof(*key)); 133221953Strociny free(key, M_ELI); 134220922Spjd key = ekey; 135220922Spjd TAILQ_REMOVE(&sc->sc_ekeys_queue, key, gek_next); 136220922Spjd } else { 137220922Spjd RB_INSERT(g_eli_key_tree, &sc->sc_ekeys_tree, key); 138220922Spjd sc->sc_ekeys_allocated++; 139220922Spjd } 140220922Spjd TAILQ_INSERT_TAIL(&sc->sc_ekeys_queue, key, gek_next); 141220922Spjd 142220922Spjd return (key); 143220922Spjd} 144220922Spjd 145220922Spjdstatic struct g_eli_key * 146220922Spjdg_eli_key_find_last(struct g_eli_softc *sc) 147220922Spjd{ 148220922Spjd struct g_eli_key *key; 149220922Spjd 150220922Spjd mtx_assert(&sc->sc_ekeys_lock, MA_OWNED); 151220922Spjd 152220922Spjd TAILQ_FOREACH(key, &sc->sc_ekeys_queue, gek_next) { 153220922Spjd if (key->gek_count == 0) 154220922Spjd break; 155220922Spjd } 156220922Spjd 157220922Spjd return (key); 158220922Spjd} 159220922Spjd 160220922Spjdstatic void 161220922Spjdg_eli_key_replace(struct g_eli_softc *sc, struct g_eli_key *key, uint64_t keyno) 162220922Spjd{ 163220922Spjd 164220922Spjd mtx_assert(&sc->sc_ekeys_lock, MA_OWNED); 165221624Spjd KASSERT(key->gek_magic == G_ELI_KEY_MAGIC, ("Invalid magic.")); 166220922Spjd 167220922Spjd RB_REMOVE(g_eli_key_tree, &sc->sc_ekeys_tree, key); 168220922Spjd TAILQ_REMOVE(&sc->sc_ekeys_queue, key, gek_next); 169220922Spjd 170220922Spjd KASSERT(key->gek_count == 0, ("gek_count=%d", key->gek_count)); 171220922Spjd 172220922Spjd g_eli_key_fill(sc, key, keyno); 173220922Spjd 174220922Spjd RB_INSERT(g_eli_key_tree, &sc->sc_ekeys_tree, key); 175220922Spjd TAILQ_INSERT_TAIL(&sc->sc_ekeys_queue, key, gek_next); 176220922Spjd} 177220922Spjd 178220922Spjdstatic void 179220922Spjdg_eli_key_remove(struct g_eli_softc *sc, struct g_eli_key *key) 180220922Spjd{ 181220922Spjd 182220922Spjd mtx_assert(&sc->sc_ekeys_lock, MA_OWNED); 183221624Spjd KASSERT(key->gek_magic == G_ELI_KEY_MAGIC, ("Invalid magic.")); 184220922Spjd KASSERT(key->gek_count == 0, ("gek_count=%d", key->gek_count)); 185220922Spjd 186220922Spjd RB_REMOVE(g_eli_key_tree, &sc->sc_ekeys_tree, key); 187220922Spjd TAILQ_REMOVE(&sc->sc_ekeys_queue, key, gek_next); 188220922Spjd sc->sc_ekeys_allocated--; 189220922Spjd bzero(key, sizeof(*key)); 190220922Spjd free(key, M_ELI); 191220922Spjd} 192220922Spjd 193220922Spjdvoid 194220922Spjdg_eli_key_init(struct g_eli_softc *sc) 195220922Spjd{ 196239184Spjd uint8_t *mkey; 197220922Spjd 198220922Spjd mtx_lock(&sc->sc_ekeys_lock); 199220922Spjd 200239184Spjd mkey = sc->sc_mkey + sizeof(sc->sc_ivkey); 201239184Spjd if ((sc->sc_flags & G_ELI_FLAG_AUTH) == 0) 202239184Spjd bcopy(mkey, sc->sc_ekey, G_ELI_DATAKEYLEN); 203239184Spjd else { 204239184Spjd /* 205239184Spjd * The encryption key is: ekey = HMAC_SHA512(Data-Key, 0x10) 206239184Spjd */ 207239184Spjd g_eli_crypto_hmac(mkey, G_ELI_MAXKEYLEN, "\x10", 1, 208239184Spjd sc->sc_ekey, 0); 209239184Spjd } 210220922Spjd 211239184Spjd if ((sc->sc_flags & G_ELI_FLAG_SINGLE_KEY) != 0) { 212220922Spjd sc->sc_ekeys_total = 1; 213220922Spjd sc->sc_ekeys_allocated = 0; 214220922Spjd } else { 215220922Spjd off_t mediasize; 216220922Spjd size_t blocksize; 217220922Spjd 218220922Spjd if ((sc->sc_flags & G_ELI_FLAG_AUTH) != 0) { 219220922Spjd struct g_provider *pp; 220220922Spjd 221220922Spjd pp = LIST_FIRST(&sc->sc_geom->consumer)->provider; 222220922Spjd mediasize = pp->mediasize; 223220922Spjd blocksize = pp->sectorsize; 224220922Spjd } else { 225220922Spjd mediasize = sc->sc_mediasize; 226220922Spjd blocksize = sc->sc_sectorsize; 227220922Spjd } 228220922Spjd sc->sc_ekeys_total = 229220922Spjd ((mediasize - 1) >> G_ELI_KEY_SHIFT) / blocksize + 1; 230220922Spjd sc->sc_ekeys_allocated = 0; 231220922Spjd TAILQ_INIT(&sc->sc_ekeys_queue); 232220922Spjd RB_INIT(&sc->sc_ekeys_tree); 233220923Spjd if (sc->sc_ekeys_total <= g_eli_key_cache_limit) { 234220923Spjd uint64_t keyno; 235220923Spjd 236220923Spjd for (keyno = 0; keyno < sc->sc_ekeys_total; keyno++) 237220923Spjd (void)g_eli_key_allocate(sc, keyno); 238220923Spjd KASSERT(sc->sc_ekeys_total == sc->sc_ekeys_allocated, 239220923Spjd ("sc_ekeys_total=%ju != sc_ekeys_allocated=%ju", 240220923Spjd (uintmax_t)sc->sc_ekeys_total, 241220923Spjd (uintmax_t)sc->sc_ekeys_allocated)); 242220923Spjd } 243220922Spjd } 244239184Spjd 245220922Spjd mtx_unlock(&sc->sc_ekeys_lock); 246220922Spjd} 247220922Spjd 248220922Spjdvoid 249220922Spjdg_eli_key_destroy(struct g_eli_softc *sc) 250220922Spjd{ 251220922Spjd 252220922Spjd mtx_lock(&sc->sc_ekeys_lock); 253220922Spjd if ((sc->sc_flags & G_ELI_FLAG_SINGLE_KEY) != 0) { 254220922Spjd bzero(sc->sc_ekey, sizeof(sc->sc_ekey)); 255220922Spjd } else { 256220922Spjd struct g_eli_key *key; 257220922Spjd 258220922Spjd while ((key = TAILQ_FIRST(&sc->sc_ekeys_queue)) != NULL) 259220922Spjd g_eli_key_remove(sc, key); 260220922Spjd TAILQ_INIT(&sc->sc_ekeys_queue); 261220922Spjd RB_INIT(&sc->sc_ekeys_tree); 262220922Spjd } 263220922Spjd mtx_unlock(&sc->sc_ekeys_lock); 264220922Spjd} 265220922Spjd 266220922Spjd/* 267220922Spjd * Select encryption key. If G_ELI_FLAG_SINGLE_KEY is present we only have one 268220922Spjd * key available for all the data. If the flag is not present select the key 269220922Spjd * based on data offset. 270220922Spjd */ 271220922Spjduint8_t * 272220922Spjdg_eli_key_hold(struct g_eli_softc *sc, off_t offset, size_t blocksize) 273220922Spjd{ 274220922Spjd struct g_eli_key *key, keysearch; 275220922Spjd uint64_t keyno; 276220922Spjd 277220922Spjd if ((sc->sc_flags & G_ELI_FLAG_SINGLE_KEY) != 0) 278220922Spjd return (sc->sc_ekey); 279220922Spjd 280220922Spjd /* We switch key every 2^G_ELI_KEY_SHIFT blocks. */ 281220922Spjd keyno = (offset >> G_ELI_KEY_SHIFT) / blocksize; 282220922Spjd 283220922Spjd KASSERT(keyno < sc->sc_ekeys_total, 284220922Spjd ("%s: keyno=%ju >= sc_ekeys_total=%ju", 285220922Spjd __func__, (uintmax_t)keyno, (uintmax_t)sc->sc_ekeys_total)); 286220922Spjd 287220922Spjd keysearch.gek_keyno = keyno; 288220922Spjd 289220923Spjd if (sc->sc_ekeys_total == sc->sc_ekeys_allocated) { 290220923Spjd /* We have all the keys, so avoid some overhead. */ 291220923Spjd key = RB_FIND(g_eli_key_tree, &sc->sc_ekeys_tree, &keysearch); 292220923Spjd KASSERT(key != NULL, ("No key %ju found.", (uintmax_t)keyno)); 293221624Spjd KASSERT(key->gek_magic == G_ELI_KEY_MAGIC, 294221624Spjd ("Invalid key magic.")); 295220923Spjd return (key->gek_key); 296220923Spjd } 297220923Spjd 298220922Spjd mtx_lock(&sc->sc_ekeys_lock); 299220922Spjd key = RB_FIND(g_eli_key_tree, &sc->sc_ekeys_tree, &keysearch); 300220922Spjd if (key != NULL) { 301220922Spjd g_eli_key_cache_hits++; 302220922Spjd TAILQ_REMOVE(&sc->sc_ekeys_queue, key, gek_next); 303220922Spjd TAILQ_INSERT_TAIL(&sc->sc_ekeys_queue, key, gek_next); 304220922Spjd } else { 305220922Spjd /* 306220922Spjd * No key in cache, find the least recently unreferenced key 307220922Spjd * or allocate one if we haven't reached our limit yet. 308220922Spjd */ 309220922Spjd if (sc->sc_ekeys_allocated < g_eli_key_cache_limit) { 310220922Spjd key = g_eli_key_allocate(sc, keyno); 311220922Spjd } else { 312220922Spjd g_eli_key_cache_misses++; 313220922Spjd key = g_eli_key_find_last(sc); 314220922Spjd if (key != NULL) { 315220922Spjd g_eli_key_replace(sc, key, keyno); 316220922Spjd } else { 317220922Spjd /* All keys are referenced? Allocate one. */ 318220922Spjd key = g_eli_key_allocate(sc, keyno); 319220922Spjd } 320220922Spjd } 321220922Spjd } 322220922Spjd key->gek_count++; 323220922Spjd mtx_unlock(&sc->sc_ekeys_lock); 324220922Spjd 325221624Spjd KASSERT(key->gek_magic == G_ELI_KEY_MAGIC, ("Invalid key magic.")); 326221624Spjd 327220922Spjd return (key->gek_key); 328220922Spjd} 329220922Spjd 330220922Spjdvoid 331220922Spjdg_eli_key_drop(struct g_eli_softc *sc, uint8_t *rawkey) 332220922Spjd{ 333220922Spjd struct g_eli_key *key = (struct g_eli_key *)rawkey; 334220922Spjd 335220922Spjd if ((sc->sc_flags & G_ELI_FLAG_SINGLE_KEY) != 0) 336220922Spjd return; 337220922Spjd 338221624Spjd KASSERT(key->gek_magic == G_ELI_KEY_MAGIC, ("Invalid key magic.")); 339221624Spjd 340220923Spjd if (sc->sc_ekeys_total == sc->sc_ekeys_allocated) 341220923Spjd return; 342220923Spjd 343220922Spjd mtx_lock(&sc->sc_ekeys_lock); 344220922Spjd KASSERT(key->gek_count > 0, ("key->gek_count=%d", key->gek_count)); 345220922Spjd key->gek_count--; 346220922Spjd while (sc->sc_ekeys_allocated > g_eli_key_cache_limit) { 347220922Spjd key = g_eli_key_find_last(sc); 348220922Spjd if (key == NULL) 349220922Spjd break; 350220922Spjd g_eli_key_remove(sc, key); 351220922Spjd } 352220922Spjd mtx_unlock(&sc->sc_ekeys_lock); 353220922Spjd} 354