xref: /openbmc/linux/security/keys/big_key.c (revision 363b02dab09b3226f3bd1420dad9c72b79a42a76)
1ab3c3587SDavid Howells /* Large capacity key type
2ab3c3587SDavid Howells  *
3428490e3SJason A. Donenfeld  * Copyright (C) 2017 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
4ab3c3587SDavid Howells  * Copyright (C) 2013 Red Hat, Inc. All Rights Reserved.
5ab3c3587SDavid Howells  * Written by David Howells (dhowells@redhat.com)
6ab3c3587SDavid Howells  *
7ab3c3587SDavid Howells  * This program is free software; you can redistribute it and/or
8ab3c3587SDavid Howells  * modify it under the terms of the GNU General Public Licence
9ab3c3587SDavid Howells  * as published by the Free Software Foundation; either version
10ab3c3587SDavid Howells  * 2 of the Licence, or (at your option) any later version.
11ab3c3587SDavid Howells  */
12ab3c3587SDavid Howells 
137df3e59cSDavid Howells #define pr_fmt(fmt) "big_key: "fmt
14ab3c3587SDavid Howells #include <linux/init.h>
15ab3c3587SDavid Howells #include <linux/seq_file.h>
16ab3c3587SDavid Howells #include <linux/file.h>
17ab3c3587SDavid Howells #include <linux/shmem_fs.h>
18ab3c3587SDavid Howells #include <linux/err.h>
1913100a72SKirill Marinushkin #include <linux/scatterlist.h>
20428490e3SJason A. Donenfeld #include <linux/random.h>
21ab3c3587SDavid Howells #include <keys/user-type.h>
22ab3c3587SDavid Howells #include <keys/big_key-type.h>
23428490e3SJason A. Donenfeld #include <crypto/aead.h>
24ab3c3587SDavid Howells 
25ab3c3587SDavid Howells /*
26146aa8b1SDavid Howells  * Layout of key payload words.
27146aa8b1SDavid Howells  */
28146aa8b1SDavid Howells enum {
29146aa8b1SDavid Howells 	big_key_data,
30146aa8b1SDavid Howells 	big_key_path,
31146aa8b1SDavid Howells 	big_key_path_2nd_part,
32146aa8b1SDavid Howells 	big_key_len,
33146aa8b1SDavid Howells };
34146aa8b1SDavid Howells 
35146aa8b1SDavid Howells /*
3613100a72SKirill Marinushkin  * Crypto operation with big_key data
3713100a72SKirill Marinushkin  */
3813100a72SKirill Marinushkin enum big_key_op {
3913100a72SKirill Marinushkin 	BIG_KEY_ENC,
4013100a72SKirill Marinushkin 	BIG_KEY_DEC,
4113100a72SKirill Marinushkin };
4213100a72SKirill Marinushkin 
4313100a72SKirill Marinushkin /*
44ab3c3587SDavid Howells  * If the data is under this limit, there's no point creating a shm file to
45ab3c3587SDavid Howells  * hold it as the permanently resident metadata for the shmem fs will be at
46ab3c3587SDavid Howells  * least as large as the data.
47ab3c3587SDavid Howells  */
48ab3c3587SDavid Howells #define BIG_KEY_FILE_THRESHOLD (sizeof(struct inode) + sizeof(struct dentry))
49ab3c3587SDavid Howells 
50ab3c3587SDavid Howells /*
5113100a72SKirill Marinushkin  * Key size for big_key data encryption
5213100a72SKirill Marinushkin  */
53428490e3SJason A. Donenfeld #define ENC_KEY_SIZE 32
54428490e3SJason A. Donenfeld 
55428490e3SJason A. Donenfeld /*
56428490e3SJason A. Donenfeld  * Authentication tag length
57428490e3SJason A. Donenfeld  */
58428490e3SJason A. Donenfeld #define ENC_AUTHTAG_SIZE 16
5913100a72SKirill Marinushkin 
6013100a72SKirill Marinushkin /*
61ab3c3587SDavid Howells  * big_key defined keys take an arbitrary string as the description and an
62ab3c3587SDavid Howells  * arbitrary blob of data as the payload
63ab3c3587SDavid Howells  */
64ab3c3587SDavid Howells struct key_type key_type_big_key = {
65ab3c3587SDavid Howells 	.name			= "big_key",
66002edaf7SDavid Howells 	.preparse		= big_key_preparse,
67002edaf7SDavid Howells 	.free_preparse		= big_key_free_preparse,
68002edaf7SDavid Howells 	.instantiate		= generic_key_instantiate,
69ab3c3587SDavid Howells 	.revoke			= big_key_revoke,
70ab3c3587SDavid Howells 	.destroy		= big_key_destroy,
71ab3c3587SDavid Howells 	.describe		= big_key_describe,
72ab3c3587SDavid Howells 	.read			= big_key_read,
73428490e3SJason A. Donenfeld 	/* no ->update(); don't add it without changing big_key_crypt() nonce */
74ab3c3587SDavid Howells };
75ab3c3587SDavid Howells 
76ab3c3587SDavid Howells /*
77428490e3SJason A. Donenfeld  * Crypto names for big_key data authenticated encryption
7813100a72SKirill Marinushkin  */
79428490e3SJason A. Donenfeld static const char big_key_alg_name[] = "gcm(aes)";
8013100a72SKirill Marinushkin 
8113100a72SKirill Marinushkin /*
82428490e3SJason A. Donenfeld  * Crypto algorithms for big_key data authenticated encryption
8313100a72SKirill Marinushkin  */
84428490e3SJason A. Donenfeld static struct crypto_aead *big_key_aead;
8513100a72SKirill Marinushkin 
8613100a72SKirill Marinushkin /*
87428490e3SJason A. Donenfeld  * Since changing the key affects the entire object, we need a mutex.
8813100a72SKirill Marinushkin  */
89428490e3SJason A. Donenfeld static DEFINE_MUTEX(big_key_aead_lock);
9013100a72SKirill Marinushkin 
9113100a72SKirill Marinushkin /*
9213100a72SKirill Marinushkin  * Encrypt/decrypt big_key data
9313100a72SKirill Marinushkin  */
9413100a72SKirill Marinushkin static int big_key_crypt(enum big_key_op op, u8 *data, size_t datalen, u8 *key)
9513100a72SKirill Marinushkin {
96428490e3SJason A. Donenfeld 	int ret;
9713100a72SKirill Marinushkin 	struct scatterlist sgio;
98428490e3SJason A. Donenfeld 	struct aead_request *aead_req;
99428490e3SJason A. Donenfeld 	/* We always use a zero nonce. The reason we can get away with this is
100428490e3SJason A. Donenfeld 	 * because we're using a different randomly generated key for every
101428490e3SJason A. Donenfeld 	 * different encryption. Notably, too, key_type_big_key doesn't define
102428490e3SJason A. Donenfeld 	 * an .update function, so there's no chance we'll wind up reusing the
103428490e3SJason A. Donenfeld 	 * key to encrypt updated data. Simply put: one key, one encryption.
104428490e3SJason A. Donenfeld 	 */
105428490e3SJason A. Donenfeld 	u8 zero_nonce[crypto_aead_ivsize(big_key_aead)];
10613100a72SKirill Marinushkin 
107428490e3SJason A. Donenfeld 	aead_req = aead_request_alloc(big_key_aead, GFP_KERNEL);
108428490e3SJason A. Donenfeld 	if (!aead_req)
109428490e3SJason A. Donenfeld 		return -ENOMEM;
110428490e3SJason A. Donenfeld 
111428490e3SJason A. Donenfeld 	memset(zero_nonce, 0, sizeof(zero_nonce));
112428490e3SJason A. Donenfeld 	sg_init_one(&sgio, data, datalen + (op == BIG_KEY_ENC ? ENC_AUTHTAG_SIZE : 0));
113428490e3SJason A. Donenfeld 	aead_request_set_crypt(aead_req, &sgio, &sgio, datalen, zero_nonce);
114428490e3SJason A. Donenfeld 	aead_request_set_callback(aead_req, CRYPTO_TFM_REQ_MAY_SLEEP, NULL, NULL);
115428490e3SJason A. Donenfeld 	aead_request_set_ad(aead_req, 0);
116428490e3SJason A. Donenfeld 
117428490e3SJason A. Donenfeld 	mutex_lock(&big_key_aead_lock);
118428490e3SJason A. Donenfeld 	if (crypto_aead_setkey(big_key_aead, key, ENC_KEY_SIZE)) {
11913100a72SKirill Marinushkin 		ret = -EAGAIN;
12013100a72SKirill Marinushkin 		goto error;
12113100a72SKirill Marinushkin 	}
12213100a72SKirill Marinushkin 	if (op == BIG_KEY_ENC)
123428490e3SJason A. Donenfeld 		ret = crypto_aead_encrypt(aead_req);
12413100a72SKirill Marinushkin 	else
125428490e3SJason A. Donenfeld 		ret = crypto_aead_decrypt(aead_req);
12613100a72SKirill Marinushkin error:
127428490e3SJason A. Donenfeld 	mutex_unlock(&big_key_aead_lock);
128428490e3SJason A. Donenfeld 	aead_request_free(aead_req);
12913100a72SKirill Marinushkin 	return ret;
13013100a72SKirill Marinushkin }
13113100a72SKirill Marinushkin 
13213100a72SKirill Marinushkin /*
133002edaf7SDavid Howells  * Preparse a big key
134ab3c3587SDavid Howells  */
135002edaf7SDavid Howells int big_key_preparse(struct key_preparsed_payload *prep)
136ab3c3587SDavid Howells {
137146aa8b1SDavid Howells 	struct path *path = (struct path *)&prep->payload.data[big_key_path];
138ab3c3587SDavid Howells 	struct file *file;
13913100a72SKirill Marinushkin 	u8 *enckey;
14013100a72SKirill Marinushkin 	u8 *data = NULL;
141ab3c3587SDavid Howells 	ssize_t written;
142ab3c3587SDavid Howells 	size_t datalen = prep->datalen;
143ab3c3587SDavid Howells 	int ret;
144ab3c3587SDavid Howells 
145ab3c3587SDavid Howells 	ret = -EINVAL;
146ab3c3587SDavid Howells 	if (datalen <= 0 || datalen > 1024 * 1024 || !prep->data)
147ab3c3587SDavid Howells 		goto error;
148ab3c3587SDavid Howells 
149ab3c3587SDavid Howells 	/* Set an arbitrary quota */
150002edaf7SDavid Howells 	prep->quotalen = 16;
151ab3c3587SDavid Howells 
152146aa8b1SDavid Howells 	prep->payload.data[big_key_len] = (void *)(unsigned long)datalen;
153ab3c3587SDavid Howells 
154ab3c3587SDavid Howells 	if (datalen > BIG_KEY_FILE_THRESHOLD) {
155ab3c3587SDavid Howells 		/* Create a shmem file to store the data in.  This will permit the data
156ab3c3587SDavid Howells 		 * to be swapped out if needed.
157ab3c3587SDavid Howells 		 *
15813100a72SKirill Marinushkin 		 * File content is stored encrypted with randomly generated key.
159ab3c3587SDavid Howells 		 */
160428490e3SJason A. Donenfeld 		size_t enclen = datalen + ENC_AUTHTAG_SIZE;
161e13ec939SChristoph Hellwig 		loff_t pos = 0;
16213100a72SKirill Marinushkin 
16313100a72SKirill Marinushkin 		data = kmalloc(enclen, GFP_KERNEL);
16413100a72SKirill Marinushkin 		if (!data)
16513100a72SKirill Marinushkin 			return -ENOMEM;
16613100a72SKirill Marinushkin 		memcpy(data, prep->data, datalen);
16713100a72SKirill Marinushkin 
16813100a72SKirill Marinushkin 		/* generate random key */
16913100a72SKirill Marinushkin 		enckey = kmalloc(ENC_KEY_SIZE, GFP_KERNEL);
17013100a72SKirill Marinushkin 		if (!enckey) {
17113100a72SKirill Marinushkin 			ret = -ENOMEM;
172002edaf7SDavid Howells 			goto error;
173d2b86970SWei Yongjun 		}
174428490e3SJason A. Donenfeld 		ret = get_random_bytes_wait(enckey, ENC_KEY_SIZE);
175428490e3SJason A. Donenfeld 		if (unlikely(ret))
17613100a72SKirill Marinushkin 			goto err_enckey;
17713100a72SKirill Marinushkin 
17813100a72SKirill Marinushkin 		/* encrypt aligned data */
179428490e3SJason A. Donenfeld 		ret = big_key_crypt(BIG_KEY_ENC, data, datalen, enckey);
18013100a72SKirill Marinushkin 		if (ret)
18113100a72SKirill Marinushkin 			goto err_enckey;
18213100a72SKirill Marinushkin 
18313100a72SKirill Marinushkin 		/* save aligned data to file */
18413100a72SKirill Marinushkin 		file = shmem_kernel_file_setup("", enclen, 0);
18513100a72SKirill Marinushkin 		if (IS_ERR(file)) {
18613100a72SKirill Marinushkin 			ret = PTR_ERR(file);
18713100a72SKirill Marinushkin 			goto err_enckey;
18813100a72SKirill Marinushkin 		}
18913100a72SKirill Marinushkin 
190e13ec939SChristoph Hellwig 		written = kernel_write(file, data, enclen, &pos);
19113100a72SKirill Marinushkin 		if (written != enclen) {
19297826c82SDavid Howells 			ret = written;
193ab3c3587SDavid Howells 			if (written >= 0)
194ab3c3587SDavid Howells 				ret = -ENOMEM;
195ab3c3587SDavid Howells 			goto err_fput;
196ab3c3587SDavid Howells 		}
197ab3c3587SDavid Howells 
198ab3c3587SDavid Howells 		/* Pin the mount and dentry to the key so that we can open it again
199ab3c3587SDavid Howells 		 * later
200ab3c3587SDavid Howells 		 */
20113100a72SKirill Marinushkin 		prep->payload.data[big_key_data] = enckey;
202ab3c3587SDavid Howells 		*path = file->f_path;
203ab3c3587SDavid Howells 		path_get(path);
204ab3c3587SDavid Howells 		fput(file);
20591080180SJason A. Donenfeld 		kzfree(data);
206ab3c3587SDavid Howells 	} else {
207ab3c3587SDavid Howells 		/* Just store the data in a buffer */
208ab3c3587SDavid Howells 		void *data = kmalloc(datalen, GFP_KERNEL);
20913100a72SKirill Marinushkin 
210002edaf7SDavid Howells 		if (!data)
211002edaf7SDavid Howells 			return -ENOMEM;
212ab3c3587SDavid Howells 
213146aa8b1SDavid Howells 		prep->payload.data[big_key_data] = data;
214146aa8b1SDavid Howells 		memcpy(data, prep->data, prep->datalen);
215ab3c3587SDavid Howells 	}
216ab3c3587SDavid Howells 	return 0;
217ab3c3587SDavid Howells 
218ab3c3587SDavid Howells err_fput:
219ab3c3587SDavid Howells 	fput(file);
22013100a72SKirill Marinushkin err_enckey:
22191080180SJason A. Donenfeld 	kzfree(enckey);
222ab3c3587SDavid Howells error:
22391080180SJason A. Donenfeld 	kzfree(data);
224ab3c3587SDavid Howells 	return ret;
225ab3c3587SDavid Howells }
226ab3c3587SDavid Howells 
227ab3c3587SDavid Howells /*
228002edaf7SDavid Howells  * Clear preparsement.
229002edaf7SDavid Howells  */
230002edaf7SDavid Howells void big_key_free_preparse(struct key_preparsed_payload *prep)
231002edaf7SDavid Howells {
232002edaf7SDavid Howells 	if (prep->datalen > BIG_KEY_FILE_THRESHOLD) {
233146aa8b1SDavid Howells 		struct path *path = (struct path *)&prep->payload.data[big_key_path];
23413100a72SKirill Marinushkin 
235002edaf7SDavid Howells 		path_put(path);
236002edaf7SDavid Howells 	}
23791080180SJason A. Donenfeld 	kzfree(prep->payload.data[big_key_data]);
238002edaf7SDavid Howells }
239002edaf7SDavid Howells 
240002edaf7SDavid Howells /*
241ab3c3587SDavid Howells  * dispose of the links from a revoked keyring
242ab3c3587SDavid Howells  * - called with the key sem write-locked
243ab3c3587SDavid Howells  */
244ab3c3587SDavid Howells void big_key_revoke(struct key *key)
245ab3c3587SDavid Howells {
246146aa8b1SDavid Howells 	struct path *path = (struct path *)&key->payload.data[big_key_path];
247ab3c3587SDavid Howells 
248ab3c3587SDavid Howells 	/* clear the quota */
249ab3c3587SDavid Howells 	key_payload_reserve(key, 0);
250*363b02daSDavid Howells 	if (key_is_positive(key) &&
251146aa8b1SDavid Howells 	    (size_t)key->payload.data[big_key_len] > BIG_KEY_FILE_THRESHOLD)
252ab3c3587SDavid Howells 		vfs_truncate(path, 0);
253ab3c3587SDavid Howells }
254ab3c3587SDavid Howells 
255ab3c3587SDavid Howells /*
256ab3c3587SDavid Howells  * dispose of the data dangling from the corpse of a big_key key
257ab3c3587SDavid Howells  */
258ab3c3587SDavid Howells void big_key_destroy(struct key *key)
259ab3c3587SDavid Howells {
260146aa8b1SDavid Howells 	size_t datalen = (size_t)key->payload.data[big_key_len];
261146aa8b1SDavid Howells 
26213100a72SKirill Marinushkin 	if (datalen > BIG_KEY_FILE_THRESHOLD) {
263146aa8b1SDavid Howells 		struct path *path = (struct path *)&key->payload.data[big_key_path];
26413100a72SKirill Marinushkin 
265ab3c3587SDavid Howells 		path_put(path);
266ab3c3587SDavid Howells 		path->mnt = NULL;
267ab3c3587SDavid Howells 		path->dentry = NULL;
26813100a72SKirill Marinushkin 	}
26991080180SJason A. Donenfeld 	kzfree(key->payload.data[big_key_data]);
270146aa8b1SDavid Howells 	key->payload.data[big_key_data] = NULL;
271ab3c3587SDavid Howells }
272ab3c3587SDavid Howells 
273ab3c3587SDavid Howells /*
274ab3c3587SDavid Howells  * describe the big_key key
275ab3c3587SDavid Howells  */
276ab3c3587SDavid Howells void big_key_describe(const struct key *key, struct seq_file *m)
277ab3c3587SDavid Howells {
278146aa8b1SDavid Howells 	size_t datalen = (size_t)key->payload.data[big_key_len];
279ab3c3587SDavid Howells 
280ab3c3587SDavid Howells 	seq_puts(m, key->description);
281ab3c3587SDavid Howells 
282*363b02daSDavid Howells 	if (key_is_positive(key))
283146aa8b1SDavid Howells 		seq_printf(m, ": %zu [%s]",
284ab3c3587SDavid Howells 			   datalen,
285ab3c3587SDavid Howells 			   datalen > BIG_KEY_FILE_THRESHOLD ? "file" : "buff");
286ab3c3587SDavid Howells }
287ab3c3587SDavid Howells 
288ab3c3587SDavid Howells /*
289ab3c3587SDavid Howells  * read the key data
290ab3c3587SDavid Howells  * - the key's semaphore is read-locked
291ab3c3587SDavid Howells  */
292ab3c3587SDavid Howells long big_key_read(const struct key *key, char __user *buffer, size_t buflen)
293ab3c3587SDavid Howells {
294146aa8b1SDavid Howells 	size_t datalen = (size_t)key->payload.data[big_key_len];
295ab3c3587SDavid Howells 	long ret;
296ab3c3587SDavid Howells 
297ab3c3587SDavid Howells 	if (!buffer || buflen < datalen)
298ab3c3587SDavid Howells 		return datalen;
299ab3c3587SDavid Howells 
300ab3c3587SDavid Howells 	if (datalen > BIG_KEY_FILE_THRESHOLD) {
301146aa8b1SDavid Howells 		struct path *path = (struct path *)&key->payload.data[big_key_path];
302ab3c3587SDavid Howells 		struct file *file;
30313100a72SKirill Marinushkin 		u8 *data;
30413100a72SKirill Marinushkin 		u8 *enckey = (u8 *)key->payload.data[big_key_data];
305428490e3SJason A. Donenfeld 		size_t enclen = datalen + ENC_AUTHTAG_SIZE;
306bdd1d2d3SChristoph Hellwig 		loff_t pos = 0;
30713100a72SKirill Marinushkin 
30813100a72SKirill Marinushkin 		data = kmalloc(enclen, GFP_KERNEL);
30913100a72SKirill Marinushkin 		if (!data)
31013100a72SKirill Marinushkin 			return -ENOMEM;
311ab3c3587SDavid Howells 
312ab3c3587SDavid Howells 		file = dentry_open(path, O_RDONLY, current_cred());
31313100a72SKirill Marinushkin 		if (IS_ERR(file)) {
31413100a72SKirill Marinushkin 			ret = PTR_ERR(file);
31513100a72SKirill Marinushkin 			goto error;
31613100a72SKirill Marinushkin 		}
317ab3c3587SDavid Howells 
31813100a72SKirill Marinushkin 		/* read file to kernel and decrypt */
319bdd1d2d3SChristoph Hellwig 		ret = kernel_read(file, data, enclen, &pos);
32013100a72SKirill Marinushkin 		if (ret >= 0 && ret != enclen) {
321ab3c3587SDavid Howells 			ret = -EIO;
32213100a72SKirill Marinushkin 			goto err_fput;
32313100a72SKirill Marinushkin 		}
32413100a72SKirill Marinushkin 
32513100a72SKirill Marinushkin 		ret = big_key_crypt(BIG_KEY_DEC, data, enclen, enckey);
32613100a72SKirill Marinushkin 		if (ret)
32713100a72SKirill Marinushkin 			goto err_fput;
32813100a72SKirill Marinushkin 
32913100a72SKirill Marinushkin 		ret = datalen;
33013100a72SKirill Marinushkin 
33113100a72SKirill Marinushkin 		/* copy decrypted data to user */
33213100a72SKirill Marinushkin 		if (copy_to_user(buffer, data, datalen) != 0)
33313100a72SKirill Marinushkin 			ret = -EFAULT;
33413100a72SKirill Marinushkin 
33513100a72SKirill Marinushkin err_fput:
33613100a72SKirill Marinushkin 		fput(file);
33713100a72SKirill Marinushkin error:
33891080180SJason A. Donenfeld 		kzfree(data);
339ab3c3587SDavid Howells 	} else {
340ab3c3587SDavid Howells 		ret = datalen;
341146aa8b1SDavid Howells 		if (copy_to_user(buffer, key->payload.data[big_key_data],
342146aa8b1SDavid Howells 				 datalen) != 0)
343ab3c3587SDavid Howells 			ret = -EFAULT;
344ab3c3587SDavid Howells 	}
345ab3c3587SDavid Howells 
346ab3c3587SDavid Howells 	return ret;
347ab3c3587SDavid Howells }
348ab3c3587SDavid Howells 
34913100a72SKirill Marinushkin /*
35013100a72SKirill Marinushkin  * Register key type
35113100a72SKirill Marinushkin  */
352ab3c3587SDavid Howells static int __init big_key_init(void)
353ab3c3587SDavid Howells {
3547df3e59cSDavid Howells 	int ret;
3557df3e59cSDavid Howells 
35613100a72SKirill Marinushkin 	/* init block cipher */
357428490e3SJason A. Donenfeld 	big_key_aead = crypto_alloc_aead(big_key_alg_name, 0, CRYPTO_ALG_ASYNC);
358428490e3SJason A. Donenfeld 	if (IS_ERR(big_key_aead)) {
359428490e3SJason A. Donenfeld 		ret = PTR_ERR(big_key_aead);
3607df3e59cSDavid Howells 		pr_err("Can't alloc crypto: %d\n", ret);
361428490e3SJason A. Donenfeld 		return ret;
3627df3e59cSDavid Howells 	}
363428490e3SJason A. Donenfeld 	ret = crypto_aead_setauthsize(big_key_aead, ENC_AUTHTAG_SIZE);
364428490e3SJason A. Donenfeld 	if (ret < 0) {
365428490e3SJason A. Donenfeld 		pr_err("Can't set crypto auth tag len: %d\n", ret);
366428490e3SJason A. Donenfeld 		goto free_aead;
367428490e3SJason A. Donenfeld 	}
3687df3e59cSDavid Howells 
3697df3e59cSDavid Howells 	ret = register_key_type(&key_type_big_key);
3707df3e59cSDavid Howells 	if (ret < 0) {
3717df3e59cSDavid Howells 		pr_err("Can't register type: %d\n", ret);
372428490e3SJason A. Donenfeld 		goto free_aead;
37313100a72SKirill Marinushkin 	}
37413100a72SKirill Marinushkin 
37513100a72SKirill Marinushkin 	return 0;
37613100a72SKirill Marinushkin 
377428490e3SJason A. Donenfeld free_aead:
378428490e3SJason A. Donenfeld 	crypto_free_aead(big_key_aead);
37913100a72SKirill Marinushkin 	return ret;
38013100a72SKirill Marinushkin }
38113100a72SKirill Marinushkin 
3827df3e59cSDavid Howells late_initcall(big_key_init);
383