/*
* Copyright (C) 2010 IBM Corporation
* Copyright (C) 2010 Politecnico di Torino, Italy
* TORSEC group -- http://security.polito.it
*
* Authors:
* Mimi Zohar <zohar@us.ibm.com>
* Roberto Sassu <roberto.sassu@polito.it>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 2 of the License.
*
* See Documentation/security/keys/trusted-encrypted.rst
*/
#include <linux/uaccess.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/parser.h>
#include <linux/string.h>
#include <linux/err.h>
#include <keys/user-type.h>
#include <keys/trusted-type.h>
#include <keys/encrypted-type.h>
#include <linux/key-type.h>
#include <linux/random.h>
#include <linux/rcupdate.h>
#include <linux/scatterlist.h>
#include <linux/ctype.h>
#include <crypto/aes.h>
#include <crypto/algapi.h>
#include <crypto/hash.h>
#include <crypto/sha.h>
#include <crypto/skcipher.h>
#include "encrypted.h"
#include "ecryptfs_format.h"
static const char KEY_TRUSTED_PREFIX[] = "trusted:";
static const char KEY_USER_PREFIX[] = "user:";
static const char hash_alg[] = "sha256";
static const char hmac_alg[] = "hmac(sha256)";
static const char blkcipher_alg[] = "cbc(aes)";
static const char key_format_default[] = "default";
static const char key_format_ecryptfs[] = "ecryptfs";
static unsigned int ivsize;
static int blksize;
#define KEY_TRUSTED_PREFIX_LEN (sizeof (KEY_TRUSTED_PREFIX) - 1)
#define KEY_USER_PREFIX_LEN (sizeof (KEY_USER_PREFIX) - 1)
#define KEY_ECRYPTFS_DESC_LEN 16
#define HASH_SIZE SHA256_DIGEST_SIZE
#define MAX_DATA_SIZE 4096
#define MIN_DATA_SIZE 20
static struct crypto_shash *hash_tfm;
enum {
Opt_err = -1, Opt_new, Opt_load, Opt_update
};
enum {
Opt_error = -1, Opt_default, Opt_ecryptfs
};
static const match_table_t key_format_tokens = {
{Opt_default, "default"},
{Opt_ecryptfs, "ecryptfs"},
{Opt_error, NULL}
};
static const match_table_t key_tokens = {
{Opt_new, "new"},
{Opt_load, "load"},
{Opt_update, "update"},
{Opt_err, NULL}
};
static int aes_get_sizes(void)
{
struct crypto_skcipher *tfm;
tfm = crypto_alloc_skcipher(blkcipher_alg, 0, CRYPTO_ALG_ASYNC);
if (IS_ERR(tfm)) {
pr_err("encrypted_key: failed to alloc_cipher (%ld)\n",
PTR_ERR(tfm));
return PTR_ERR(tfm);
}
ivsize = crypto_skcipher_ivsize(tfm);
blksize = crypto_skcipher_blocksize(tfm);
crypto_free_skcipher(tfm);
return 0;
}
/*
* valid_ecryptfs_desc - verify the description of a new/loaded encrypted key
*
* The description of a encrypted key with format 'ecryptfs' must contain
* exactly 16 hexadecimal characters.
*
*/
static int valid_ecryptfs_desc(const char *ecryptfs_desc)
{
int i;
if (strlen(ecryptfs_desc) != KEY_ECRYPTFS_DESC_LEN) {
pr_err("encrypted_key: key description must be %d hexadecimal "
"characters long\n", KEY_ECRYPTFS_DESC_LEN);
return -EINVAL;
}
for (i = 0; i < KEY_ECRYPTFS_DESC_LEN; i++) {
if (!isxdigit(ecryptfs_desc[i])) {
pr_err("encrypted_key: key description must contain "
"only hexadecimal characters\n");
return -EINVAL;
}
}
return 0;
}
/*
* valid_master_desc - verify the 'key-type:desc' of a new/updated master-key
*
* key-type:= "trusted:" | "user:"
* desc:= master-key description
*
* Verify that 'key-type' is valid and that 'desc' exists. On key update,
* only the master key description is permitted to change, not the key-type.
* The key-type remains constant.
*
* On success returns 0, otherwise -EINVAL.
*/
static int valid_master_desc(const char *new_desc, const char *orig_desc)
{
int prefix_len;
if (!strncmp(new_desc, KEY_TRUSTED_PREFIX, KEY_TRUSTED_PREFIX_LEN))
prefix_len = KEY_TRUSTED_PREFIX_LEN;
else if (!strncmp(new_desc, KEY_USER_PREFIX, KEY_USER_PREFIX_LEN))
prefix_len = KEY_USER_PREFIX_LEN;
else
return -EINVAL;
if (!new_desc[prefix_len])
return -EINVAL;
if (orig_desc && strncmp(new_desc, orig_desc, prefix_len))
return -EINVAL;
return 0;
}
/*
* datablob_parse - parse the keyctl data
*
* datablob format:
* new [<format>] <master-key name> <decrypted data length>
* load [<format>] <master-key name> <decrypted data length>
* <encrypted iv + data>
* update <new-master-key name>
*
* Tokenizes a copy of the keyctl data, returning a pointer to each token,
* which is null terminated.
*
* On success returns 0, otherwise -EINVAL.
*/
static int datablob_parse(char *datablob, const char **format,
char **master_desc, char **decrypted_datalen,
char **hex_encoded_iv)
{
substring_t args[MAX_OPT_ARGS];
int ret = -EINVAL;
int