// SPDX-License-Identifier: GPL-2.0-or-later /* * eCryptfs: Linux filesystem encryption layer * In-kernel key management code. Includes functions to parse and * write authentication token-related packets with the underlying * file. * * Copyright (C) 2004-2006 International Business Machines Corp. * Author(s): Michael A. Halcrow <mhalcrow@us.ibm.com> * Michael C. Thompson <mcthomps@us.ibm.com> * Trevor S. Highland <trevor.highland@gmail.com>
*/
/* * request_key returned an error instead of a valid key address; * determine the type of error, make appropriate log entries, and * return an error code.
*/ staticint process_request_key_err(long err_code)
{ int rc = 0;
/** * ecryptfs_parse_packet_length * @data: Pointer to memory containing length at offset * @size: This function writes the decoded size to this memory * address; zero on error * @length_size: The number of bytes occupied by the encoded length * * Returns zero on success; non-zero on error
*/ int ecryptfs_parse_packet_length(unsignedchar *data, size_t *size,
size_t *length_size)
{ int rc = 0;
/** * ecryptfs_write_packet_length * @dest: The byte array target into which to write the length. Must * have at least ECRYPTFS_MAX_PKT_LEN_SIZE bytes allocated. * @size: The length to write. * @packet_size_length: The number of bytes used to encode the packet * length is written to this address. * * Returns zero on success; non-zero on error.
*/ int ecryptfs_write_packet_length(char *dest, size_t size,
size_t *packet_size_length)
{ int rc = 0;
staticint
parse_tag_67_packet(struct ecryptfs_key_record *key_rec, struct ecryptfs_message *msg)
{
size_t i = 0; char *data;
size_t data_len;
size_t message_len; int rc;
/* * ***** TAG 65 Packet Format ***** * | Content Type | 1 byte | * | Status Indicator | 1 byte | * | Encrypted File Encryption Key Size | 1 or 2 bytes | * | Encrypted File Encryption Key | arbitrary |
*/
message_len = msg->data_len;
data = msg->data; /* verify that everything through the encrypted FEK size is present */ if (message_len < 4) {
rc = -EIO;
printk(KERN_ERR "%s: message_len is [%zd]; minimum acceptable " "message length is [%d]\n", __func__, message_len, 4); goto out;
} if (data[i++] != ECRYPTFS_TAG_67_PACKET_TYPE) {
rc = -EIO;
printk(KERN_ERR "%s: Type should be ECRYPTFS_TAG_67\n",
__func__); goto out;
} if (data[i++]) {
rc = -EIO;
printk(KERN_ERR "%s: Status indicator has non zero " "value [%d]\n", __func__, data[i-1]);
goto out;
}
rc = ecryptfs_parse_packet_length(&data[i], &key_rec->enc_key_size,
&data_len); if (rc) {
ecryptfs_printk(KERN_WARNING, "Error parsing packet length; " "rc = [%d]\n", rc); goto out;
}
i += data_len; if (message_len < (i + key_rec->enc_key_size)) {
rc = -EIO;
printk(KERN_ERR "%s: message_len [%zd]; max len is [%zd]\n",
__func__, message_len, (i + key_rec->enc_key_size)); goto out;
} if (key_rec->enc_key_size > ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES) {
rc = -EIO;
printk(KERN_ERR "%s: Encrypted key_size [%zd] larger than " "the maximum key size [%d]\n", __func__,
key_rec->enc_key_size,
ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES); goto out;
}
memcpy(key_rec->enc_key, &data[i], key_rec->enc_key_size);
out: return rc;
}
/** * ecryptfs_verify_version * @version: The version number to confirm * * Returns zero on good version; non-zero otherwise
*/ staticint ecryptfs_verify_version(u16 version)
{ int rc = 0; unsignedchar major; unsignedchar minor;
major = ((version >> 8) & 0xFF);
minor = (version & 0xFF); if (major != ECRYPTFS_VERSION_MAJOR) {
ecryptfs_printk(KERN_ERR, "Major version number mismatch. " "Expected [%d]; got [%d]\n",
ECRYPTFS_VERSION_MAJOR, major);
rc = -EINVAL; goto out;
} if (minor != ECRYPTFS_VERSION_MINOR) {
ecryptfs_printk(KERN_ERR, "Minor version number mismatch. " "Expected [%d]; got [%d]\n",
ECRYPTFS_VERSION_MINOR, minor);
rc = -EINVAL; goto out;
}
out: return rc;
}
/** * ecryptfs_verify_auth_tok_from_key * @auth_tok_key: key containing the authentication token * @auth_tok: authentication token * * Returns zero on valid auth tok; -EINVAL if the payload is invalid; or * -EKEYREVOKED if the key was revoked before we acquired its semaphore.
*/ staticint
ecryptfs_verify_auth_tok_from_key(struct key *auth_tok_key, struct ecryptfs_auth_tok **auth_tok)
{ int rc = 0;
/** * ecryptfs_find_auth_tok_for_sig * @auth_tok_key: key containing the authentication token * @auth_tok: Set to the matching auth_tok; NULL if not found * @mount_crypt_stat: inode crypt_stat crypto context * @sig: Sig of auth_tok to find * * For now, this function simply looks at the registered auth_tok's * linked off the mount_crypt_stat, so all the auth_toks that can be * used must be registered at mount time. This function could * potentially try a lot harder to find auth_tok's (e.g., by calling * out to ecryptfsd to dynamically retrieve an auth_tok object) so * that static registration of auth_tok's will no longer be necessary. * * Returns zero on no error; non-zero on error
*/ staticint
ecryptfs_find_auth_tok_for_sig( struct key **auth_tok_key, struct ecryptfs_auth_tok **auth_tok, struct ecryptfs_mount_crypt_stat *mount_crypt_stat, char *sig)
{ int rc = 0;
rc = ecryptfs_find_global_auth_tok_for_sig(auth_tok_key, auth_tok,
mount_crypt_stat, sig); if (rc == -ENOENT) { /* if the flag ECRYPTFS_GLOBAL_MOUNT_AUTH_TOK_ONLY is set in the * mount_crypt_stat structure, we prevent to use auth toks that * are not inserted through the ecryptfs_add_global_auth_tok * function.
*/ if (mount_crypt_stat->flags
& ECRYPTFS_GLOBAL_MOUNT_AUTH_TOK_ONLY) return -EINVAL;
/* * write_tag_70_packet can gobble a lot of stack space. We stuff most * of the function's parameters in a kmalloc'd struct to help reduce * eCryptfs' overall stack usage.
*/ struct ecryptfs_write_tag_70_packet_silly_stack {
u8 cipher_code;
size_t max_packet_size;
size_t packet_size_len;
size_t block_aligned_filename_size;
size_t block_size;
size_t i;
size_t j;
size_t num_rand_bytes; struct mutex *tfm_mutex; char *block_aligned_filename; struct ecryptfs_auth_tok *auth_tok; struct scatterlist src_sg[2]; struct scatterlist dst_sg[2]; struct crypto_skcipher *skcipher_tfm; struct skcipher_request *skcipher_req; char iv[ECRYPTFS_MAX_IV_BYTES]; char hash[ECRYPTFS_TAG_70_DIGEST_SIZE]; char tmp_hash[ECRYPTFS_TAG_70_DIGEST_SIZE]; struct crypto_shash *hash_tfm; struct shash_desc *hash_desc;
};
/* * write_tag_70_packet - Write encrypted filename (EFN) packet against FNEK * @filename: NULL-terminated filename string * * This is the simplest mechanism for achieving filename encryption in * eCryptfs. It encrypts the given filename with the mount-wide * filename encryption key (FNEK) and stores it in a packet to @dest, * which the callee will encode and write directly into the dentry * name.
*/ int
ecryptfs_write_tag_70_packet(char *dest, size_t *remaining_bytes,
size_t *packet_size, struct ecryptfs_mount_crypt_stat *mount_crypt_stat, char *filename, size_t filename_size)
{ struct ecryptfs_write_tag_70_packet_silly_stack *s; struct key *auth_tok_key = NULL; int rc = 0;
s = kzalloc(sizeof(*s), GFP_KERNEL); if (!s) return -ENOMEM;
(*packet_size) = 0;
rc = ecryptfs_find_auth_tok_for_sig(
&auth_tok_key,
&s->auth_tok, mount_crypt_stat,
mount_crypt_stat->global_default_fnek_sig); if (rc) {
printk(KERN_ERR "%s: Error attempting to find auth tok for " "fnek sig [%s]; rc = [%d]\n", __func__,
mount_crypt_stat->global_default_fnek_sig, rc); goto out;
}
rc = ecryptfs_get_tfm_and_mutex_for_cipher_name(
&s->skcipher_tfm,
&s->tfm_mutex, mount_crypt_stat->global_default_fn_cipher_name); if (unlikely(rc)) {
printk(KERN_ERR "Internal error whilst attempting to get " "tfm and mutex for cipher name [%s]; rc = [%d]\n",
mount_crypt_stat->global_default_fn_cipher_name, rc); goto out;
}
mutex_lock(s->tfm_mutex);
s->block_size = crypto_skcipher_blocksize(s->skcipher_tfm); /* Plus one for the \0 separator between the random prefix
* and the plaintext filename */
s->num_rand_bytes = (ECRYPTFS_FILENAME_MIN_RANDOM_PREPEND_BYTES + 1);
s->block_aligned_filename_size = (s->num_rand_bytes + filename_size); if ((s->block_aligned_filename_size % s->block_size) != 0) {
s->num_rand_bytes += (s->block_size
- (s->block_aligned_filename_size
% s->block_size));
s->block_aligned_filename_size = (s->num_rand_bytes
+ filename_size);
} /* Octet 0: Tag 70 identifier * Octets 1-N1: Tag 70 packet size (includes cipher identifier * and block-aligned encrypted filename size) * Octets N1-N2: FNEK sig (ECRYPTFS_SIG_SIZE) * Octet N2-N3: Cipher identifier (1 octet) * Octets N3-N4: Block-aligned encrypted filename * - Consists of a minimum number of random characters, a \0
* separator, and then the filename */
s->max_packet_size = (ECRYPTFS_TAG_70_MAX_METADATA_SIZE
+ s->block_aligned_filename_size); if (!dest) {
(*packet_size) = s->max_packet_size; goto out_unlock;
} if (s->max_packet_size > (*remaining_bytes)) {
printk(KERN_WARNING "%s: Require [%zd] bytes to write; only " "[%zd] available\n", __func__, s->max_packet_size,
(*remaining_bytes));
rc = -EINVAL; goto out_unlock;
}
s->skcipher_req = skcipher_request_alloc(s->skcipher_tfm, GFP_KERNEL); if (!s->skcipher_req) {
printk(KERN_ERR "%s: Out of kernel memory whilst attempting to " "skcipher_request_alloc for %s\n", __func__,
crypto_skcipher_driver_name(s->skcipher_tfm));
rc = -ENOMEM; goto out_unlock;
}
/** * ecryptfs_parse_tag_70_packet - Parse and process FNEK-encrypted passphrase packet * @filename: This function kmalloc's the memory for the filename * @filename_size: This function sets this to the amount of memory * kmalloc'd for the filename * @packet_size: This function sets this to the the number of octets * in the packet parsed * @mount_crypt_stat: The mount-wide cryptographic context * @data: The memory location containing the start of the tag 70 * packet * @max_packet_size: The maximum legal size of the packet to be parsed * from @data * * Returns zero on success; non-zero otherwise
*/ int
ecryptfs_parse_tag_70_packet(char **filename, size_t *filename_size,
size_t *packet_size, struct ecryptfs_mount_crypt_stat *mount_crypt_stat, char *data, size_t max_packet_size)
{ struct ecryptfs_parse_tag_70_packet_silly_stack *s; struct key *auth_tok_key = NULL; int rc = 0;
(*packet_size) = 0;
(*filename_size) = 0;
(*filename) = NULL;
s = kzalloc(sizeof(*s), GFP_KERNEL); if (!s) return -ENOMEM;
if (max_packet_size < ECRYPTFS_TAG_70_MIN_METADATA_SIZE) {
printk(KERN_WARNING "%s: max_packet_size is [%zd]; it must be " "at least [%d]\n", __func__, max_packet_size,
ECRYPTFS_TAG_70_MIN_METADATA_SIZE);
rc = -EINVAL; goto out;
} /* Octet 0: Tag 70 identifier * Octets 1-N1: Tag 70 packet size (includes cipher identifier * and block-aligned encrypted filename size) * Octets N1-N2: FNEK sig (ECRYPTFS_SIG_SIZE) * Octet N2-N3: Cipher identifier (1 octet) * Octets N3-N4: Block-aligned encrypted filename * - Consists of a minimum number of random numbers, a \0
* separator, and then the filename */ if (data[(*packet_size)++] != ECRYPTFS_TAG_70_PACKET_TYPE) {
printk(KERN_WARNING "%s: Invalid packet tag [0x%.2x]; must be " "tag [0x%.2x]\n", __func__,
data[((*packet_size) - 1)], ECRYPTFS_TAG_70_PACKET_TYPE);
rc = -EINVAL; goto out;
}
rc = ecryptfs_parse_packet_length(&data[(*packet_size)],
&s->parsed_tag_70_packet_size,
&s->packet_size_len); if (rc) {
printk(KERN_WARNING "%s: Error parsing packet length; " "rc = [%d]\n", __func__, rc); goto out;
}
s->block_aligned_filename_size = (s->parsed_tag_70_packet_size
- ECRYPTFS_SIG_SIZE - 1); if ((1 + s->packet_size_len + s->parsed_tag_70_packet_size)
> max_packet_size) {
printk(KERN_WARNING "%s: max_packet_size is [%zd]; real packet " "size is [%zd]\n", __func__, max_packet_size,
(1 + s->packet_size_len + 1
+ s->block_aligned_filename_size));
rc = -EINVAL; goto out;
}
(*packet_size) += s->packet_size_len;
ecryptfs_to_hex(s->fnek_sig_hex, &data[(*packet_size)],
ECRYPTFS_SIG_SIZE);
s->fnek_sig_hex[ECRYPTFS_SIG_SIZE_HEX] = '\0';
(*packet_size) += ECRYPTFS_SIG_SIZE;
s->cipher_code = data[(*packet_size)++];
rc = ecryptfs_cipher_code_to_string(s->cipher_string, s->cipher_code); if (rc) {
printk(KERN_WARNING "%s: Cipher code [%d] is invalid\n",
__func__, s->cipher_code); goto out;
}
rc = ecryptfs_find_auth_tok_for_sig(&auth_tok_key,
&s->auth_tok, mount_crypt_stat,
s->fnek_sig_hex); if (rc) {
printk(KERN_ERR "%s: Error attempting to find auth tok for " "fnek sig [%s]; rc = [%d]\n", __func__, s->fnek_sig_hex,
rc); goto out;
}
rc = ecryptfs_get_tfm_and_mutex_for_cipher_name(&s->skcipher_tfm,
&s->tfm_mutex,
s->cipher_string); if (unlikely(rc)) {
printk(KERN_ERR "Internal error whilst attempting to get " "tfm and mutex for cipher name [%s]; rc = [%d]\n",
s->cipher_string, rc); goto out;
}
mutex_lock(s->tfm_mutex);
rc = virt_to_scatterlist(&data[(*packet_size)],
s->block_aligned_filename_size, s->src_sg, 2); if (rc < 1) {
printk(KERN_ERR "%s: Internal error whilst attempting to " "convert encrypted filename memory to scatterlist; " "rc = [%d]. block_aligned_filename_size = [%zd]\n",
__func__, rc, s->block_aligned_filename_size); goto out_unlock;
}
(*packet_size) += s->block_aligned_filename_size;
s->decrypted_filename = kmalloc(s->block_aligned_filename_size,
GFP_KERNEL); if (!s->decrypted_filename) {
rc = -ENOMEM; goto out_unlock;
}
rc = virt_to_scatterlist(s->decrypted_filename,
s->block_aligned_filename_size, s->dst_sg, 2); if (rc < 1) {
printk(KERN_ERR "%s: Internal error whilst attempting to " "convert decrypted filename memory to scatterlist; " "rc = [%d]. block_aligned_filename_size = [%zd]\n",
__func__, rc, s->block_aligned_filename_size); goto out_free_unlock;
}
s->skcipher_req = skcipher_request_alloc(s->skcipher_tfm, GFP_KERNEL); if (!s->skcipher_req) {
printk(KERN_ERR "%s: Out of kernel memory whilst attempting to " "skcipher_request_alloc for %s\n", __func__,
crypto_skcipher_driver_name(s->skcipher_tfm));
rc = -ENOMEM; goto out_free_unlock;
}
/* The characters in the first block effectively do the job of * the IV here, so we just use 0's for the IV. Note the * constraint that ECRYPTFS_FILENAME_MIN_RANDOM_PREPEND_BYTES
* >= ECRYPTFS_MAX_IV_BYTES. */ /* TODO: Support other key modules than passphrase for
* filename encryption */ if (s->auth_tok->token_type != ECRYPTFS_PASSWORD) {
rc = -EOPNOTSUPP;
printk(KERN_INFO "%s: Filename encryption only supports " "password tokens\n", __func__); goto out_free_unlock;
}
rc = crypto_skcipher_setkey(
s->skcipher_tfm,
s->auth_tok->token.password.session_key_encryption_key,
mount_crypt_stat->global_default_fn_cipher_key_bytes); if (rc < 0) {
printk(KERN_ERR "%s: Error setting key for crypto context; " "rc = [%d]. s->auth_tok->token.password.session_key_" "encryption_key = [0x%p]; mount_crypt_stat->" "global_default_fn_cipher_key_bytes = [%zd]\n", __func__,
rc,
s->auth_tok->token.password.session_key_encryption_key,
mount_crypt_stat->global_default_fn_cipher_key_bytes); goto out_free_unlock;
}
skcipher_request_set_crypt(s->skcipher_req, s->src_sg, s->dst_sg,
s->block_aligned_filename_size, s->iv);
rc = crypto_skcipher_decrypt(s->skcipher_req); if (rc) {
printk(KERN_ERR "%s: Error attempting to decrypt filename; " "rc = [%d]\n", __func__, rc); goto out_free_unlock;
}
while (s->i < s->block_aligned_filename_size &&
s->decrypted_filename[s->i] != '\0')
s->i++; if (s->i == s->block_aligned_filename_size) {
printk(KERN_WARNING "%s: Invalid tag 70 packet; could not " "find valid separator between random characters and " "the filename\n", __func__);
rc = -EINVAL; goto out_free_unlock;
}
s->i++;
(*filename_size) = (s->block_aligned_filename_size - s->i); if (!((*filename_size) > 0 && (*filename_size < PATH_MAX))) {
printk(KERN_WARNING "%s: Filename size is [%zd], which is " "invalid\n", __func__, (*filename_size));
rc = -EINVAL; goto out_free_unlock;
}
(*filename) = kmalloc(((*filename_size) + 1), GFP_KERNEL); if (!(*filename)) {
rc = -ENOMEM; goto out_free_unlock;
}
memcpy((*filename), &s->decrypted_filename[s->i], (*filename_size));
(*filename)[(*filename_size)] = '\0';
out_free_unlock:
kfree(s->decrypted_filename);
out_unlock:
mutex_unlock(s->tfm_mutex);
out: if (rc) {
(*packet_size) = 0;
(*filename_size) = 0;
(*filename) = NULL;
} if (auth_tok_key) {
up_write(&(auth_tok_key->sem));
key_put(auth_tok_key);
}
skcipher_request_free(s->skcipher_req);
kfree(s); return rc;
}
/** * parse_tag_1_packet * @crypt_stat: The cryptographic context to modify based on packet contents * @data: The raw bytes of the packet. * @auth_tok_list: eCryptfs parses packets into authentication tokens; * a new authentication token will be placed at the * end of this list for this packet. * @new_auth_tok: Pointer to a pointer to memory that this function * allocates; sets the memory address of the pointer to * NULL on error. This object is added to the * auth_tok_list. * @packet_size: This function writes the size of the parsed packet * into this memory location; zero on error. * @max_packet_size: The maximum allowable packet size * * Returns zero on success; non-zero on error.
*/ staticint
parse_tag_1_packet(struct ecryptfs_crypt_stat *crypt_stat, unsignedchar *data, struct list_head *auth_tok_list, struct ecryptfs_auth_tok **new_auth_tok,
size_t *packet_size, size_t max_packet_size)
{
size_t body_size; struct ecryptfs_auth_tok_list_item *auth_tok_list_item;
size_t length_size; int rc = 0;
(*packet_size) = 0;
(*new_auth_tok) = NULL; /** * This format is inspired by OpenPGP; see RFC 2440 * packet tag 1 * * Tag 1 identifier (1 byte) * Max Tag 1 packet size (max 3 bytes) * Version (1 byte) * Key identifier (8 bytes; ECRYPTFS_SIG_SIZE) * Cipher identifier (1 byte) * Encrypted key size (arbitrary) * * 12 bytes minimum packet size
*/ if (unlikely(max_packet_size < 12)) {
printk(KERN_ERR "Invalid max packet size; must be >=12\n");
rc = -EINVAL; goto out;
} if (data[(*packet_size)++] != ECRYPTFS_TAG_1_PACKET_TYPE) {
printk(KERN_ERR "Enter w/ first byte != 0x%.2x\n",
ECRYPTFS_TAG_1_PACKET_TYPE);
rc = -EINVAL; goto out;
} /* Released: wipe_auth_tok_list called in ecryptfs_parse_packet_set or
* at end of function upon failure */
auth_tok_list_item =
kmem_cache_zalloc(ecryptfs_auth_tok_list_item_cache,
GFP_KERNEL); if (!auth_tok_list_item) {
printk(KERN_ERR "Unable to allocate memory\n");
rc = -ENOMEM; goto out;
}
(*new_auth_tok) = &auth_tok_list_item->auth_tok;
rc = ecryptfs_parse_packet_length(&data[(*packet_size)], &body_size,
&length_size); if (rc) {
printk(KERN_WARNING "Error parsing packet length; " "rc = [%d]\n", rc); goto out_free;
} if (unlikely(body_size < (ECRYPTFS_SIG_SIZE + 2))) {
printk(KERN_WARNING "Invalid body size ([%td])\n", body_size);
rc = -EINVAL; goto out_free;
}
(*packet_size) += length_size; if (unlikely((*packet_size) + body_size > max_packet_size)) {
printk(KERN_WARNING "Packet size exceeds max\n");
rc = -EINVAL; goto out_free;
} if (unlikely(data[(*packet_size)++] != 0x03)) {
printk(KERN_WARNING "Unknown version number [%d]\n",
data[(*packet_size) - 1]);
rc = -EINVAL; goto out_free;
}
ecryptfs_to_hex((*new_auth_tok)->token.private_key.signature,
&data[(*packet_size)], ECRYPTFS_SIG_SIZE);
*packet_size += ECRYPTFS_SIG_SIZE; /* This byte is skipped because the kernel does not need to
* know which public key encryption algorithm was used */
(*packet_size)++;
(*new_auth_tok)->session_key.encrypted_key_size =
body_size - (ECRYPTFS_SIG_SIZE + 2); if ((*new_auth_tok)->session_key.encrypted_key_size
> ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES) {
printk(KERN_WARNING "Tag 1 packet contains key larger " "than ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES\n");
rc = -EINVAL; goto out_free;
}
memcpy((*new_auth_tok)->session_key.encrypted_key,
&data[(*packet_size)], (body_size - (ECRYPTFS_SIG_SIZE + 2)));
(*packet_size) += (*new_auth_tok)->session_key.encrypted_key_size;
(*new_auth_tok)->session_key.flags &=
~ECRYPTFS_CONTAINS_DECRYPTED_KEY;
(*new_auth_tok)->session_key.flags |=
ECRYPTFS_CONTAINS_ENCRYPTED_KEY;
(*new_auth_tok)->token_type = ECRYPTFS_PRIVATE_KEY;
(*new_auth_tok)->flags = 0;
(*new_auth_tok)->session_key.flags &=
~(ECRYPTFS_USERSPACE_SHOULD_TRY_TO_DECRYPT);
(*new_auth_tok)->session_key.flags &=
~(ECRYPTFS_USERSPACE_SHOULD_TRY_TO_ENCRYPT);
list_add(&auth_tok_list_item->list, auth_tok_list); goto out;
out_free:
(*new_auth_tok) = NULL;
memset(auth_tok_list_item, 0, sizeof(struct ecryptfs_auth_tok_list_item));
kmem_cache_free(ecryptfs_auth_tok_list_item_cache,
auth_tok_list_item);
out: if (rc)
(*packet_size) = 0; return rc;
}
/** * parse_tag_3_packet * @crypt_stat: The cryptographic context to modify based on packet * contents. * @data: The raw bytes of the packet. * @auth_tok_list: eCryptfs parses packets into authentication tokens; * a new authentication token will be placed at the end * of this list for this packet. * @new_auth_tok: Pointer to a pointer to memory that this function * allocates; sets the memory address of the pointer to * NULL on error. This object is added to the * auth_tok_list. * @packet_size: This function writes the size of the parsed packet * into this memory location; zero on error. * @max_packet_size: maximum number of bytes to parse * * Returns zero on success; non-zero on error.
*/ staticint
parse_tag_3_packet(struct ecryptfs_crypt_stat *crypt_stat, unsignedchar *data, struct list_head *auth_tok_list, struct ecryptfs_auth_tok **new_auth_tok,
size_t *packet_size, size_t max_packet_size)
{
size_t body_size; struct ecryptfs_auth_tok_list_item *auth_tok_list_item;
size_t length_size; int rc = 0;
(*packet_size) = 0;
(*new_auth_tok) = NULL; /** *This format is inspired by OpenPGP; see RFC 2440 * packet tag 3 * * Tag 3 identifier (1 byte) * Max Tag 3 packet size (max 3 bytes) * Version (1 byte) * Cipher code (1 byte) * S2K specifier (1 byte) * Hash identifier (1 byte) * Salt (ECRYPTFS_SALT_SIZE) * Hash iterations (1 byte) * Encrypted key (arbitrary) * * (ECRYPTFS_SALT_SIZE + 7) minimum packet size
*/ if (max_packet_size < (ECRYPTFS_SALT_SIZE + 7)) {
printk(KERN_ERR "Max packet size too large\n");
rc = -EINVAL; goto out;
} if (data[(*packet_size)++] != ECRYPTFS_TAG_3_PACKET_TYPE) {
printk(KERN_ERR "First byte != 0x%.2x; invalid packet\n",
ECRYPTFS_TAG_3_PACKET_TYPE);
rc = -EINVAL; goto out;
} /* Released: wipe_auth_tok_list called in ecryptfs_parse_packet_set or
* at end of function upon failure */
auth_tok_list_item =
kmem_cache_zalloc(ecryptfs_auth_tok_list_item_cache, GFP_KERNEL); if (!auth_tok_list_item) {
printk(KERN_ERR "Unable to allocate memory\n");
rc = -ENOMEM; goto out;
}
(*new_auth_tok) = &auth_tok_list_item->auth_tok;
rc = ecryptfs_parse_packet_length(&data[(*packet_size)], &body_size,
&length_size); if (rc) {
printk(KERN_WARNING "Error parsing packet length; rc = [%d]\n",
rc); goto out_free;
} if (unlikely(body_size < (ECRYPTFS_SALT_SIZE + 5))) {
printk(KERN_WARNING "Invalid body size ([%td])\n", body_size);
rc = -EINVAL; goto out_free;
}
(*packet_size) += length_size; if (unlikely((*packet_size) + body_size > max_packet_size)) {
printk(KERN_ERR "Packet size exceeds max\n");
rc = -EINVAL; goto out_free;
}
(*new_auth_tok)->session_key.encrypted_key_size =
(body_size - (ECRYPTFS_SALT_SIZE + 5)); if ((*new_auth_tok)->session_key.encrypted_key_size
> ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES) {
printk(KERN_WARNING "Tag 3 packet contains key larger " "than ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES\n");
rc = -EINVAL; goto out_free;
} if (unlikely(data[(*packet_size)++] != 0x04)) {
printk(KERN_WARNING "Unknown version number [%d]\n",
data[(*packet_size) - 1]);
rc = -EINVAL; goto out_free;
}
rc = ecryptfs_cipher_code_to_string(crypt_stat->cipher,
(u16)data[(*packet_size)]); if (rc) goto out_free; /* A little extra work to differentiate among the AES key
* sizes; see RFC2440 */ switch(data[(*packet_size)++]) { case RFC2440_CIPHER_AES_192:
crypt_stat->key_size = 24; break; default:
crypt_stat->key_size =
(*new_auth_tok)->session_key.encrypted_key_size;
}
rc = ecryptfs_init_crypt_ctx(crypt_stat); if (rc) goto out_free; if (unlikely(data[(*packet_size)++] != 0x03)) {
printk(KERN_WARNING "Only S2K ID 3 is currently supported\n");
rc = -ENOSYS; goto out_free;
} /* TODO: finish the hash mapping */ switch (data[(*packet_size)++]) { case 0x01: /* See RFC2440 for these numbers and their mappings */ /* Choose MD5 */
memcpy((*new_auth_tok)->token.password.salt,
&data[(*packet_size)], ECRYPTFS_SALT_SIZE);
(*packet_size) += ECRYPTFS_SALT_SIZE; /* This conversion was taken straight from RFC2440 */
(*new_auth_tok)->token.password.hash_iterations =
((u32) 16 + (data[(*packet_size)] & 15))
<< ((data[(*packet_size)] >> 4) + 6);
(*packet_size)++; /* Friendly reminder: * (*new_auth_tok)->session_key.encrypted_key_size =
* (body_size - (ECRYPTFS_SALT_SIZE + 5)); */
memcpy((*new_auth_tok)->session_key.encrypted_key,
&data[(*packet_size)],
(*new_auth_tok)->session_key.encrypted_key_size);
(*packet_size) +=
(*new_auth_tok)->session_key.encrypted_key_size;
(*new_auth_tok)->session_key.flags &=
~ECRYPTFS_CONTAINS_DECRYPTED_KEY;
(*new_auth_tok)->session_key.flags |=
ECRYPTFS_CONTAINS_ENCRYPTED_KEY;
(*new_auth_tok)->token.password.hash_algo = 0x01; /* MD5 */ break; default:
ecryptfs_printk(KERN_ERR, "Unsupported hash algorithm: " "[%d]\n", data[(*packet_size) - 1]);
rc = -ENOSYS; goto out_free;
}
(*new_auth_tok)->token_type = ECRYPTFS_PASSWORD; /* TODO: Parametarize; we might actually want userspace to
* decrypt the session key. */
(*new_auth_tok)->session_key.flags &=
~(ECRYPTFS_USERSPACE_SHOULD_TRY_TO_DECRYPT);
(*new_auth_tok)->session_key.flags &=
~(ECRYPTFS_USERSPACE_SHOULD_TRY_TO_ENCRYPT);
list_add(&auth_tok_list_item->list, auth_tok_list); goto out;
out_free:
(*new_auth_tok) = NULL;
memset(auth_tok_list_item, 0, sizeof(struct ecryptfs_auth_tok_list_item));
kmem_cache_free(ecryptfs_auth_tok_list_item_cache,
auth_tok_list_item);
out: if (rc)
(*packet_size) = 0; return rc;
}
/** * parse_tag_11_packet * @data: The raw bytes of the packet * @contents: This function writes the data contents of the literal * packet into this memory location * @max_contents_bytes: The maximum number of bytes that this function * is allowed to write into contents * @tag_11_contents_size: This function writes the size of the parsed * contents into this memory location; zero on * error * @packet_size: This function writes the size of the parsed packet * into this memory location; zero on error * @max_packet_size: maximum number of bytes to parse * * Returns zero on success; non-zero on error.
*/ staticint
parse_tag_11_packet(unsignedchar *data, unsignedchar *contents,
size_t max_contents_bytes, size_t *tag_11_contents_size,
size_t *packet_size, size_t max_packet_size)
{
size_t body_size;
size_t length_size; int rc = 0;
(*packet_size) = 0;
(*tag_11_contents_size) = 0; /* This format is inspired by OpenPGP; see RFC 2440 * packet tag 11 * * Tag 11 identifier (1 byte) * Max Tag 11 packet size (max 3 bytes) * Binary format specifier (1 byte) * Filename length (1 byte) * Filename ("_CONSOLE") (8 bytes) * Modification date (4 bytes) * Literal data (arbitrary) * * We need at least 16 bytes of data for the packet to even be * valid.
*/ if (max_packet_size < 16) {
printk(KERN_ERR "Maximum packet size too small\n");
rc = -EINVAL; goto out;
} if (data[(*packet_size)++] != ECRYPTFS_TAG_11_PACKET_TYPE) {
printk(KERN_WARNING "Invalid tag 11 packet format\n");
rc = -EINVAL; goto out;
}
rc = ecryptfs_parse_packet_length(&data[(*packet_size)], &body_size,
&length_size); if (rc) {
printk(KERN_WARNING "Invalid tag 11 packet format\n"); goto out;
} if (body_size < 14) {
printk(KERN_WARNING "Invalid body size ([%td])\n", body_size);
rc = -EINVAL; goto out;
}
(*packet_size) += length_size;
(*tag_11_contents_size) = (body_size - 14); if (unlikely((*packet_size) + body_size + 1 > max_packet_size)) {
printk(KERN_ERR "Packet size exceeds max\n");
rc = -EINVAL; goto out;
} if (unlikely((*tag_11_contents_size) > max_contents_bytes)) {
printk(KERN_ERR "Literal data section in tag 11 packet exceeds " "expected size\n");
rc = -EINVAL; goto out;
} if (data[(*packet_size)++] != 0x62) {
printk(KERN_WARNING "Unrecognizable packet\n");
rc = -EINVAL; goto out;
} if (data[(*packet_size)++] != 0x08) {
printk(KERN_WARNING "Unrecognizable packet\n");
rc = -EINVAL; goto out;
}
(*packet_size) += 12; /* Ignore filename and modification date */
memcpy(contents, &data[(*packet_size)], (*tag_11_contents_size));
(*packet_size) += (*tag_11_contents_size);
out: if (rc) {
(*packet_size) = 0;
(*tag_11_contents_size) = 0;
} return rc;
}
int ecryptfs_keyring_auth_tok_for_sig(struct key **auth_tok_key, struct ecryptfs_auth_tok **auth_tok, char *sig)
{ int rc = 0;
/** * ecryptfs_parse_packet_set * @crypt_stat: The cryptographic context * @src: Virtual address of region of memory containing the packets * @ecryptfs_dentry: The eCryptfs dentry associated with the packet set * * Get crypt_stat to have the file's session key if the requisite key * is available to decrypt the session key. * * Returns Zero if a valid authentication token was retrieved and * processed; negative value for file not encrypted or for error * conditions.
*/ int ecryptfs_parse_packet_set(struct ecryptfs_crypt_stat *crypt_stat, unsignedchar *src, struct dentry *ecryptfs_dentry)
{
size_t i = 0;
size_t found_auth_tok;
size_t next_packet_is_auth_tok_packet; struct list_head auth_tok_list; struct ecryptfs_auth_tok *matching_auth_tok; struct ecryptfs_auth_tok *candidate_auth_tok; char *candidate_auth_tok_sig;
size_t packet_size; struct ecryptfs_auth_tok *new_auth_tok; unsignedchar sig_tmp_space[ECRYPTFS_SIG_SIZE]; struct ecryptfs_auth_tok_list_item *auth_tok_list_item;
size_t tag_11_contents_size;
size_t tag_11_packet_size; struct key *auth_tok_key = NULL; int rc = 0;
INIT_LIST_HEAD(&auth_tok_list); /* Parse the header to find as many packets as we can; these will be
* added the our &auth_tok_list */
next_packet_is_auth_tok_packet = 1; while (next_packet_is_auth_tok_packet) {
size_t max_packet_size = ((PAGE_SIZE - 8) - i);
switch (src[i]) { case ECRYPTFS_TAG_3_PACKET_TYPE:
rc = parse_tag_3_packet(crypt_stat,
(unsignedchar *)&src[i],
&auth_tok_list, &new_auth_tok,
&packet_size, max_packet_size); if (rc) {
ecryptfs_printk(KERN_ERR, "Error parsing " "tag 3 packet\n");
rc = -EIO; goto out_wipe_list;
}
i += packet_size;
rc = parse_tag_11_packet((unsignedchar *)&src[i],
sig_tmp_space,
ECRYPTFS_SIG_SIZE,
&tag_11_contents_size,
&tag_11_packet_size,
max_packet_size); if (rc) {
ecryptfs_printk(KERN_ERR, "No valid " "(ecryptfs-specific) literal " "packet containing " "authentication token " "signature found after " "tag 3 packet\n");
rc = -EIO; goto out_wipe_list;
}
i += tag_11_packet_size; if (ECRYPTFS_SIG_SIZE != tag_11_contents_size) {
ecryptfs_printk(KERN_ERR, "Expected " "signature of size [%d]; " "read size [%zd]\n",
ECRYPTFS_SIG_SIZE,
tag_11_contents_size);
rc = -EIO; goto out_wipe_list;
}
ecryptfs_to_hex(new_auth_tok->token.password.signature,
sig_tmp_space, tag_11_contents_size);
new_auth_tok->token.password.signature[
ECRYPTFS_PASSWORD_SIG_SIZE] = '\0';
crypt_stat->flags |= ECRYPTFS_ENCRYPTED; break; case ECRYPTFS_TAG_1_PACKET_TYPE:
rc = parse_tag_1_packet(crypt_stat,
(unsignedchar *)&src[i],
&auth_tok_list, &new_auth_tok,
&packet_size, max_packet_size); if (rc) {
ecryptfs_printk(KERN_ERR, "Error parsing " "tag 1 packet\n");
rc = -EIO; goto out_wipe_list;
}
i += packet_size;
crypt_stat->flags |= ECRYPTFS_ENCRYPTED; break; case ECRYPTFS_TAG_11_PACKET_TYPE:
ecryptfs_printk(KERN_WARNING, "Invalid packet set " "(Tag 11 not allowed by itself)\n");
rc = -EIO; goto out_wipe_list; default:
ecryptfs_printk(KERN_DEBUG, "No packet at offset [%zd] " "of the file header; hex value of " "character is [0x%.2x]\n", i, src[i]);
next_packet_is_auth_tok_packet = 0;
}
} if (list_empty(&auth_tok_list)) {
printk(KERN_ERR "The lower file appears to be a non-encrypted " "eCryptfs file; this is not supported in this version " "of the eCryptfs kernel module\n");
rc = -EINVAL; goto out;
} /* auth_tok_list contains the set of authentication tokens * parsed from the metadata. We need to find a matching * authentication token that has the secret component(s) * necessary to decrypt the EFEK in the auth_tok parsed from * the metadata. There may be several potential matches, but
* just one will be sufficient to decrypt to get the FEK. */
find_next_matching_auth_tok:
found_auth_tok = 0;
list_for_each_entry(auth_tok_list_item, &auth_tok_list, list) {
candidate_auth_tok = &auth_tok_list_item->auth_tok; if (unlikely(ecryptfs_verbosity > 0)) {
ecryptfs_printk(KERN_DEBUG, "Considering candidate auth tok:\n");
ecryptfs_dump_auth_tok(candidate_auth_tok);
}
rc = ecryptfs_get_auth_tok_sig(&candidate_auth_tok_sig,
candidate_auth_tok); if (rc) {
printk(KERN_ERR "Unrecognized candidate auth tok type: [%d]\n",
candidate_auth_tok->token_type);
rc = -EINVAL; goto out_wipe_list;
}
rc = ecryptfs_find_auth_tok_for_sig(&auth_tok_key,
&matching_auth_tok,
crypt_stat->mount_crypt_stat,
candidate_auth_tok_sig); if (!rc) {
found_auth_tok = 1; goto found_matching_auth_tok;
}
} if (!found_auth_tok) {
ecryptfs_printk(KERN_ERR, "Could not find a usable " "authentication token\n");
rc = -EIO; goto out_wipe_list;
}
found_matching_auth_tok: if (candidate_auth_tok->token_type == ECRYPTFS_PRIVATE_KEY) {
memcpy(&(candidate_auth_tok->token.private_key),
&(matching_auth_tok->token.private_key), sizeof(struct ecryptfs_private_key));
up_write(&(auth_tok_key->sem));
key_put(auth_tok_key);
rc = decrypt_pki_encrypted_session_key(candidate_auth_tok,
crypt_stat);
} elseif (candidate_auth_tok->token_type == ECRYPTFS_PASSWORD) {
memcpy(&(candidate_auth_tok->token.password),
&(matching_auth_tok->token.password), sizeof(struct ecryptfs_password));
up_write(&(auth_tok_key->sem));
key_put(auth_tok_key);
rc = decrypt_passphrase_encrypted_session_key(
candidate_auth_tok, crypt_stat);
} else {
up_write(&(auth_tok_key->sem));
key_put(auth_tok_key);
rc = -EINVAL;
} if (rc) { struct ecryptfs_auth_tok_list_item *auth_tok_list_item_tmp;
ecryptfs_printk(KERN_WARNING, "Error decrypting the " "session key for authentication token with sig " "[%.*s]; rc = [%d]. Removing auth tok " "candidate from the list and searching for " "the next match.\n", ECRYPTFS_SIG_SIZE_HEX,
candidate_auth_tok_sig, rc);
list_for_each_entry_safe(auth_tok_list_item,
auth_tok_list_item_tmp,
&auth_tok_list, list) { if (candidate_auth_tok
== &auth_tok_list_item->auth_tok) {
list_del(&auth_tok_list_item->list);
kmem_cache_free(
ecryptfs_auth_tok_list_item_cache,
auth_tok_list_item); goto find_next_matching_auth_tok;
}
}
BUG();
}
rc = ecryptfs_compute_root_iv(crypt_stat); if (rc) {
ecryptfs_printk(KERN_ERR, "Error computing " "the root IV\n"); goto out_wipe_list;
}
rc = ecryptfs_init_crypt_ctx(crypt_stat); if (rc) {
ecryptfs_printk(KERN_ERR, "Error initializing crypto " "context for cipher [%s]; rc = [%d]\n",
crypt_stat->cipher, rc);
}
out_wipe_list:
wipe_auth_tok_list(&auth_tok_list);
out: return rc;
}
rc = write_tag_66_packet(auth_tok->token.private_key.signature,
ecryptfs_code_for_cipher_string(
crypt_stat->cipher,
crypt_stat->key_size),
crypt_stat, &payload, &payload_len);
up_write(&(auth_tok_key->sem));
key_put(auth_tok_key); if (rc) {
ecryptfs_printk(KERN_ERR, "Error generating tag 66 packet\n"); goto out;
}
rc = ecryptfs_send_message(payload, payload_len, &msg_ctx); if (rc) {
ecryptfs_printk(KERN_ERR, "Error sending message to " "ecryptfsd: %d\n", rc); goto out;
}
rc = ecryptfs_wait_for_response(msg_ctx, &msg); if (rc) {
ecryptfs_printk(KERN_ERR, "Failed to receive tag 67 packet " "from the user space daemon\n");
rc = -EIO; goto out;
}
rc = parse_tag_67_packet(key_rec, msg); if (rc)
ecryptfs_printk(KERN_ERR, "Error parsing tag 67 packet\n");
kfree(msg);
out:
kfree(payload); return rc;
} /** * write_tag_1_packet - Write an RFC2440-compatible tag 1 (public key) packet * @dest: Buffer into which to write the packet * @remaining_bytes: Maximum number of bytes that can be writtn * @auth_tok_key: The authentication token key to unlock and put when done with * @auth_tok * @auth_tok: The authentication token used for generating the tag 1 packet * @crypt_stat: The cryptographic context * @key_rec: The key record struct for the tag 1 packet * @packet_size: This function will write the number of bytes that end * up constituting the packet; set to zero on error * * Returns zero on success; non-zero on error.
*/ staticint
write_tag_1_packet(char *dest, size_t *remaining_bytes, struct key *auth_tok_key, struct ecryptfs_auth_tok *auth_tok, struct ecryptfs_crypt_stat *crypt_stat, struct ecryptfs_key_record *key_rec, size_t *packet_size)
{
size_t i;
size_t encrypted_session_key_valid = 0;
size_t packet_size_length;
size_t max_packet_size; int rc = 0;
(*packet_size) = 0;
ecryptfs_from_hex(key_rec->sig, auth_tok->token.private_key.signature,
ECRYPTFS_SIG_SIZE);
encrypted_session_key_valid = 0; for (i = 0; i < crypt_stat->key_size; i++)
encrypted_session_key_valid |=
auth_tok->session_key.encrypted_key[i]; if (encrypted_session_key_valid) {
memcpy(key_rec->enc_key,
auth_tok->session_key.encrypted_key,
auth_tok->session_key.encrypted_key_size);
up_write(&(auth_tok_key->sem));
key_put(auth_tok_key); goto encrypted_session_key_set;
} if (auth_tok->session_key.encrypted_key_size == 0)
auth_tok->session_key.encrypted_key_size =
auth_tok->token.private_key.key_size;
rc = pki_encrypt_session_key(auth_tok_key, auth_tok, crypt_stat,
key_rec); if (rc) {
printk(KERN_ERR "Failed to encrypt session key via a key " "module; rc = [%d]\n", rc); goto out;
} if (ecryptfs_verbosity > 0) {
ecryptfs_printk(KERN_DEBUG, "Encrypted key:\n");
ecryptfs_dump_hex(key_rec->enc_key, key_rec->enc_key_size);
}
encrypted_session_key_set: /* This format is inspired by OpenPGP; see RFC 2440
* packet tag 1 */
max_packet_size = (1 /* Tag 1 identifier */
+ 3 /* Max Tag 1 packet size */
+ 1 /* Version */
+ ECRYPTFS_SIG_SIZE /* Key identifier */
+ 1 /* Cipher identifier */
+ key_rec->enc_key_size); /* Encrypted key size */ if (max_packet_size > (*remaining_bytes)) {
printk(KERN_ERR "Packet length larger than maximum allowable; " "need up to [%td] bytes, but there are only [%td] " "available\n", max_packet_size, (*remaining_bytes));
rc = -EINVAL; goto out;
}
--> --------------------
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.