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