18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/**
38c2ecf20Sopenharmony_ci * eCryptfs: Linux filesystem encryption layer
48c2ecf20Sopenharmony_ci * In-kernel key management code.  Includes functions to parse and
58c2ecf20Sopenharmony_ci * write authentication token-related packets with the underlying
68c2ecf20Sopenharmony_ci * file.
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * Copyright (C) 2004-2006 International Business Machines Corp.
98c2ecf20Sopenharmony_ci *   Author(s): Michael A. Halcrow <mhalcrow@us.ibm.com>
108c2ecf20Sopenharmony_ci *              Michael C. Thompson <mcthomps@us.ibm.com>
118c2ecf20Sopenharmony_ci *              Trevor S. Highland <trevor.highland@gmail.com>
128c2ecf20Sopenharmony_ci */
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#include <crypto/hash.h>
158c2ecf20Sopenharmony_ci#include <crypto/skcipher.h>
168c2ecf20Sopenharmony_ci#include <linux/string.h>
178c2ecf20Sopenharmony_ci#include <linux/pagemap.h>
188c2ecf20Sopenharmony_ci#include <linux/key.h>
198c2ecf20Sopenharmony_ci#include <linux/random.h>
208c2ecf20Sopenharmony_ci#include <linux/scatterlist.h>
218c2ecf20Sopenharmony_ci#include <linux/slab.h>
228c2ecf20Sopenharmony_ci#include "ecryptfs_kernel.h"
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci/**
258c2ecf20Sopenharmony_ci * request_key returned an error instead of a valid key address;
268c2ecf20Sopenharmony_ci * determine the type of error, make appropriate log entries, and
278c2ecf20Sopenharmony_ci * return an error code.
288c2ecf20Sopenharmony_ci */
298c2ecf20Sopenharmony_cistatic int process_request_key_err(long err_code)
308c2ecf20Sopenharmony_ci{
318c2ecf20Sopenharmony_ci	int rc = 0;
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci	switch (err_code) {
348c2ecf20Sopenharmony_ci	case -ENOKEY:
358c2ecf20Sopenharmony_ci		ecryptfs_printk(KERN_WARNING, "No key\n");
368c2ecf20Sopenharmony_ci		rc = -ENOENT;
378c2ecf20Sopenharmony_ci		break;
388c2ecf20Sopenharmony_ci	case -EKEYEXPIRED:
398c2ecf20Sopenharmony_ci		ecryptfs_printk(KERN_WARNING, "Key expired\n");
408c2ecf20Sopenharmony_ci		rc = -ETIME;
418c2ecf20Sopenharmony_ci		break;
428c2ecf20Sopenharmony_ci	case -EKEYREVOKED:
438c2ecf20Sopenharmony_ci		ecryptfs_printk(KERN_WARNING, "Key revoked\n");
448c2ecf20Sopenharmony_ci		rc = -EINVAL;
458c2ecf20Sopenharmony_ci		break;
468c2ecf20Sopenharmony_ci	default:
478c2ecf20Sopenharmony_ci		ecryptfs_printk(KERN_WARNING, "Unknown error code: "
488c2ecf20Sopenharmony_ci				"[0x%.16lx]\n", err_code);
498c2ecf20Sopenharmony_ci		rc = -EINVAL;
508c2ecf20Sopenharmony_ci	}
518c2ecf20Sopenharmony_ci	return rc;
528c2ecf20Sopenharmony_ci}
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_cistatic int process_find_global_auth_tok_for_sig_err(int err_code)
558c2ecf20Sopenharmony_ci{
568c2ecf20Sopenharmony_ci	int rc = err_code;
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci	switch (err_code) {
598c2ecf20Sopenharmony_ci	case -ENOENT:
608c2ecf20Sopenharmony_ci		ecryptfs_printk(KERN_WARNING, "Missing auth tok\n");
618c2ecf20Sopenharmony_ci		break;
628c2ecf20Sopenharmony_ci	case -EINVAL:
638c2ecf20Sopenharmony_ci		ecryptfs_printk(KERN_WARNING, "Invalid auth tok\n");
648c2ecf20Sopenharmony_ci		break;
658c2ecf20Sopenharmony_ci	default:
668c2ecf20Sopenharmony_ci		rc = process_request_key_err(err_code);
678c2ecf20Sopenharmony_ci		break;
688c2ecf20Sopenharmony_ci	}
698c2ecf20Sopenharmony_ci	return rc;
708c2ecf20Sopenharmony_ci}
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci/**
738c2ecf20Sopenharmony_ci * ecryptfs_parse_packet_length
748c2ecf20Sopenharmony_ci * @data: Pointer to memory containing length at offset
758c2ecf20Sopenharmony_ci * @size: This function writes the decoded size to this memory
768c2ecf20Sopenharmony_ci *        address; zero on error
778c2ecf20Sopenharmony_ci * @length_size: The number of bytes occupied by the encoded length
788c2ecf20Sopenharmony_ci *
798c2ecf20Sopenharmony_ci * Returns zero on success; non-zero on error
808c2ecf20Sopenharmony_ci */
818c2ecf20Sopenharmony_ciint ecryptfs_parse_packet_length(unsigned char *data, size_t *size,
828c2ecf20Sopenharmony_ci				 size_t *length_size)
838c2ecf20Sopenharmony_ci{
848c2ecf20Sopenharmony_ci	int rc = 0;
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci	(*length_size) = 0;
878c2ecf20Sopenharmony_ci	(*size) = 0;
888c2ecf20Sopenharmony_ci	if (data[0] < 192) {
898c2ecf20Sopenharmony_ci		/* One-byte length */
908c2ecf20Sopenharmony_ci		(*size) = data[0];
918c2ecf20Sopenharmony_ci		(*length_size) = 1;
928c2ecf20Sopenharmony_ci	} else if (data[0] < 224) {
938c2ecf20Sopenharmony_ci		/* Two-byte length */
948c2ecf20Sopenharmony_ci		(*size) = (data[0] - 192) * 256;
958c2ecf20Sopenharmony_ci		(*size) += data[1] + 192;
968c2ecf20Sopenharmony_ci		(*length_size) = 2;
978c2ecf20Sopenharmony_ci	} else if (data[0] == 255) {
988c2ecf20Sopenharmony_ci		/* If support is added, adjust ECRYPTFS_MAX_PKT_LEN_SIZE */
998c2ecf20Sopenharmony_ci		ecryptfs_printk(KERN_ERR, "Five-byte packet length not "
1008c2ecf20Sopenharmony_ci				"supported\n");
1018c2ecf20Sopenharmony_ci		rc = -EINVAL;
1028c2ecf20Sopenharmony_ci		goto out;
1038c2ecf20Sopenharmony_ci	} else {
1048c2ecf20Sopenharmony_ci		ecryptfs_printk(KERN_ERR, "Error parsing packet length\n");
1058c2ecf20Sopenharmony_ci		rc = -EINVAL;
1068c2ecf20Sopenharmony_ci		goto out;
1078c2ecf20Sopenharmony_ci	}
1088c2ecf20Sopenharmony_ciout:
1098c2ecf20Sopenharmony_ci	return rc;
1108c2ecf20Sopenharmony_ci}
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci/**
1138c2ecf20Sopenharmony_ci * ecryptfs_write_packet_length
1148c2ecf20Sopenharmony_ci * @dest: The byte array target into which to write the length. Must
1158c2ecf20Sopenharmony_ci *        have at least ECRYPTFS_MAX_PKT_LEN_SIZE bytes allocated.
1168c2ecf20Sopenharmony_ci * @size: The length to write.
1178c2ecf20Sopenharmony_ci * @packet_size_length: The number of bytes used to encode the packet
1188c2ecf20Sopenharmony_ci *                      length is written to this address.
1198c2ecf20Sopenharmony_ci *
1208c2ecf20Sopenharmony_ci * Returns zero on success; non-zero on error.
1218c2ecf20Sopenharmony_ci */
1228c2ecf20Sopenharmony_ciint ecryptfs_write_packet_length(char *dest, size_t size,
1238c2ecf20Sopenharmony_ci				 size_t *packet_size_length)
1248c2ecf20Sopenharmony_ci{
1258c2ecf20Sopenharmony_ci	int rc = 0;
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci	if (size < 192) {
1288c2ecf20Sopenharmony_ci		dest[0] = size;
1298c2ecf20Sopenharmony_ci		(*packet_size_length) = 1;
1308c2ecf20Sopenharmony_ci	} else if (size < 65536) {
1318c2ecf20Sopenharmony_ci		dest[0] = (((size - 192) / 256) + 192);
1328c2ecf20Sopenharmony_ci		dest[1] = ((size - 192) % 256);
1338c2ecf20Sopenharmony_ci		(*packet_size_length) = 2;
1348c2ecf20Sopenharmony_ci	} else {
1358c2ecf20Sopenharmony_ci		/* If support is added, adjust ECRYPTFS_MAX_PKT_LEN_SIZE */
1368c2ecf20Sopenharmony_ci		rc = -EINVAL;
1378c2ecf20Sopenharmony_ci		ecryptfs_printk(KERN_WARNING,
1388c2ecf20Sopenharmony_ci				"Unsupported packet size: [%zd]\n", size);
1398c2ecf20Sopenharmony_ci	}
1408c2ecf20Sopenharmony_ci	return rc;
1418c2ecf20Sopenharmony_ci}
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_cistatic int
1448c2ecf20Sopenharmony_ciwrite_tag_64_packet(char *signature, struct ecryptfs_session_key *session_key,
1458c2ecf20Sopenharmony_ci		    char **packet, size_t *packet_len)
1468c2ecf20Sopenharmony_ci{
1478c2ecf20Sopenharmony_ci	size_t i = 0;
1488c2ecf20Sopenharmony_ci	size_t data_len;
1498c2ecf20Sopenharmony_ci	size_t packet_size_len;
1508c2ecf20Sopenharmony_ci	char *message;
1518c2ecf20Sopenharmony_ci	int rc;
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci	/*
1548c2ecf20Sopenharmony_ci	 *              ***** TAG 64 Packet Format *****
1558c2ecf20Sopenharmony_ci	 *    | Content Type                       | 1 byte       |
1568c2ecf20Sopenharmony_ci	 *    | Key Identifier Size                | 1 or 2 bytes |
1578c2ecf20Sopenharmony_ci	 *    | Key Identifier                     | arbitrary    |
1588c2ecf20Sopenharmony_ci	 *    | Encrypted File Encryption Key Size | 1 or 2 bytes |
1598c2ecf20Sopenharmony_ci	 *    | Encrypted File Encryption Key      | arbitrary    |
1608c2ecf20Sopenharmony_ci	 */
1618c2ecf20Sopenharmony_ci	data_len = (5 + ECRYPTFS_SIG_SIZE_HEX
1628c2ecf20Sopenharmony_ci		    + session_key->encrypted_key_size);
1638c2ecf20Sopenharmony_ci	*packet = kmalloc(data_len, GFP_KERNEL);
1648c2ecf20Sopenharmony_ci	message = *packet;
1658c2ecf20Sopenharmony_ci	if (!message) {
1668c2ecf20Sopenharmony_ci		ecryptfs_printk(KERN_ERR, "Unable to allocate memory\n");
1678c2ecf20Sopenharmony_ci		rc = -ENOMEM;
1688c2ecf20Sopenharmony_ci		goto out;
1698c2ecf20Sopenharmony_ci	}
1708c2ecf20Sopenharmony_ci	message[i++] = ECRYPTFS_TAG_64_PACKET_TYPE;
1718c2ecf20Sopenharmony_ci	rc = ecryptfs_write_packet_length(&message[i], ECRYPTFS_SIG_SIZE_HEX,
1728c2ecf20Sopenharmony_ci					  &packet_size_len);
1738c2ecf20Sopenharmony_ci	if (rc) {
1748c2ecf20Sopenharmony_ci		ecryptfs_printk(KERN_ERR, "Error generating tag 64 packet "
1758c2ecf20Sopenharmony_ci				"header; cannot generate packet length\n");
1768c2ecf20Sopenharmony_ci		goto out;
1778c2ecf20Sopenharmony_ci	}
1788c2ecf20Sopenharmony_ci	i += packet_size_len;
1798c2ecf20Sopenharmony_ci	memcpy(&message[i], signature, ECRYPTFS_SIG_SIZE_HEX);
1808c2ecf20Sopenharmony_ci	i += ECRYPTFS_SIG_SIZE_HEX;
1818c2ecf20Sopenharmony_ci	rc = ecryptfs_write_packet_length(&message[i],
1828c2ecf20Sopenharmony_ci					  session_key->encrypted_key_size,
1838c2ecf20Sopenharmony_ci					  &packet_size_len);
1848c2ecf20Sopenharmony_ci	if (rc) {
1858c2ecf20Sopenharmony_ci		ecryptfs_printk(KERN_ERR, "Error generating tag 64 packet "
1868c2ecf20Sopenharmony_ci				"header; cannot generate packet length\n");
1878c2ecf20Sopenharmony_ci		goto out;
1888c2ecf20Sopenharmony_ci	}
1898c2ecf20Sopenharmony_ci	i += packet_size_len;
1908c2ecf20Sopenharmony_ci	memcpy(&message[i], session_key->encrypted_key,
1918c2ecf20Sopenharmony_ci	       session_key->encrypted_key_size);
1928c2ecf20Sopenharmony_ci	i += session_key->encrypted_key_size;
1938c2ecf20Sopenharmony_ci	*packet_len = i;
1948c2ecf20Sopenharmony_ciout:
1958c2ecf20Sopenharmony_ci	return rc;
1968c2ecf20Sopenharmony_ci}
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_cistatic int
1998c2ecf20Sopenharmony_ciparse_tag_65_packet(struct ecryptfs_session_key *session_key, u8 *cipher_code,
2008c2ecf20Sopenharmony_ci		    struct ecryptfs_message *msg)
2018c2ecf20Sopenharmony_ci{
2028c2ecf20Sopenharmony_ci	size_t i = 0;
2038c2ecf20Sopenharmony_ci	char *data;
2048c2ecf20Sopenharmony_ci	size_t data_len;
2058c2ecf20Sopenharmony_ci	size_t m_size;
2068c2ecf20Sopenharmony_ci	size_t message_len;
2078c2ecf20Sopenharmony_ci	u16 checksum = 0;
2088c2ecf20Sopenharmony_ci	u16 expected_checksum = 0;
2098c2ecf20Sopenharmony_ci	int rc;
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci	/*
2128c2ecf20Sopenharmony_ci	 *              ***** TAG 65 Packet Format *****
2138c2ecf20Sopenharmony_ci	 *         | Content Type             | 1 byte       |
2148c2ecf20Sopenharmony_ci	 *         | Status Indicator         | 1 byte       |
2158c2ecf20Sopenharmony_ci	 *         | File Encryption Key Size | 1 or 2 bytes |
2168c2ecf20Sopenharmony_ci	 *         | File Encryption Key      | arbitrary    |
2178c2ecf20Sopenharmony_ci	 */
2188c2ecf20Sopenharmony_ci	message_len = msg->data_len;
2198c2ecf20Sopenharmony_ci	data = msg->data;
2208c2ecf20Sopenharmony_ci	if (message_len < 4) {
2218c2ecf20Sopenharmony_ci		rc = -EIO;
2228c2ecf20Sopenharmony_ci		goto out;
2238c2ecf20Sopenharmony_ci	}
2248c2ecf20Sopenharmony_ci	if (data[i++] != ECRYPTFS_TAG_65_PACKET_TYPE) {
2258c2ecf20Sopenharmony_ci		ecryptfs_printk(KERN_ERR, "Type should be ECRYPTFS_TAG_65\n");
2268c2ecf20Sopenharmony_ci		rc = -EIO;
2278c2ecf20Sopenharmony_ci		goto out;
2288c2ecf20Sopenharmony_ci	}
2298c2ecf20Sopenharmony_ci	if (data[i++]) {
2308c2ecf20Sopenharmony_ci		ecryptfs_printk(KERN_ERR, "Status indicator has non-zero value "
2318c2ecf20Sopenharmony_ci				"[%d]\n", data[i-1]);
2328c2ecf20Sopenharmony_ci		rc = -EIO;
2338c2ecf20Sopenharmony_ci		goto out;
2348c2ecf20Sopenharmony_ci	}
2358c2ecf20Sopenharmony_ci	rc = ecryptfs_parse_packet_length(&data[i], &m_size, &data_len);
2368c2ecf20Sopenharmony_ci	if (rc) {
2378c2ecf20Sopenharmony_ci		ecryptfs_printk(KERN_WARNING, "Error parsing packet length; "
2388c2ecf20Sopenharmony_ci				"rc = [%d]\n", rc);
2398c2ecf20Sopenharmony_ci		goto out;
2408c2ecf20Sopenharmony_ci	}
2418c2ecf20Sopenharmony_ci	i += data_len;
2428c2ecf20Sopenharmony_ci	if (message_len < (i + m_size)) {
2438c2ecf20Sopenharmony_ci		ecryptfs_printk(KERN_ERR, "The message received from ecryptfsd "
2448c2ecf20Sopenharmony_ci				"is shorter than expected\n");
2458c2ecf20Sopenharmony_ci		rc = -EIO;
2468c2ecf20Sopenharmony_ci		goto out;
2478c2ecf20Sopenharmony_ci	}
2488c2ecf20Sopenharmony_ci	if (m_size < 3) {
2498c2ecf20Sopenharmony_ci		ecryptfs_printk(KERN_ERR,
2508c2ecf20Sopenharmony_ci				"The decrypted key is not long enough to "
2518c2ecf20Sopenharmony_ci				"include a cipher code and checksum\n");
2528c2ecf20Sopenharmony_ci		rc = -EIO;
2538c2ecf20Sopenharmony_ci		goto out;
2548c2ecf20Sopenharmony_ci	}
2558c2ecf20Sopenharmony_ci	*cipher_code = data[i++];
2568c2ecf20Sopenharmony_ci	/* The decrypted key includes 1 byte cipher code and 2 byte checksum */
2578c2ecf20Sopenharmony_ci	session_key->decrypted_key_size = m_size - 3;
2588c2ecf20Sopenharmony_ci	if (session_key->decrypted_key_size > ECRYPTFS_MAX_KEY_BYTES) {
2598c2ecf20Sopenharmony_ci		ecryptfs_printk(KERN_ERR, "key_size [%d] larger than "
2608c2ecf20Sopenharmony_ci				"the maximum key size [%d]\n",
2618c2ecf20Sopenharmony_ci				session_key->decrypted_key_size,
2628c2ecf20Sopenharmony_ci				ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES);
2638c2ecf20Sopenharmony_ci		rc = -EIO;
2648c2ecf20Sopenharmony_ci		goto out;
2658c2ecf20Sopenharmony_ci	}
2668c2ecf20Sopenharmony_ci	memcpy(session_key->decrypted_key, &data[i],
2678c2ecf20Sopenharmony_ci	       session_key->decrypted_key_size);
2688c2ecf20Sopenharmony_ci	i += session_key->decrypted_key_size;
2698c2ecf20Sopenharmony_ci	expected_checksum += (unsigned char)(data[i++]) << 8;
2708c2ecf20Sopenharmony_ci	expected_checksum += (unsigned char)(data[i++]);
2718c2ecf20Sopenharmony_ci	for (i = 0; i < session_key->decrypted_key_size; i++)
2728c2ecf20Sopenharmony_ci		checksum += session_key->decrypted_key[i];
2738c2ecf20Sopenharmony_ci	if (expected_checksum != checksum) {
2748c2ecf20Sopenharmony_ci		ecryptfs_printk(KERN_ERR, "Invalid checksum for file "
2758c2ecf20Sopenharmony_ci				"encryption  key; expected [%x]; calculated "
2768c2ecf20Sopenharmony_ci				"[%x]\n", expected_checksum, checksum);
2778c2ecf20Sopenharmony_ci		rc = -EIO;
2788c2ecf20Sopenharmony_ci	}
2798c2ecf20Sopenharmony_ciout:
2808c2ecf20Sopenharmony_ci	return rc;
2818c2ecf20Sopenharmony_ci}
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_cistatic int
2858c2ecf20Sopenharmony_ciwrite_tag_66_packet(char *signature, u8 cipher_code,
2868c2ecf20Sopenharmony_ci		    struct ecryptfs_crypt_stat *crypt_stat, char **packet,
2878c2ecf20Sopenharmony_ci		    size_t *packet_len)
2888c2ecf20Sopenharmony_ci{
2898c2ecf20Sopenharmony_ci	size_t i = 0;
2908c2ecf20Sopenharmony_ci	size_t j;
2918c2ecf20Sopenharmony_ci	size_t data_len;
2928c2ecf20Sopenharmony_ci	size_t checksum = 0;
2938c2ecf20Sopenharmony_ci	size_t packet_size_len;
2948c2ecf20Sopenharmony_ci	char *message;
2958c2ecf20Sopenharmony_ci	int rc;
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci	/*
2988c2ecf20Sopenharmony_ci	 *              ***** TAG 66 Packet Format *****
2998c2ecf20Sopenharmony_ci	 *         | Content Type             | 1 byte       |
3008c2ecf20Sopenharmony_ci	 *         | Key Identifier Size      | 1 or 2 bytes |
3018c2ecf20Sopenharmony_ci	 *         | Key Identifier           | arbitrary    |
3028c2ecf20Sopenharmony_ci	 *         | File Encryption Key Size | 1 or 2 bytes |
3038c2ecf20Sopenharmony_ci	 *         | File Encryption Key      | arbitrary    |
3048c2ecf20Sopenharmony_ci	 */
3058c2ecf20Sopenharmony_ci	data_len = (5 + ECRYPTFS_SIG_SIZE_HEX + crypt_stat->key_size);
3068c2ecf20Sopenharmony_ci	*packet = kmalloc(data_len, GFP_KERNEL);
3078c2ecf20Sopenharmony_ci	message = *packet;
3088c2ecf20Sopenharmony_ci	if (!message) {
3098c2ecf20Sopenharmony_ci		ecryptfs_printk(KERN_ERR, "Unable to allocate memory\n");
3108c2ecf20Sopenharmony_ci		rc = -ENOMEM;
3118c2ecf20Sopenharmony_ci		goto out;
3128c2ecf20Sopenharmony_ci	}
3138c2ecf20Sopenharmony_ci	message[i++] = ECRYPTFS_TAG_66_PACKET_TYPE;
3148c2ecf20Sopenharmony_ci	rc = ecryptfs_write_packet_length(&message[i], ECRYPTFS_SIG_SIZE_HEX,
3158c2ecf20Sopenharmony_ci					  &packet_size_len);
3168c2ecf20Sopenharmony_ci	if (rc) {
3178c2ecf20Sopenharmony_ci		ecryptfs_printk(KERN_ERR, "Error generating tag 66 packet "
3188c2ecf20Sopenharmony_ci				"header; cannot generate packet length\n");
3198c2ecf20Sopenharmony_ci		goto out;
3208c2ecf20Sopenharmony_ci	}
3218c2ecf20Sopenharmony_ci	i += packet_size_len;
3228c2ecf20Sopenharmony_ci	memcpy(&message[i], signature, ECRYPTFS_SIG_SIZE_HEX);
3238c2ecf20Sopenharmony_ci	i += ECRYPTFS_SIG_SIZE_HEX;
3248c2ecf20Sopenharmony_ci	/* The encrypted key includes 1 byte cipher code and 2 byte checksum */
3258c2ecf20Sopenharmony_ci	rc = ecryptfs_write_packet_length(&message[i], crypt_stat->key_size + 3,
3268c2ecf20Sopenharmony_ci					  &packet_size_len);
3278c2ecf20Sopenharmony_ci	if (rc) {
3288c2ecf20Sopenharmony_ci		ecryptfs_printk(KERN_ERR, "Error generating tag 66 packet "
3298c2ecf20Sopenharmony_ci				"header; cannot generate packet length\n");
3308c2ecf20Sopenharmony_ci		goto out;
3318c2ecf20Sopenharmony_ci	}
3328c2ecf20Sopenharmony_ci	i += packet_size_len;
3338c2ecf20Sopenharmony_ci	message[i++] = cipher_code;
3348c2ecf20Sopenharmony_ci	memcpy(&message[i], crypt_stat->key, crypt_stat->key_size);
3358c2ecf20Sopenharmony_ci	i += crypt_stat->key_size;
3368c2ecf20Sopenharmony_ci	for (j = 0; j < crypt_stat->key_size; j++)
3378c2ecf20Sopenharmony_ci		checksum += crypt_stat->key[j];
3388c2ecf20Sopenharmony_ci	message[i++] = (checksum / 256) % 256;
3398c2ecf20Sopenharmony_ci	message[i++] = (checksum % 256);
3408c2ecf20Sopenharmony_ci	*packet_len = i;
3418c2ecf20Sopenharmony_ciout:
3428c2ecf20Sopenharmony_ci	return rc;
3438c2ecf20Sopenharmony_ci}
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_cistatic int
3468c2ecf20Sopenharmony_ciparse_tag_67_packet(struct ecryptfs_key_record *key_rec,
3478c2ecf20Sopenharmony_ci		    struct ecryptfs_message *msg)
3488c2ecf20Sopenharmony_ci{
3498c2ecf20Sopenharmony_ci	size_t i = 0;
3508c2ecf20Sopenharmony_ci	char *data;
3518c2ecf20Sopenharmony_ci	size_t data_len;
3528c2ecf20Sopenharmony_ci	size_t message_len;
3538c2ecf20Sopenharmony_ci	int rc;
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_ci	/*
3568c2ecf20Sopenharmony_ci	 *              ***** TAG 65 Packet Format *****
3578c2ecf20Sopenharmony_ci	 *    | Content Type                       | 1 byte       |
3588c2ecf20Sopenharmony_ci	 *    | Status Indicator                   | 1 byte       |
3598c2ecf20Sopenharmony_ci	 *    | Encrypted File Encryption Key Size | 1 or 2 bytes |
3608c2ecf20Sopenharmony_ci	 *    | Encrypted File Encryption Key      | arbitrary    |
3618c2ecf20Sopenharmony_ci	 */
3628c2ecf20Sopenharmony_ci	message_len = msg->data_len;
3638c2ecf20Sopenharmony_ci	data = msg->data;
3648c2ecf20Sopenharmony_ci	/* verify that everything through the encrypted FEK size is present */
3658c2ecf20Sopenharmony_ci	if (message_len < 4) {
3668c2ecf20Sopenharmony_ci		rc = -EIO;
3678c2ecf20Sopenharmony_ci		printk(KERN_ERR "%s: message_len is [%zd]; minimum acceptable "
3688c2ecf20Sopenharmony_ci		       "message length is [%d]\n", __func__, message_len, 4);
3698c2ecf20Sopenharmony_ci		goto out;
3708c2ecf20Sopenharmony_ci	}
3718c2ecf20Sopenharmony_ci	if (data[i++] != ECRYPTFS_TAG_67_PACKET_TYPE) {
3728c2ecf20Sopenharmony_ci		rc = -EIO;
3738c2ecf20Sopenharmony_ci		printk(KERN_ERR "%s: Type should be ECRYPTFS_TAG_67\n",
3748c2ecf20Sopenharmony_ci		       __func__);
3758c2ecf20Sopenharmony_ci		goto out;
3768c2ecf20Sopenharmony_ci	}
3778c2ecf20Sopenharmony_ci	if (data[i++]) {
3788c2ecf20Sopenharmony_ci		rc = -EIO;
3798c2ecf20Sopenharmony_ci		printk(KERN_ERR "%s: Status indicator has non zero "
3808c2ecf20Sopenharmony_ci		       "value [%d]\n", __func__, data[i-1]);
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_ci		goto out;
3838c2ecf20Sopenharmony_ci	}
3848c2ecf20Sopenharmony_ci	rc = ecryptfs_parse_packet_length(&data[i], &key_rec->enc_key_size,
3858c2ecf20Sopenharmony_ci					  &data_len);
3868c2ecf20Sopenharmony_ci	if (rc) {
3878c2ecf20Sopenharmony_ci		ecryptfs_printk(KERN_WARNING, "Error parsing packet length; "
3888c2ecf20Sopenharmony_ci				"rc = [%d]\n", rc);
3898c2ecf20Sopenharmony_ci		goto out;
3908c2ecf20Sopenharmony_ci	}
3918c2ecf20Sopenharmony_ci	i += data_len;
3928c2ecf20Sopenharmony_ci	if (message_len < (i + key_rec->enc_key_size)) {
3938c2ecf20Sopenharmony_ci		rc = -EIO;
3948c2ecf20Sopenharmony_ci		printk(KERN_ERR "%s: message_len [%zd]; max len is [%zd]\n",
3958c2ecf20Sopenharmony_ci		       __func__, message_len, (i + key_rec->enc_key_size));
3968c2ecf20Sopenharmony_ci		goto out;
3978c2ecf20Sopenharmony_ci	}
3988c2ecf20Sopenharmony_ci	if (key_rec->enc_key_size > ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES) {
3998c2ecf20Sopenharmony_ci		rc = -EIO;
4008c2ecf20Sopenharmony_ci		printk(KERN_ERR "%s: Encrypted key_size [%zd] larger than "
4018c2ecf20Sopenharmony_ci		       "the maximum key size [%d]\n", __func__,
4028c2ecf20Sopenharmony_ci		       key_rec->enc_key_size,
4038c2ecf20Sopenharmony_ci		       ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES);
4048c2ecf20Sopenharmony_ci		goto out;
4058c2ecf20Sopenharmony_ci	}
4068c2ecf20Sopenharmony_ci	memcpy(key_rec->enc_key, &data[i], key_rec->enc_key_size);
4078c2ecf20Sopenharmony_ciout:
4088c2ecf20Sopenharmony_ci	return rc;
4098c2ecf20Sopenharmony_ci}
4108c2ecf20Sopenharmony_ci
4118c2ecf20Sopenharmony_ci/**
4128c2ecf20Sopenharmony_ci * ecryptfs_verify_version
4138c2ecf20Sopenharmony_ci * @version: The version number to confirm
4148c2ecf20Sopenharmony_ci *
4158c2ecf20Sopenharmony_ci * Returns zero on good version; non-zero otherwise
4168c2ecf20Sopenharmony_ci */
4178c2ecf20Sopenharmony_cistatic int ecryptfs_verify_version(u16 version)
4188c2ecf20Sopenharmony_ci{
4198c2ecf20Sopenharmony_ci	int rc = 0;
4208c2ecf20Sopenharmony_ci	unsigned char major;
4218c2ecf20Sopenharmony_ci	unsigned char minor;
4228c2ecf20Sopenharmony_ci
4238c2ecf20Sopenharmony_ci	major = ((version >> 8) & 0xFF);
4248c2ecf20Sopenharmony_ci	minor = (version & 0xFF);
4258c2ecf20Sopenharmony_ci	if (major != ECRYPTFS_VERSION_MAJOR) {
4268c2ecf20Sopenharmony_ci		ecryptfs_printk(KERN_ERR, "Major version number mismatch. "
4278c2ecf20Sopenharmony_ci				"Expected [%d]; got [%d]\n",
4288c2ecf20Sopenharmony_ci				ECRYPTFS_VERSION_MAJOR, major);
4298c2ecf20Sopenharmony_ci		rc = -EINVAL;
4308c2ecf20Sopenharmony_ci		goto out;
4318c2ecf20Sopenharmony_ci	}
4328c2ecf20Sopenharmony_ci	if (minor != ECRYPTFS_VERSION_MINOR) {
4338c2ecf20Sopenharmony_ci		ecryptfs_printk(KERN_ERR, "Minor version number mismatch. "
4348c2ecf20Sopenharmony_ci				"Expected [%d]; got [%d]\n",
4358c2ecf20Sopenharmony_ci				ECRYPTFS_VERSION_MINOR, minor);
4368c2ecf20Sopenharmony_ci		rc = -EINVAL;
4378c2ecf20Sopenharmony_ci		goto out;
4388c2ecf20Sopenharmony_ci	}
4398c2ecf20Sopenharmony_ciout:
4408c2ecf20Sopenharmony_ci	return rc;
4418c2ecf20Sopenharmony_ci}
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_ci/**
4448c2ecf20Sopenharmony_ci * ecryptfs_verify_auth_tok_from_key
4458c2ecf20Sopenharmony_ci * @auth_tok_key: key containing the authentication token
4468c2ecf20Sopenharmony_ci * @auth_tok: authentication token
4478c2ecf20Sopenharmony_ci *
4488c2ecf20Sopenharmony_ci * Returns zero on valid auth tok; -EINVAL if the payload is invalid; or
4498c2ecf20Sopenharmony_ci * -EKEYREVOKED if the key was revoked before we acquired its semaphore.
4508c2ecf20Sopenharmony_ci */
4518c2ecf20Sopenharmony_cistatic int
4528c2ecf20Sopenharmony_ciecryptfs_verify_auth_tok_from_key(struct key *auth_tok_key,
4538c2ecf20Sopenharmony_ci				  struct ecryptfs_auth_tok **auth_tok)
4548c2ecf20Sopenharmony_ci{
4558c2ecf20Sopenharmony_ci	int rc = 0;
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_ci	(*auth_tok) = ecryptfs_get_key_payload_data(auth_tok_key);
4588c2ecf20Sopenharmony_ci	if (IS_ERR(*auth_tok)) {
4598c2ecf20Sopenharmony_ci		rc = PTR_ERR(*auth_tok);
4608c2ecf20Sopenharmony_ci		*auth_tok = NULL;
4618c2ecf20Sopenharmony_ci		goto out;
4628c2ecf20Sopenharmony_ci	}
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_ci	if (ecryptfs_verify_version((*auth_tok)->version)) {
4658c2ecf20Sopenharmony_ci		printk(KERN_ERR "Data structure version mismatch. Userspace "
4668c2ecf20Sopenharmony_ci		       "tools must match eCryptfs kernel module with major "
4678c2ecf20Sopenharmony_ci		       "version [%d] and minor version [%d]\n",
4688c2ecf20Sopenharmony_ci		       ECRYPTFS_VERSION_MAJOR, ECRYPTFS_VERSION_MINOR);
4698c2ecf20Sopenharmony_ci		rc = -EINVAL;
4708c2ecf20Sopenharmony_ci		goto out;
4718c2ecf20Sopenharmony_ci	}
4728c2ecf20Sopenharmony_ci	if ((*auth_tok)->token_type != ECRYPTFS_PASSWORD
4738c2ecf20Sopenharmony_ci	    && (*auth_tok)->token_type != ECRYPTFS_PRIVATE_KEY) {
4748c2ecf20Sopenharmony_ci		printk(KERN_ERR "Invalid auth_tok structure "
4758c2ecf20Sopenharmony_ci		       "returned from key query\n");
4768c2ecf20Sopenharmony_ci		rc = -EINVAL;
4778c2ecf20Sopenharmony_ci		goto out;
4788c2ecf20Sopenharmony_ci	}
4798c2ecf20Sopenharmony_ciout:
4808c2ecf20Sopenharmony_ci	return rc;
4818c2ecf20Sopenharmony_ci}
4828c2ecf20Sopenharmony_ci
4838c2ecf20Sopenharmony_cistatic int
4848c2ecf20Sopenharmony_ciecryptfs_find_global_auth_tok_for_sig(
4858c2ecf20Sopenharmony_ci	struct key **auth_tok_key,
4868c2ecf20Sopenharmony_ci	struct ecryptfs_auth_tok **auth_tok,
4878c2ecf20Sopenharmony_ci	struct ecryptfs_mount_crypt_stat *mount_crypt_stat, char *sig)
4888c2ecf20Sopenharmony_ci{
4898c2ecf20Sopenharmony_ci	struct ecryptfs_global_auth_tok *walker;
4908c2ecf20Sopenharmony_ci	int rc = 0;
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_ci	(*auth_tok_key) = NULL;
4938c2ecf20Sopenharmony_ci	(*auth_tok) = NULL;
4948c2ecf20Sopenharmony_ci	mutex_lock(&mount_crypt_stat->global_auth_tok_list_mutex);
4958c2ecf20Sopenharmony_ci	list_for_each_entry(walker,
4968c2ecf20Sopenharmony_ci			    &mount_crypt_stat->global_auth_tok_list,
4978c2ecf20Sopenharmony_ci			    mount_crypt_stat_list) {
4988c2ecf20Sopenharmony_ci		if (memcmp(walker->sig, sig, ECRYPTFS_SIG_SIZE_HEX))
4998c2ecf20Sopenharmony_ci			continue;
5008c2ecf20Sopenharmony_ci
5018c2ecf20Sopenharmony_ci		if (walker->flags & ECRYPTFS_AUTH_TOK_INVALID) {
5028c2ecf20Sopenharmony_ci			rc = -EINVAL;
5038c2ecf20Sopenharmony_ci			goto out;
5048c2ecf20Sopenharmony_ci		}
5058c2ecf20Sopenharmony_ci
5068c2ecf20Sopenharmony_ci		rc = key_validate(walker->global_auth_tok_key);
5078c2ecf20Sopenharmony_ci		if (rc) {
5088c2ecf20Sopenharmony_ci			if (rc == -EKEYEXPIRED)
5098c2ecf20Sopenharmony_ci				goto out;
5108c2ecf20Sopenharmony_ci			goto out_invalid_auth_tok;
5118c2ecf20Sopenharmony_ci		}
5128c2ecf20Sopenharmony_ci
5138c2ecf20Sopenharmony_ci		down_write(&(walker->global_auth_tok_key->sem));
5148c2ecf20Sopenharmony_ci		rc = ecryptfs_verify_auth_tok_from_key(
5158c2ecf20Sopenharmony_ci				walker->global_auth_tok_key, auth_tok);
5168c2ecf20Sopenharmony_ci		if (rc)
5178c2ecf20Sopenharmony_ci			goto out_invalid_auth_tok_unlock;
5188c2ecf20Sopenharmony_ci
5198c2ecf20Sopenharmony_ci		(*auth_tok_key) = walker->global_auth_tok_key;
5208c2ecf20Sopenharmony_ci		key_get(*auth_tok_key);
5218c2ecf20Sopenharmony_ci		goto out;
5228c2ecf20Sopenharmony_ci	}
5238c2ecf20Sopenharmony_ci	rc = -ENOENT;
5248c2ecf20Sopenharmony_ci	goto out;
5258c2ecf20Sopenharmony_ciout_invalid_auth_tok_unlock:
5268c2ecf20Sopenharmony_ci	up_write(&(walker->global_auth_tok_key->sem));
5278c2ecf20Sopenharmony_ciout_invalid_auth_tok:
5288c2ecf20Sopenharmony_ci	printk(KERN_WARNING "Invalidating auth tok with sig = [%s]\n", sig);
5298c2ecf20Sopenharmony_ci	walker->flags |= ECRYPTFS_AUTH_TOK_INVALID;
5308c2ecf20Sopenharmony_ci	key_put(walker->global_auth_tok_key);
5318c2ecf20Sopenharmony_ci	walker->global_auth_tok_key = NULL;
5328c2ecf20Sopenharmony_ciout:
5338c2ecf20Sopenharmony_ci	mutex_unlock(&mount_crypt_stat->global_auth_tok_list_mutex);
5348c2ecf20Sopenharmony_ci	return rc;
5358c2ecf20Sopenharmony_ci}
5368c2ecf20Sopenharmony_ci
5378c2ecf20Sopenharmony_ci/**
5388c2ecf20Sopenharmony_ci * ecryptfs_find_auth_tok_for_sig
5398c2ecf20Sopenharmony_ci * @auth_tok: Set to the matching auth_tok; NULL if not found
5408c2ecf20Sopenharmony_ci * @crypt_stat: inode crypt_stat crypto context
5418c2ecf20Sopenharmony_ci * @sig: Sig of auth_tok to find
5428c2ecf20Sopenharmony_ci *
5438c2ecf20Sopenharmony_ci * For now, this function simply looks at the registered auth_tok's
5448c2ecf20Sopenharmony_ci * linked off the mount_crypt_stat, so all the auth_toks that can be
5458c2ecf20Sopenharmony_ci * used must be registered at mount time. This function could
5468c2ecf20Sopenharmony_ci * potentially try a lot harder to find auth_tok's (e.g., by calling
5478c2ecf20Sopenharmony_ci * out to ecryptfsd to dynamically retrieve an auth_tok object) so
5488c2ecf20Sopenharmony_ci * that static registration of auth_tok's will no longer be necessary.
5498c2ecf20Sopenharmony_ci *
5508c2ecf20Sopenharmony_ci * Returns zero on no error; non-zero on error
5518c2ecf20Sopenharmony_ci */
5528c2ecf20Sopenharmony_cistatic int
5538c2ecf20Sopenharmony_ciecryptfs_find_auth_tok_for_sig(
5548c2ecf20Sopenharmony_ci	struct key **auth_tok_key,
5558c2ecf20Sopenharmony_ci	struct ecryptfs_auth_tok **auth_tok,
5568c2ecf20Sopenharmony_ci	struct ecryptfs_mount_crypt_stat *mount_crypt_stat,
5578c2ecf20Sopenharmony_ci	char *sig)
5588c2ecf20Sopenharmony_ci{
5598c2ecf20Sopenharmony_ci	int rc = 0;
5608c2ecf20Sopenharmony_ci
5618c2ecf20Sopenharmony_ci	rc = ecryptfs_find_global_auth_tok_for_sig(auth_tok_key, auth_tok,
5628c2ecf20Sopenharmony_ci						   mount_crypt_stat, sig);
5638c2ecf20Sopenharmony_ci	if (rc == -ENOENT) {
5648c2ecf20Sopenharmony_ci		/* if the flag ECRYPTFS_GLOBAL_MOUNT_AUTH_TOK_ONLY is set in the
5658c2ecf20Sopenharmony_ci		 * mount_crypt_stat structure, we prevent to use auth toks that
5668c2ecf20Sopenharmony_ci		 * are not inserted through the ecryptfs_add_global_auth_tok
5678c2ecf20Sopenharmony_ci		 * function.
5688c2ecf20Sopenharmony_ci		 */
5698c2ecf20Sopenharmony_ci		if (mount_crypt_stat->flags
5708c2ecf20Sopenharmony_ci				& ECRYPTFS_GLOBAL_MOUNT_AUTH_TOK_ONLY)
5718c2ecf20Sopenharmony_ci			return -EINVAL;
5728c2ecf20Sopenharmony_ci
5738c2ecf20Sopenharmony_ci		rc = ecryptfs_keyring_auth_tok_for_sig(auth_tok_key, auth_tok,
5748c2ecf20Sopenharmony_ci						       sig);
5758c2ecf20Sopenharmony_ci	}
5768c2ecf20Sopenharmony_ci	return rc;
5778c2ecf20Sopenharmony_ci}
5788c2ecf20Sopenharmony_ci
5798c2ecf20Sopenharmony_ci/**
5808c2ecf20Sopenharmony_ci * write_tag_70_packet can gobble a lot of stack space. We stuff most
5818c2ecf20Sopenharmony_ci * of the function's parameters in a kmalloc'd struct to help reduce
5828c2ecf20Sopenharmony_ci * eCryptfs' overall stack usage.
5838c2ecf20Sopenharmony_ci */
5848c2ecf20Sopenharmony_cistruct ecryptfs_write_tag_70_packet_silly_stack {
5858c2ecf20Sopenharmony_ci	u8 cipher_code;
5868c2ecf20Sopenharmony_ci	size_t max_packet_size;
5878c2ecf20Sopenharmony_ci	size_t packet_size_len;
5888c2ecf20Sopenharmony_ci	size_t block_aligned_filename_size;
5898c2ecf20Sopenharmony_ci	size_t block_size;
5908c2ecf20Sopenharmony_ci	size_t i;
5918c2ecf20Sopenharmony_ci	size_t j;
5928c2ecf20Sopenharmony_ci	size_t num_rand_bytes;
5938c2ecf20Sopenharmony_ci	struct mutex *tfm_mutex;
5948c2ecf20Sopenharmony_ci	char *block_aligned_filename;
5958c2ecf20Sopenharmony_ci	struct ecryptfs_auth_tok *auth_tok;
5968c2ecf20Sopenharmony_ci	struct scatterlist src_sg[2];
5978c2ecf20Sopenharmony_ci	struct scatterlist dst_sg[2];
5988c2ecf20Sopenharmony_ci	struct crypto_skcipher *skcipher_tfm;
5998c2ecf20Sopenharmony_ci	struct skcipher_request *skcipher_req;
6008c2ecf20Sopenharmony_ci	char iv[ECRYPTFS_MAX_IV_BYTES];
6018c2ecf20Sopenharmony_ci	char hash[ECRYPTFS_TAG_70_DIGEST_SIZE];
6028c2ecf20Sopenharmony_ci	char tmp_hash[ECRYPTFS_TAG_70_DIGEST_SIZE];
6038c2ecf20Sopenharmony_ci	struct crypto_shash *hash_tfm;
6048c2ecf20Sopenharmony_ci	struct shash_desc *hash_desc;
6058c2ecf20Sopenharmony_ci};
6068c2ecf20Sopenharmony_ci
6078c2ecf20Sopenharmony_ci/**
6088c2ecf20Sopenharmony_ci * write_tag_70_packet - Write encrypted filename (EFN) packet against FNEK
6098c2ecf20Sopenharmony_ci * @filename: NULL-terminated filename string
6108c2ecf20Sopenharmony_ci *
6118c2ecf20Sopenharmony_ci * This is the simplest mechanism for achieving filename encryption in
6128c2ecf20Sopenharmony_ci * eCryptfs. It encrypts the given filename with the mount-wide
6138c2ecf20Sopenharmony_ci * filename encryption key (FNEK) and stores it in a packet to @dest,
6148c2ecf20Sopenharmony_ci * which the callee will encode and write directly into the dentry
6158c2ecf20Sopenharmony_ci * name.
6168c2ecf20Sopenharmony_ci */
6178c2ecf20Sopenharmony_ciint
6188c2ecf20Sopenharmony_ciecryptfs_write_tag_70_packet(char *dest, size_t *remaining_bytes,
6198c2ecf20Sopenharmony_ci			     size_t *packet_size,
6208c2ecf20Sopenharmony_ci			     struct ecryptfs_mount_crypt_stat *mount_crypt_stat,
6218c2ecf20Sopenharmony_ci			     char *filename, size_t filename_size)
6228c2ecf20Sopenharmony_ci{
6238c2ecf20Sopenharmony_ci	struct ecryptfs_write_tag_70_packet_silly_stack *s;
6248c2ecf20Sopenharmony_ci	struct key *auth_tok_key = NULL;
6258c2ecf20Sopenharmony_ci	int rc = 0;
6268c2ecf20Sopenharmony_ci
6278c2ecf20Sopenharmony_ci	s = kzalloc(sizeof(*s), GFP_KERNEL);
6288c2ecf20Sopenharmony_ci	if (!s)
6298c2ecf20Sopenharmony_ci		return -ENOMEM;
6308c2ecf20Sopenharmony_ci
6318c2ecf20Sopenharmony_ci	(*packet_size) = 0;
6328c2ecf20Sopenharmony_ci	rc = ecryptfs_find_auth_tok_for_sig(
6338c2ecf20Sopenharmony_ci		&auth_tok_key,
6348c2ecf20Sopenharmony_ci		&s->auth_tok, mount_crypt_stat,
6358c2ecf20Sopenharmony_ci		mount_crypt_stat->global_default_fnek_sig);
6368c2ecf20Sopenharmony_ci	if (rc) {
6378c2ecf20Sopenharmony_ci		printk(KERN_ERR "%s: Error attempting to find auth tok for "
6388c2ecf20Sopenharmony_ci		       "fnek sig [%s]; rc = [%d]\n", __func__,
6398c2ecf20Sopenharmony_ci		       mount_crypt_stat->global_default_fnek_sig, rc);
6408c2ecf20Sopenharmony_ci		goto out;
6418c2ecf20Sopenharmony_ci	}
6428c2ecf20Sopenharmony_ci	rc = ecryptfs_get_tfm_and_mutex_for_cipher_name(
6438c2ecf20Sopenharmony_ci		&s->skcipher_tfm,
6448c2ecf20Sopenharmony_ci		&s->tfm_mutex, mount_crypt_stat->global_default_fn_cipher_name);
6458c2ecf20Sopenharmony_ci	if (unlikely(rc)) {
6468c2ecf20Sopenharmony_ci		printk(KERN_ERR "Internal error whilst attempting to get "
6478c2ecf20Sopenharmony_ci		       "tfm and mutex for cipher name [%s]; rc = [%d]\n",
6488c2ecf20Sopenharmony_ci		       mount_crypt_stat->global_default_fn_cipher_name, rc);
6498c2ecf20Sopenharmony_ci		goto out;
6508c2ecf20Sopenharmony_ci	}
6518c2ecf20Sopenharmony_ci	mutex_lock(s->tfm_mutex);
6528c2ecf20Sopenharmony_ci	s->block_size = crypto_skcipher_blocksize(s->skcipher_tfm);
6538c2ecf20Sopenharmony_ci	/* Plus one for the \0 separator between the random prefix
6548c2ecf20Sopenharmony_ci	 * and the plaintext filename */
6558c2ecf20Sopenharmony_ci	s->num_rand_bytes = (ECRYPTFS_FILENAME_MIN_RANDOM_PREPEND_BYTES + 1);
6568c2ecf20Sopenharmony_ci	s->block_aligned_filename_size = (s->num_rand_bytes + filename_size);
6578c2ecf20Sopenharmony_ci	if ((s->block_aligned_filename_size % s->block_size) != 0) {
6588c2ecf20Sopenharmony_ci		s->num_rand_bytes += (s->block_size
6598c2ecf20Sopenharmony_ci				      - (s->block_aligned_filename_size
6608c2ecf20Sopenharmony_ci					 % s->block_size));
6618c2ecf20Sopenharmony_ci		s->block_aligned_filename_size = (s->num_rand_bytes
6628c2ecf20Sopenharmony_ci						  + filename_size);
6638c2ecf20Sopenharmony_ci	}
6648c2ecf20Sopenharmony_ci	/* Octet 0: Tag 70 identifier
6658c2ecf20Sopenharmony_ci	 * Octets 1-N1: Tag 70 packet size (includes cipher identifier
6668c2ecf20Sopenharmony_ci	 *              and block-aligned encrypted filename size)
6678c2ecf20Sopenharmony_ci	 * Octets N1-N2: FNEK sig (ECRYPTFS_SIG_SIZE)
6688c2ecf20Sopenharmony_ci	 * Octet N2-N3: Cipher identifier (1 octet)
6698c2ecf20Sopenharmony_ci	 * Octets N3-N4: Block-aligned encrypted filename
6708c2ecf20Sopenharmony_ci	 *  - Consists of a minimum number of random characters, a \0
6718c2ecf20Sopenharmony_ci	 *    separator, and then the filename */
6728c2ecf20Sopenharmony_ci	s->max_packet_size = (ECRYPTFS_TAG_70_MAX_METADATA_SIZE
6738c2ecf20Sopenharmony_ci			      + s->block_aligned_filename_size);
6748c2ecf20Sopenharmony_ci	if (!dest) {
6758c2ecf20Sopenharmony_ci		(*packet_size) = s->max_packet_size;
6768c2ecf20Sopenharmony_ci		goto out_unlock;
6778c2ecf20Sopenharmony_ci	}
6788c2ecf20Sopenharmony_ci	if (s->max_packet_size > (*remaining_bytes)) {
6798c2ecf20Sopenharmony_ci		printk(KERN_WARNING "%s: Require [%zd] bytes to write; only "
6808c2ecf20Sopenharmony_ci		       "[%zd] available\n", __func__, s->max_packet_size,
6818c2ecf20Sopenharmony_ci		       (*remaining_bytes));
6828c2ecf20Sopenharmony_ci		rc = -EINVAL;
6838c2ecf20Sopenharmony_ci		goto out_unlock;
6848c2ecf20Sopenharmony_ci	}
6858c2ecf20Sopenharmony_ci
6868c2ecf20Sopenharmony_ci	s->skcipher_req = skcipher_request_alloc(s->skcipher_tfm, GFP_KERNEL);
6878c2ecf20Sopenharmony_ci	if (!s->skcipher_req) {
6888c2ecf20Sopenharmony_ci		printk(KERN_ERR "%s: Out of kernel memory whilst attempting to "
6898c2ecf20Sopenharmony_ci		       "skcipher_request_alloc for %s\n", __func__,
6908c2ecf20Sopenharmony_ci		       crypto_skcipher_driver_name(s->skcipher_tfm));
6918c2ecf20Sopenharmony_ci		rc = -ENOMEM;
6928c2ecf20Sopenharmony_ci		goto out_unlock;
6938c2ecf20Sopenharmony_ci	}
6948c2ecf20Sopenharmony_ci
6958c2ecf20Sopenharmony_ci	skcipher_request_set_callback(s->skcipher_req,
6968c2ecf20Sopenharmony_ci				      CRYPTO_TFM_REQ_MAY_SLEEP, NULL, NULL);
6978c2ecf20Sopenharmony_ci
6988c2ecf20Sopenharmony_ci	s->block_aligned_filename = kzalloc(s->block_aligned_filename_size,
6998c2ecf20Sopenharmony_ci					    GFP_KERNEL);
7008c2ecf20Sopenharmony_ci	if (!s->block_aligned_filename) {
7018c2ecf20Sopenharmony_ci		rc = -ENOMEM;
7028c2ecf20Sopenharmony_ci		goto out_unlock;
7038c2ecf20Sopenharmony_ci	}
7048c2ecf20Sopenharmony_ci	dest[s->i++] = ECRYPTFS_TAG_70_PACKET_TYPE;
7058c2ecf20Sopenharmony_ci	rc = ecryptfs_write_packet_length(&dest[s->i],
7068c2ecf20Sopenharmony_ci					  (ECRYPTFS_SIG_SIZE
7078c2ecf20Sopenharmony_ci					   + 1 /* Cipher code */
7088c2ecf20Sopenharmony_ci					   + s->block_aligned_filename_size),
7098c2ecf20Sopenharmony_ci					  &s->packet_size_len);
7108c2ecf20Sopenharmony_ci	if (rc) {
7118c2ecf20Sopenharmony_ci		printk(KERN_ERR "%s: Error generating tag 70 packet "
7128c2ecf20Sopenharmony_ci		       "header; cannot generate packet length; rc = [%d]\n",
7138c2ecf20Sopenharmony_ci		       __func__, rc);
7148c2ecf20Sopenharmony_ci		goto out_free_unlock;
7158c2ecf20Sopenharmony_ci	}
7168c2ecf20Sopenharmony_ci	s->i += s->packet_size_len;
7178c2ecf20Sopenharmony_ci	ecryptfs_from_hex(&dest[s->i],
7188c2ecf20Sopenharmony_ci			  mount_crypt_stat->global_default_fnek_sig,
7198c2ecf20Sopenharmony_ci			  ECRYPTFS_SIG_SIZE);
7208c2ecf20Sopenharmony_ci	s->i += ECRYPTFS_SIG_SIZE;
7218c2ecf20Sopenharmony_ci	s->cipher_code = ecryptfs_code_for_cipher_string(
7228c2ecf20Sopenharmony_ci		mount_crypt_stat->global_default_fn_cipher_name,
7238c2ecf20Sopenharmony_ci		mount_crypt_stat->global_default_fn_cipher_key_bytes);
7248c2ecf20Sopenharmony_ci	if (s->cipher_code == 0) {
7258c2ecf20Sopenharmony_ci		printk(KERN_WARNING "%s: Unable to generate code for "
7268c2ecf20Sopenharmony_ci		       "cipher [%s] with key bytes [%zd]\n", __func__,
7278c2ecf20Sopenharmony_ci		       mount_crypt_stat->global_default_fn_cipher_name,
7288c2ecf20Sopenharmony_ci		       mount_crypt_stat->global_default_fn_cipher_key_bytes);
7298c2ecf20Sopenharmony_ci		rc = -EINVAL;
7308c2ecf20Sopenharmony_ci		goto out_free_unlock;
7318c2ecf20Sopenharmony_ci	}
7328c2ecf20Sopenharmony_ci	dest[s->i++] = s->cipher_code;
7338c2ecf20Sopenharmony_ci	/* TODO: Support other key modules than passphrase for
7348c2ecf20Sopenharmony_ci	 * filename encryption */
7358c2ecf20Sopenharmony_ci	if (s->auth_tok->token_type != ECRYPTFS_PASSWORD) {
7368c2ecf20Sopenharmony_ci		rc = -EOPNOTSUPP;
7378c2ecf20Sopenharmony_ci		printk(KERN_INFO "%s: Filename encryption only supports "
7388c2ecf20Sopenharmony_ci		       "password tokens\n", __func__);
7398c2ecf20Sopenharmony_ci		goto out_free_unlock;
7408c2ecf20Sopenharmony_ci	}
7418c2ecf20Sopenharmony_ci	s->hash_tfm = crypto_alloc_shash(ECRYPTFS_TAG_70_DIGEST, 0, 0);
7428c2ecf20Sopenharmony_ci	if (IS_ERR(s->hash_tfm)) {
7438c2ecf20Sopenharmony_ci			rc = PTR_ERR(s->hash_tfm);
7448c2ecf20Sopenharmony_ci			printk(KERN_ERR "%s: Error attempting to "
7458c2ecf20Sopenharmony_ci			       "allocate hash crypto context; rc = [%d]\n",
7468c2ecf20Sopenharmony_ci			       __func__, rc);
7478c2ecf20Sopenharmony_ci			goto out_free_unlock;
7488c2ecf20Sopenharmony_ci	}
7498c2ecf20Sopenharmony_ci
7508c2ecf20Sopenharmony_ci	s->hash_desc = kmalloc(sizeof(*s->hash_desc) +
7518c2ecf20Sopenharmony_ci			       crypto_shash_descsize(s->hash_tfm), GFP_KERNEL);
7528c2ecf20Sopenharmony_ci	if (!s->hash_desc) {
7538c2ecf20Sopenharmony_ci		rc = -ENOMEM;
7548c2ecf20Sopenharmony_ci		goto out_release_free_unlock;
7558c2ecf20Sopenharmony_ci	}
7568c2ecf20Sopenharmony_ci
7578c2ecf20Sopenharmony_ci	s->hash_desc->tfm = s->hash_tfm;
7588c2ecf20Sopenharmony_ci
7598c2ecf20Sopenharmony_ci	rc = crypto_shash_digest(s->hash_desc,
7608c2ecf20Sopenharmony_ci				 (u8 *)s->auth_tok->token.password.session_key_encryption_key,
7618c2ecf20Sopenharmony_ci				 s->auth_tok->token.password.session_key_encryption_key_bytes,
7628c2ecf20Sopenharmony_ci				 s->hash);
7638c2ecf20Sopenharmony_ci	if (rc) {
7648c2ecf20Sopenharmony_ci		printk(KERN_ERR
7658c2ecf20Sopenharmony_ci		       "%s: Error computing crypto hash; rc = [%d]\n",
7668c2ecf20Sopenharmony_ci		       __func__, rc);
7678c2ecf20Sopenharmony_ci		goto out_release_free_unlock;
7688c2ecf20Sopenharmony_ci	}
7698c2ecf20Sopenharmony_ci	for (s->j = 0; s->j < (s->num_rand_bytes - 1); s->j++) {
7708c2ecf20Sopenharmony_ci		s->block_aligned_filename[s->j] =
7718c2ecf20Sopenharmony_ci			s->hash[(s->j % ECRYPTFS_TAG_70_DIGEST_SIZE)];
7728c2ecf20Sopenharmony_ci		if ((s->j % ECRYPTFS_TAG_70_DIGEST_SIZE)
7738c2ecf20Sopenharmony_ci		    == (ECRYPTFS_TAG_70_DIGEST_SIZE - 1)) {
7748c2ecf20Sopenharmony_ci			rc = crypto_shash_digest(s->hash_desc, (u8 *)s->hash,
7758c2ecf20Sopenharmony_ci						ECRYPTFS_TAG_70_DIGEST_SIZE,
7768c2ecf20Sopenharmony_ci						s->tmp_hash);
7778c2ecf20Sopenharmony_ci			if (rc) {
7788c2ecf20Sopenharmony_ci				printk(KERN_ERR
7798c2ecf20Sopenharmony_ci				       "%s: Error computing crypto hash; "
7808c2ecf20Sopenharmony_ci				       "rc = [%d]\n", __func__, rc);
7818c2ecf20Sopenharmony_ci				goto out_release_free_unlock;
7828c2ecf20Sopenharmony_ci			}
7838c2ecf20Sopenharmony_ci			memcpy(s->hash, s->tmp_hash,
7848c2ecf20Sopenharmony_ci			       ECRYPTFS_TAG_70_DIGEST_SIZE);
7858c2ecf20Sopenharmony_ci		}
7868c2ecf20Sopenharmony_ci		if (s->block_aligned_filename[s->j] == '\0')
7878c2ecf20Sopenharmony_ci			s->block_aligned_filename[s->j] = ECRYPTFS_NON_NULL;
7888c2ecf20Sopenharmony_ci	}
7898c2ecf20Sopenharmony_ci	memcpy(&s->block_aligned_filename[s->num_rand_bytes], filename,
7908c2ecf20Sopenharmony_ci	       filename_size);
7918c2ecf20Sopenharmony_ci	rc = virt_to_scatterlist(s->block_aligned_filename,
7928c2ecf20Sopenharmony_ci				 s->block_aligned_filename_size, s->src_sg, 2);
7938c2ecf20Sopenharmony_ci	if (rc < 1) {
7948c2ecf20Sopenharmony_ci		printk(KERN_ERR "%s: Internal error whilst attempting to "
7958c2ecf20Sopenharmony_ci		       "convert filename memory to scatterlist; rc = [%d]. "
7968c2ecf20Sopenharmony_ci		       "block_aligned_filename_size = [%zd]\n", __func__, rc,
7978c2ecf20Sopenharmony_ci		       s->block_aligned_filename_size);
7988c2ecf20Sopenharmony_ci		goto out_release_free_unlock;
7998c2ecf20Sopenharmony_ci	}
8008c2ecf20Sopenharmony_ci	rc = virt_to_scatterlist(&dest[s->i], s->block_aligned_filename_size,
8018c2ecf20Sopenharmony_ci				 s->dst_sg, 2);
8028c2ecf20Sopenharmony_ci	if (rc < 1) {
8038c2ecf20Sopenharmony_ci		printk(KERN_ERR "%s: Internal error whilst attempting to "
8048c2ecf20Sopenharmony_ci		       "convert encrypted filename memory to scatterlist; "
8058c2ecf20Sopenharmony_ci		       "rc = [%d]. block_aligned_filename_size = [%zd]\n",
8068c2ecf20Sopenharmony_ci		       __func__, rc, s->block_aligned_filename_size);
8078c2ecf20Sopenharmony_ci		goto out_release_free_unlock;
8088c2ecf20Sopenharmony_ci	}
8098c2ecf20Sopenharmony_ci	/* The characters in the first block effectively do the job
8108c2ecf20Sopenharmony_ci	 * of the IV here, so we just use 0's for the IV. Note the
8118c2ecf20Sopenharmony_ci	 * constraint that ECRYPTFS_FILENAME_MIN_RANDOM_PREPEND_BYTES
8128c2ecf20Sopenharmony_ci	 * >= ECRYPTFS_MAX_IV_BYTES. */
8138c2ecf20Sopenharmony_ci	rc = crypto_skcipher_setkey(
8148c2ecf20Sopenharmony_ci		s->skcipher_tfm,
8158c2ecf20Sopenharmony_ci		s->auth_tok->token.password.session_key_encryption_key,
8168c2ecf20Sopenharmony_ci		mount_crypt_stat->global_default_fn_cipher_key_bytes);
8178c2ecf20Sopenharmony_ci	if (rc < 0) {
8188c2ecf20Sopenharmony_ci		printk(KERN_ERR "%s: Error setting key for crypto context; "
8198c2ecf20Sopenharmony_ci		       "rc = [%d]. s->auth_tok->token.password.session_key_"
8208c2ecf20Sopenharmony_ci		       "encryption_key = [0x%p]; mount_crypt_stat->"
8218c2ecf20Sopenharmony_ci		       "global_default_fn_cipher_key_bytes = [%zd]\n", __func__,
8228c2ecf20Sopenharmony_ci		       rc,
8238c2ecf20Sopenharmony_ci		       s->auth_tok->token.password.session_key_encryption_key,
8248c2ecf20Sopenharmony_ci		       mount_crypt_stat->global_default_fn_cipher_key_bytes);
8258c2ecf20Sopenharmony_ci		goto out_release_free_unlock;
8268c2ecf20Sopenharmony_ci	}
8278c2ecf20Sopenharmony_ci	skcipher_request_set_crypt(s->skcipher_req, s->src_sg, s->dst_sg,
8288c2ecf20Sopenharmony_ci				   s->block_aligned_filename_size, s->iv);
8298c2ecf20Sopenharmony_ci	rc = crypto_skcipher_encrypt(s->skcipher_req);
8308c2ecf20Sopenharmony_ci	if (rc) {
8318c2ecf20Sopenharmony_ci		printk(KERN_ERR "%s: Error attempting to encrypt filename; "
8328c2ecf20Sopenharmony_ci		       "rc = [%d]\n", __func__, rc);
8338c2ecf20Sopenharmony_ci		goto out_release_free_unlock;
8348c2ecf20Sopenharmony_ci	}
8358c2ecf20Sopenharmony_ci	s->i += s->block_aligned_filename_size;
8368c2ecf20Sopenharmony_ci	(*packet_size) = s->i;
8378c2ecf20Sopenharmony_ci	(*remaining_bytes) -= (*packet_size);
8388c2ecf20Sopenharmony_ciout_release_free_unlock:
8398c2ecf20Sopenharmony_ci	crypto_free_shash(s->hash_tfm);
8408c2ecf20Sopenharmony_ciout_free_unlock:
8418c2ecf20Sopenharmony_ci	kfree_sensitive(s->block_aligned_filename);
8428c2ecf20Sopenharmony_ciout_unlock:
8438c2ecf20Sopenharmony_ci	mutex_unlock(s->tfm_mutex);
8448c2ecf20Sopenharmony_ciout:
8458c2ecf20Sopenharmony_ci	if (auth_tok_key) {
8468c2ecf20Sopenharmony_ci		up_write(&(auth_tok_key->sem));
8478c2ecf20Sopenharmony_ci		key_put(auth_tok_key);
8488c2ecf20Sopenharmony_ci	}
8498c2ecf20Sopenharmony_ci	skcipher_request_free(s->skcipher_req);
8508c2ecf20Sopenharmony_ci	kfree_sensitive(s->hash_desc);
8518c2ecf20Sopenharmony_ci	kfree(s);
8528c2ecf20Sopenharmony_ci	return rc;
8538c2ecf20Sopenharmony_ci}
8548c2ecf20Sopenharmony_ci
8558c2ecf20Sopenharmony_cistruct ecryptfs_parse_tag_70_packet_silly_stack {
8568c2ecf20Sopenharmony_ci	u8 cipher_code;
8578c2ecf20Sopenharmony_ci	size_t max_packet_size;
8588c2ecf20Sopenharmony_ci	size_t packet_size_len;
8598c2ecf20Sopenharmony_ci	size_t parsed_tag_70_packet_size;
8608c2ecf20Sopenharmony_ci	size_t block_aligned_filename_size;
8618c2ecf20Sopenharmony_ci	size_t block_size;
8628c2ecf20Sopenharmony_ci	size_t i;
8638c2ecf20Sopenharmony_ci	struct mutex *tfm_mutex;
8648c2ecf20Sopenharmony_ci	char *decrypted_filename;
8658c2ecf20Sopenharmony_ci	struct ecryptfs_auth_tok *auth_tok;
8668c2ecf20Sopenharmony_ci	struct scatterlist src_sg[2];
8678c2ecf20Sopenharmony_ci	struct scatterlist dst_sg[2];
8688c2ecf20Sopenharmony_ci	struct crypto_skcipher *skcipher_tfm;
8698c2ecf20Sopenharmony_ci	struct skcipher_request *skcipher_req;
8708c2ecf20Sopenharmony_ci	char fnek_sig_hex[ECRYPTFS_SIG_SIZE_HEX + 1];
8718c2ecf20Sopenharmony_ci	char iv[ECRYPTFS_MAX_IV_BYTES];
8728c2ecf20Sopenharmony_ci	char cipher_string[ECRYPTFS_MAX_CIPHER_NAME_SIZE + 1];
8738c2ecf20Sopenharmony_ci};
8748c2ecf20Sopenharmony_ci
8758c2ecf20Sopenharmony_ci/**
8768c2ecf20Sopenharmony_ci * parse_tag_70_packet - Parse and process FNEK-encrypted passphrase packet
8778c2ecf20Sopenharmony_ci * @filename: This function kmalloc's the memory for the filename
8788c2ecf20Sopenharmony_ci * @filename_size: This function sets this to the amount of memory
8798c2ecf20Sopenharmony_ci *                 kmalloc'd for the filename
8808c2ecf20Sopenharmony_ci * @packet_size: This function sets this to the the number of octets
8818c2ecf20Sopenharmony_ci *               in the packet parsed
8828c2ecf20Sopenharmony_ci * @mount_crypt_stat: The mount-wide cryptographic context
8838c2ecf20Sopenharmony_ci * @data: The memory location containing the start of the tag 70
8848c2ecf20Sopenharmony_ci *        packet
8858c2ecf20Sopenharmony_ci * @max_packet_size: The maximum legal size of the packet to be parsed
8868c2ecf20Sopenharmony_ci *                   from @data
8878c2ecf20Sopenharmony_ci *
8888c2ecf20Sopenharmony_ci * Returns zero on success; non-zero otherwise
8898c2ecf20Sopenharmony_ci */
8908c2ecf20Sopenharmony_ciint
8918c2ecf20Sopenharmony_ciecryptfs_parse_tag_70_packet(char **filename, size_t *filename_size,
8928c2ecf20Sopenharmony_ci			     size_t *packet_size,
8938c2ecf20Sopenharmony_ci			     struct ecryptfs_mount_crypt_stat *mount_crypt_stat,
8948c2ecf20Sopenharmony_ci			     char *data, size_t max_packet_size)
8958c2ecf20Sopenharmony_ci{
8968c2ecf20Sopenharmony_ci	struct ecryptfs_parse_tag_70_packet_silly_stack *s;
8978c2ecf20Sopenharmony_ci	struct key *auth_tok_key = NULL;
8988c2ecf20Sopenharmony_ci	int rc = 0;
8998c2ecf20Sopenharmony_ci
9008c2ecf20Sopenharmony_ci	(*packet_size) = 0;
9018c2ecf20Sopenharmony_ci	(*filename_size) = 0;
9028c2ecf20Sopenharmony_ci	(*filename) = NULL;
9038c2ecf20Sopenharmony_ci	s = kzalloc(sizeof(*s), GFP_KERNEL);
9048c2ecf20Sopenharmony_ci	if (!s)
9058c2ecf20Sopenharmony_ci		return -ENOMEM;
9068c2ecf20Sopenharmony_ci
9078c2ecf20Sopenharmony_ci	if (max_packet_size < ECRYPTFS_TAG_70_MIN_METADATA_SIZE) {
9088c2ecf20Sopenharmony_ci		printk(KERN_WARNING "%s: max_packet_size is [%zd]; it must be "
9098c2ecf20Sopenharmony_ci		       "at least [%d]\n", __func__, max_packet_size,
9108c2ecf20Sopenharmony_ci		       ECRYPTFS_TAG_70_MIN_METADATA_SIZE);
9118c2ecf20Sopenharmony_ci		rc = -EINVAL;
9128c2ecf20Sopenharmony_ci		goto out;
9138c2ecf20Sopenharmony_ci	}
9148c2ecf20Sopenharmony_ci	/* Octet 0: Tag 70 identifier
9158c2ecf20Sopenharmony_ci	 * Octets 1-N1: Tag 70 packet size (includes cipher identifier
9168c2ecf20Sopenharmony_ci	 *              and block-aligned encrypted filename size)
9178c2ecf20Sopenharmony_ci	 * Octets N1-N2: FNEK sig (ECRYPTFS_SIG_SIZE)
9188c2ecf20Sopenharmony_ci	 * Octet N2-N3: Cipher identifier (1 octet)
9198c2ecf20Sopenharmony_ci	 * Octets N3-N4: Block-aligned encrypted filename
9208c2ecf20Sopenharmony_ci	 *  - Consists of a minimum number of random numbers, a \0
9218c2ecf20Sopenharmony_ci	 *    separator, and then the filename */
9228c2ecf20Sopenharmony_ci	if (data[(*packet_size)++] != ECRYPTFS_TAG_70_PACKET_TYPE) {
9238c2ecf20Sopenharmony_ci		printk(KERN_WARNING "%s: Invalid packet tag [0x%.2x]; must be "
9248c2ecf20Sopenharmony_ci		       "tag [0x%.2x]\n", __func__,
9258c2ecf20Sopenharmony_ci		       data[((*packet_size) - 1)], ECRYPTFS_TAG_70_PACKET_TYPE);
9268c2ecf20Sopenharmony_ci		rc = -EINVAL;
9278c2ecf20Sopenharmony_ci		goto out;
9288c2ecf20Sopenharmony_ci	}
9298c2ecf20Sopenharmony_ci	rc = ecryptfs_parse_packet_length(&data[(*packet_size)],
9308c2ecf20Sopenharmony_ci					  &s->parsed_tag_70_packet_size,
9318c2ecf20Sopenharmony_ci					  &s->packet_size_len);
9328c2ecf20Sopenharmony_ci	if (rc) {
9338c2ecf20Sopenharmony_ci		printk(KERN_WARNING "%s: Error parsing packet length; "
9348c2ecf20Sopenharmony_ci		       "rc = [%d]\n", __func__, rc);
9358c2ecf20Sopenharmony_ci		goto out;
9368c2ecf20Sopenharmony_ci	}
9378c2ecf20Sopenharmony_ci	s->block_aligned_filename_size = (s->parsed_tag_70_packet_size
9388c2ecf20Sopenharmony_ci					  - ECRYPTFS_SIG_SIZE - 1);
9398c2ecf20Sopenharmony_ci	if ((1 + s->packet_size_len + s->parsed_tag_70_packet_size)
9408c2ecf20Sopenharmony_ci	    > max_packet_size) {
9418c2ecf20Sopenharmony_ci		printk(KERN_WARNING "%s: max_packet_size is [%zd]; real packet "
9428c2ecf20Sopenharmony_ci		       "size is [%zd]\n", __func__, max_packet_size,
9438c2ecf20Sopenharmony_ci		       (1 + s->packet_size_len + 1
9448c2ecf20Sopenharmony_ci			+ s->block_aligned_filename_size));
9458c2ecf20Sopenharmony_ci		rc = -EINVAL;
9468c2ecf20Sopenharmony_ci		goto out;
9478c2ecf20Sopenharmony_ci	}
9488c2ecf20Sopenharmony_ci	(*packet_size) += s->packet_size_len;
9498c2ecf20Sopenharmony_ci	ecryptfs_to_hex(s->fnek_sig_hex, &data[(*packet_size)],
9508c2ecf20Sopenharmony_ci			ECRYPTFS_SIG_SIZE);
9518c2ecf20Sopenharmony_ci	s->fnek_sig_hex[ECRYPTFS_SIG_SIZE_HEX] = '\0';
9528c2ecf20Sopenharmony_ci	(*packet_size) += ECRYPTFS_SIG_SIZE;
9538c2ecf20Sopenharmony_ci	s->cipher_code = data[(*packet_size)++];
9548c2ecf20Sopenharmony_ci	rc = ecryptfs_cipher_code_to_string(s->cipher_string, s->cipher_code);
9558c2ecf20Sopenharmony_ci	if (rc) {
9568c2ecf20Sopenharmony_ci		printk(KERN_WARNING "%s: Cipher code [%d] is invalid\n",
9578c2ecf20Sopenharmony_ci		       __func__, s->cipher_code);
9588c2ecf20Sopenharmony_ci		goto out;
9598c2ecf20Sopenharmony_ci	}
9608c2ecf20Sopenharmony_ci	rc = ecryptfs_find_auth_tok_for_sig(&auth_tok_key,
9618c2ecf20Sopenharmony_ci					    &s->auth_tok, mount_crypt_stat,
9628c2ecf20Sopenharmony_ci					    s->fnek_sig_hex);
9638c2ecf20Sopenharmony_ci	if (rc) {
9648c2ecf20Sopenharmony_ci		printk(KERN_ERR "%s: Error attempting to find auth tok for "
9658c2ecf20Sopenharmony_ci		       "fnek sig [%s]; rc = [%d]\n", __func__, s->fnek_sig_hex,
9668c2ecf20Sopenharmony_ci		       rc);
9678c2ecf20Sopenharmony_ci		goto out;
9688c2ecf20Sopenharmony_ci	}
9698c2ecf20Sopenharmony_ci	rc = ecryptfs_get_tfm_and_mutex_for_cipher_name(&s->skcipher_tfm,
9708c2ecf20Sopenharmony_ci							&s->tfm_mutex,
9718c2ecf20Sopenharmony_ci							s->cipher_string);
9728c2ecf20Sopenharmony_ci	if (unlikely(rc)) {
9738c2ecf20Sopenharmony_ci		printk(KERN_ERR "Internal error whilst attempting to get "
9748c2ecf20Sopenharmony_ci		       "tfm and mutex for cipher name [%s]; rc = [%d]\n",
9758c2ecf20Sopenharmony_ci		       s->cipher_string, rc);
9768c2ecf20Sopenharmony_ci		goto out;
9778c2ecf20Sopenharmony_ci	}
9788c2ecf20Sopenharmony_ci	mutex_lock(s->tfm_mutex);
9798c2ecf20Sopenharmony_ci	rc = virt_to_scatterlist(&data[(*packet_size)],
9808c2ecf20Sopenharmony_ci				 s->block_aligned_filename_size, s->src_sg, 2);
9818c2ecf20Sopenharmony_ci	if (rc < 1) {
9828c2ecf20Sopenharmony_ci		printk(KERN_ERR "%s: Internal error whilst attempting to "
9838c2ecf20Sopenharmony_ci		       "convert encrypted filename memory to scatterlist; "
9848c2ecf20Sopenharmony_ci		       "rc = [%d]. block_aligned_filename_size = [%zd]\n",
9858c2ecf20Sopenharmony_ci		       __func__, rc, s->block_aligned_filename_size);
9868c2ecf20Sopenharmony_ci		goto out_unlock;
9878c2ecf20Sopenharmony_ci	}
9888c2ecf20Sopenharmony_ci	(*packet_size) += s->block_aligned_filename_size;
9898c2ecf20Sopenharmony_ci	s->decrypted_filename = kmalloc(s->block_aligned_filename_size,
9908c2ecf20Sopenharmony_ci					GFP_KERNEL);
9918c2ecf20Sopenharmony_ci	if (!s->decrypted_filename) {
9928c2ecf20Sopenharmony_ci		rc = -ENOMEM;
9938c2ecf20Sopenharmony_ci		goto out_unlock;
9948c2ecf20Sopenharmony_ci	}
9958c2ecf20Sopenharmony_ci	rc = virt_to_scatterlist(s->decrypted_filename,
9968c2ecf20Sopenharmony_ci				 s->block_aligned_filename_size, s->dst_sg, 2);
9978c2ecf20Sopenharmony_ci	if (rc < 1) {
9988c2ecf20Sopenharmony_ci		printk(KERN_ERR "%s: Internal error whilst attempting to "
9998c2ecf20Sopenharmony_ci		       "convert decrypted filename memory to scatterlist; "
10008c2ecf20Sopenharmony_ci		       "rc = [%d]. block_aligned_filename_size = [%zd]\n",
10018c2ecf20Sopenharmony_ci		       __func__, rc, s->block_aligned_filename_size);
10028c2ecf20Sopenharmony_ci		goto out_free_unlock;
10038c2ecf20Sopenharmony_ci	}
10048c2ecf20Sopenharmony_ci
10058c2ecf20Sopenharmony_ci	s->skcipher_req = skcipher_request_alloc(s->skcipher_tfm, GFP_KERNEL);
10068c2ecf20Sopenharmony_ci	if (!s->skcipher_req) {
10078c2ecf20Sopenharmony_ci		printk(KERN_ERR "%s: Out of kernel memory whilst attempting to "
10088c2ecf20Sopenharmony_ci		       "skcipher_request_alloc for %s\n", __func__,
10098c2ecf20Sopenharmony_ci		       crypto_skcipher_driver_name(s->skcipher_tfm));
10108c2ecf20Sopenharmony_ci		rc = -ENOMEM;
10118c2ecf20Sopenharmony_ci		goto out_free_unlock;
10128c2ecf20Sopenharmony_ci	}
10138c2ecf20Sopenharmony_ci
10148c2ecf20Sopenharmony_ci	skcipher_request_set_callback(s->skcipher_req,
10158c2ecf20Sopenharmony_ci				      CRYPTO_TFM_REQ_MAY_SLEEP, NULL, NULL);
10168c2ecf20Sopenharmony_ci
10178c2ecf20Sopenharmony_ci	/* The characters in the first block effectively do the job of
10188c2ecf20Sopenharmony_ci	 * the IV here, so we just use 0's for the IV. Note the
10198c2ecf20Sopenharmony_ci	 * constraint that ECRYPTFS_FILENAME_MIN_RANDOM_PREPEND_BYTES
10208c2ecf20Sopenharmony_ci	 * >= ECRYPTFS_MAX_IV_BYTES. */
10218c2ecf20Sopenharmony_ci	/* TODO: Support other key modules than passphrase for
10228c2ecf20Sopenharmony_ci	 * filename encryption */
10238c2ecf20Sopenharmony_ci	if (s->auth_tok->token_type != ECRYPTFS_PASSWORD) {
10248c2ecf20Sopenharmony_ci		rc = -EOPNOTSUPP;
10258c2ecf20Sopenharmony_ci		printk(KERN_INFO "%s: Filename encryption only supports "
10268c2ecf20Sopenharmony_ci		       "password tokens\n", __func__);
10278c2ecf20Sopenharmony_ci		goto out_free_unlock;
10288c2ecf20Sopenharmony_ci	}
10298c2ecf20Sopenharmony_ci	rc = crypto_skcipher_setkey(
10308c2ecf20Sopenharmony_ci		s->skcipher_tfm,
10318c2ecf20Sopenharmony_ci		s->auth_tok->token.password.session_key_encryption_key,
10328c2ecf20Sopenharmony_ci		mount_crypt_stat->global_default_fn_cipher_key_bytes);
10338c2ecf20Sopenharmony_ci	if (rc < 0) {
10348c2ecf20Sopenharmony_ci		printk(KERN_ERR "%s: Error setting key for crypto context; "
10358c2ecf20Sopenharmony_ci		       "rc = [%d]. s->auth_tok->token.password.session_key_"
10368c2ecf20Sopenharmony_ci		       "encryption_key = [0x%p]; mount_crypt_stat->"
10378c2ecf20Sopenharmony_ci		       "global_default_fn_cipher_key_bytes = [%zd]\n", __func__,
10388c2ecf20Sopenharmony_ci		       rc,
10398c2ecf20Sopenharmony_ci		       s->auth_tok->token.password.session_key_encryption_key,
10408c2ecf20Sopenharmony_ci		       mount_crypt_stat->global_default_fn_cipher_key_bytes);
10418c2ecf20Sopenharmony_ci		goto out_free_unlock;
10428c2ecf20Sopenharmony_ci	}
10438c2ecf20Sopenharmony_ci	skcipher_request_set_crypt(s->skcipher_req, s->src_sg, s->dst_sg,
10448c2ecf20Sopenharmony_ci				   s->block_aligned_filename_size, s->iv);
10458c2ecf20Sopenharmony_ci	rc = crypto_skcipher_decrypt(s->skcipher_req);
10468c2ecf20Sopenharmony_ci	if (rc) {
10478c2ecf20Sopenharmony_ci		printk(KERN_ERR "%s: Error attempting to decrypt filename; "
10488c2ecf20Sopenharmony_ci		       "rc = [%d]\n", __func__, rc);
10498c2ecf20Sopenharmony_ci		goto out_free_unlock;
10508c2ecf20Sopenharmony_ci	}
10518c2ecf20Sopenharmony_ci
10528c2ecf20Sopenharmony_ci	while (s->i < s->block_aligned_filename_size &&
10538c2ecf20Sopenharmony_ci	       s->decrypted_filename[s->i] != '\0')
10548c2ecf20Sopenharmony_ci		s->i++;
10558c2ecf20Sopenharmony_ci	if (s->i == s->block_aligned_filename_size) {
10568c2ecf20Sopenharmony_ci		printk(KERN_WARNING "%s: Invalid tag 70 packet; could not "
10578c2ecf20Sopenharmony_ci		       "find valid separator between random characters and "
10588c2ecf20Sopenharmony_ci		       "the filename\n", __func__);
10598c2ecf20Sopenharmony_ci		rc = -EINVAL;
10608c2ecf20Sopenharmony_ci		goto out_free_unlock;
10618c2ecf20Sopenharmony_ci	}
10628c2ecf20Sopenharmony_ci	s->i++;
10638c2ecf20Sopenharmony_ci	(*filename_size) = (s->block_aligned_filename_size - s->i);
10648c2ecf20Sopenharmony_ci	if (!((*filename_size) > 0 && (*filename_size < PATH_MAX))) {
10658c2ecf20Sopenharmony_ci		printk(KERN_WARNING "%s: Filename size is [%zd], which is "
10668c2ecf20Sopenharmony_ci		       "invalid\n", __func__, (*filename_size));
10678c2ecf20Sopenharmony_ci		rc = -EINVAL;
10688c2ecf20Sopenharmony_ci		goto out_free_unlock;
10698c2ecf20Sopenharmony_ci	}
10708c2ecf20Sopenharmony_ci	(*filename) = kmalloc(((*filename_size) + 1), GFP_KERNEL);
10718c2ecf20Sopenharmony_ci	if (!(*filename)) {
10728c2ecf20Sopenharmony_ci		rc = -ENOMEM;
10738c2ecf20Sopenharmony_ci		goto out_free_unlock;
10748c2ecf20Sopenharmony_ci	}
10758c2ecf20Sopenharmony_ci	memcpy((*filename), &s->decrypted_filename[s->i], (*filename_size));
10768c2ecf20Sopenharmony_ci	(*filename)[(*filename_size)] = '\0';
10778c2ecf20Sopenharmony_ciout_free_unlock:
10788c2ecf20Sopenharmony_ci	kfree(s->decrypted_filename);
10798c2ecf20Sopenharmony_ciout_unlock:
10808c2ecf20Sopenharmony_ci	mutex_unlock(s->tfm_mutex);
10818c2ecf20Sopenharmony_ciout:
10828c2ecf20Sopenharmony_ci	if (rc) {
10838c2ecf20Sopenharmony_ci		(*packet_size) = 0;
10848c2ecf20Sopenharmony_ci		(*filename_size) = 0;
10858c2ecf20Sopenharmony_ci		(*filename) = NULL;
10868c2ecf20Sopenharmony_ci	}
10878c2ecf20Sopenharmony_ci	if (auth_tok_key) {
10888c2ecf20Sopenharmony_ci		up_write(&(auth_tok_key->sem));
10898c2ecf20Sopenharmony_ci		key_put(auth_tok_key);
10908c2ecf20Sopenharmony_ci	}
10918c2ecf20Sopenharmony_ci	skcipher_request_free(s->skcipher_req);
10928c2ecf20Sopenharmony_ci	kfree(s);
10938c2ecf20Sopenharmony_ci	return rc;
10948c2ecf20Sopenharmony_ci}
10958c2ecf20Sopenharmony_ci
10968c2ecf20Sopenharmony_cistatic int
10978c2ecf20Sopenharmony_ciecryptfs_get_auth_tok_sig(char **sig, struct ecryptfs_auth_tok *auth_tok)
10988c2ecf20Sopenharmony_ci{
10998c2ecf20Sopenharmony_ci	int rc = 0;
11008c2ecf20Sopenharmony_ci
11018c2ecf20Sopenharmony_ci	(*sig) = NULL;
11028c2ecf20Sopenharmony_ci	switch (auth_tok->token_type) {
11038c2ecf20Sopenharmony_ci	case ECRYPTFS_PASSWORD:
11048c2ecf20Sopenharmony_ci		(*sig) = auth_tok->token.password.signature;
11058c2ecf20Sopenharmony_ci		break;
11068c2ecf20Sopenharmony_ci	case ECRYPTFS_PRIVATE_KEY:
11078c2ecf20Sopenharmony_ci		(*sig) = auth_tok->token.private_key.signature;
11088c2ecf20Sopenharmony_ci		break;
11098c2ecf20Sopenharmony_ci	default:
11108c2ecf20Sopenharmony_ci		printk(KERN_ERR "Cannot get sig for auth_tok of type [%d]\n",
11118c2ecf20Sopenharmony_ci		       auth_tok->token_type);
11128c2ecf20Sopenharmony_ci		rc = -EINVAL;
11138c2ecf20Sopenharmony_ci	}
11148c2ecf20Sopenharmony_ci	return rc;
11158c2ecf20Sopenharmony_ci}
11168c2ecf20Sopenharmony_ci
11178c2ecf20Sopenharmony_ci/**
11188c2ecf20Sopenharmony_ci * decrypt_pki_encrypted_session_key - Decrypt the session key with the given auth_tok.
11198c2ecf20Sopenharmony_ci * @auth_tok: The key authentication token used to decrypt the session key
11208c2ecf20Sopenharmony_ci * @crypt_stat: The cryptographic context
11218c2ecf20Sopenharmony_ci *
11228c2ecf20Sopenharmony_ci * Returns zero on success; non-zero error otherwise.
11238c2ecf20Sopenharmony_ci */
11248c2ecf20Sopenharmony_cistatic int
11258c2ecf20Sopenharmony_cidecrypt_pki_encrypted_session_key(struct ecryptfs_auth_tok *auth_tok,
11268c2ecf20Sopenharmony_ci				  struct ecryptfs_crypt_stat *crypt_stat)
11278c2ecf20Sopenharmony_ci{
11288c2ecf20Sopenharmony_ci	u8 cipher_code = 0;
11298c2ecf20Sopenharmony_ci	struct ecryptfs_msg_ctx *msg_ctx;
11308c2ecf20Sopenharmony_ci	struct ecryptfs_message *msg = NULL;
11318c2ecf20Sopenharmony_ci	char *auth_tok_sig;
11328c2ecf20Sopenharmony_ci	char *payload = NULL;
11338c2ecf20Sopenharmony_ci	size_t payload_len = 0;
11348c2ecf20Sopenharmony_ci	int rc;
11358c2ecf20Sopenharmony_ci
11368c2ecf20Sopenharmony_ci	rc = ecryptfs_get_auth_tok_sig(&auth_tok_sig, auth_tok);
11378c2ecf20Sopenharmony_ci	if (rc) {
11388c2ecf20Sopenharmony_ci		printk(KERN_ERR "Unrecognized auth tok type: [%d]\n",
11398c2ecf20Sopenharmony_ci		       auth_tok->token_type);
11408c2ecf20Sopenharmony_ci		goto out;
11418c2ecf20Sopenharmony_ci	}
11428c2ecf20Sopenharmony_ci	rc = write_tag_64_packet(auth_tok_sig, &(auth_tok->session_key),
11438c2ecf20Sopenharmony_ci				 &payload, &payload_len);
11448c2ecf20Sopenharmony_ci	if (rc) {
11458c2ecf20Sopenharmony_ci		ecryptfs_printk(KERN_ERR, "Failed to write tag 64 packet\n");
11468c2ecf20Sopenharmony_ci		goto out;
11478c2ecf20Sopenharmony_ci	}
11488c2ecf20Sopenharmony_ci	rc = ecryptfs_send_message(payload, payload_len, &msg_ctx);
11498c2ecf20Sopenharmony_ci	if (rc) {
11508c2ecf20Sopenharmony_ci		ecryptfs_printk(KERN_ERR, "Error sending message to "
11518c2ecf20Sopenharmony_ci				"ecryptfsd: %d\n", rc);
11528c2ecf20Sopenharmony_ci		goto out;
11538c2ecf20Sopenharmony_ci	}
11548c2ecf20Sopenharmony_ci	rc = ecryptfs_wait_for_response(msg_ctx, &msg);
11558c2ecf20Sopenharmony_ci	if (rc) {
11568c2ecf20Sopenharmony_ci		ecryptfs_printk(KERN_ERR, "Failed to receive tag 65 packet "
11578c2ecf20Sopenharmony_ci				"from the user space daemon\n");
11588c2ecf20Sopenharmony_ci		rc = -EIO;
11598c2ecf20Sopenharmony_ci		goto out;
11608c2ecf20Sopenharmony_ci	}
11618c2ecf20Sopenharmony_ci	rc = parse_tag_65_packet(&(auth_tok->session_key),
11628c2ecf20Sopenharmony_ci				 &cipher_code, msg);
11638c2ecf20Sopenharmony_ci	if (rc) {
11648c2ecf20Sopenharmony_ci		printk(KERN_ERR "Failed to parse tag 65 packet; rc = [%d]\n",
11658c2ecf20Sopenharmony_ci		       rc);
11668c2ecf20Sopenharmony_ci		goto out;
11678c2ecf20Sopenharmony_ci	}
11688c2ecf20Sopenharmony_ci	auth_tok->session_key.flags |= ECRYPTFS_CONTAINS_DECRYPTED_KEY;
11698c2ecf20Sopenharmony_ci	memcpy(crypt_stat->key, auth_tok->session_key.decrypted_key,
11708c2ecf20Sopenharmony_ci	       auth_tok->session_key.decrypted_key_size);
11718c2ecf20Sopenharmony_ci	crypt_stat->key_size = auth_tok->session_key.decrypted_key_size;
11728c2ecf20Sopenharmony_ci	rc = ecryptfs_cipher_code_to_string(crypt_stat->cipher, cipher_code);
11738c2ecf20Sopenharmony_ci	if (rc) {
11748c2ecf20Sopenharmony_ci		ecryptfs_printk(KERN_ERR, "Cipher code [%d] is invalid\n",
11758c2ecf20Sopenharmony_ci				cipher_code)
11768c2ecf20Sopenharmony_ci		goto out;
11778c2ecf20Sopenharmony_ci	}
11788c2ecf20Sopenharmony_ci	crypt_stat->flags |= ECRYPTFS_KEY_VALID;
11798c2ecf20Sopenharmony_ci	if (ecryptfs_verbosity > 0) {
11808c2ecf20Sopenharmony_ci		ecryptfs_printk(KERN_DEBUG, "Decrypted session key:\n");
11818c2ecf20Sopenharmony_ci		ecryptfs_dump_hex(crypt_stat->key,
11828c2ecf20Sopenharmony_ci				  crypt_stat->key_size);
11838c2ecf20Sopenharmony_ci	}
11848c2ecf20Sopenharmony_ciout:
11858c2ecf20Sopenharmony_ci	kfree(msg);
11868c2ecf20Sopenharmony_ci	kfree(payload);
11878c2ecf20Sopenharmony_ci	return rc;
11888c2ecf20Sopenharmony_ci}
11898c2ecf20Sopenharmony_ci
11908c2ecf20Sopenharmony_cistatic void wipe_auth_tok_list(struct list_head *auth_tok_list_head)
11918c2ecf20Sopenharmony_ci{
11928c2ecf20Sopenharmony_ci	struct ecryptfs_auth_tok_list_item *auth_tok_list_item;
11938c2ecf20Sopenharmony_ci	struct ecryptfs_auth_tok_list_item *auth_tok_list_item_tmp;
11948c2ecf20Sopenharmony_ci
11958c2ecf20Sopenharmony_ci	list_for_each_entry_safe(auth_tok_list_item, auth_tok_list_item_tmp,
11968c2ecf20Sopenharmony_ci				 auth_tok_list_head, list) {
11978c2ecf20Sopenharmony_ci		list_del(&auth_tok_list_item->list);
11988c2ecf20Sopenharmony_ci		kmem_cache_free(ecryptfs_auth_tok_list_item_cache,
11998c2ecf20Sopenharmony_ci				auth_tok_list_item);
12008c2ecf20Sopenharmony_ci	}
12018c2ecf20Sopenharmony_ci}
12028c2ecf20Sopenharmony_ci
12038c2ecf20Sopenharmony_cistruct kmem_cache *ecryptfs_auth_tok_list_item_cache;
12048c2ecf20Sopenharmony_ci
12058c2ecf20Sopenharmony_ci/**
12068c2ecf20Sopenharmony_ci * parse_tag_1_packet
12078c2ecf20Sopenharmony_ci * @crypt_stat: The cryptographic context to modify based on packet contents
12088c2ecf20Sopenharmony_ci * @data: The raw bytes of the packet.
12098c2ecf20Sopenharmony_ci * @auth_tok_list: eCryptfs parses packets into authentication tokens;
12108c2ecf20Sopenharmony_ci *                 a new authentication token will be placed at the
12118c2ecf20Sopenharmony_ci *                 end of this list for this packet.
12128c2ecf20Sopenharmony_ci * @new_auth_tok: Pointer to a pointer to memory that this function
12138c2ecf20Sopenharmony_ci *                allocates; sets the memory address of the pointer to
12148c2ecf20Sopenharmony_ci *                NULL on error. This object is added to the
12158c2ecf20Sopenharmony_ci *                auth_tok_list.
12168c2ecf20Sopenharmony_ci * @packet_size: This function writes the size of the parsed packet
12178c2ecf20Sopenharmony_ci *               into this memory location; zero on error.
12188c2ecf20Sopenharmony_ci * @max_packet_size: The maximum allowable packet size
12198c2ecf20Sopenharmony_ci *
12208c2ecf20Sopenharmony_ci * Returns zero on success; non-zero on error.
12218c2ecf20Sopenharmony_ci */
12228c2ecf20Sopenharmony_cistatic int
12238c2ecf20Sopenharmony_ciparse_tag_1_packet(struct ecryptfs_crypt_stat *crypt_stat,
12248c2ecf20Sopenharmony_ci		   unsigned char *data, struct list_head *auth_tok_list,
12258c2ecf20Sopenharmony_ci		   struct ecryptfs_auth_tok **new_auth_tok,
12268c2ecf20Sopenharmony_ci		   size_t *packet_size, size_t max_packet_size)
12278c2ecf20Sopenharmony_ci{
12288c2ecf20Sopenharmony_ci	size_t body_size;
12298c2ecf20Sopenharmony_ci	struct ecryptfs_auth_tok_list_item *auth_tok_list_item;
12308c2ecf20Sopenharmony_ci	size_t length_size;
12318c2ecf20Sopenharmony_ci	int rc = 0;
12328c2ecf20Sopenharmony_ci
12338c2ecf20Sopenharmony_ci	(*packet_size) = 0;
12348c2ecf20Sopenharmony_ci	(*new_auth_tok) = NULL;
12358c2ecf20Sopenharmony_ci	/**
12368c2ecf20Sopenharmony_ci	 * This format is inspired by OpenPGP; see RFC 2440
12378c2ecf20Sopenharmony_ci	 * packet tag 1
12388c2ecf20Sopenharmony_ci	 *
12398c2ecf20Sopenharmony_ci	 * Tag 1 identifier (1 byte)
12408c2ecf20Sopenharmony_ci	 * Max Tag 1 packet size (max 3 bytes)
12418c2ecf20Sopenharmony_ci	 * Version (1 byte)
12428c2ecf20Sopenharmony_ci	 * Key identifier (8 bytes; ECRYPTFS_SIG_SIZE)
12438c2ecf20Sopenharmony_ci	 * Cipher identifier (1 byte)
12448c2ecf20Sopenharmony_ci	 * Encrypted key size (arbitrary)
12458c2ecf20Sopenharmony_ci	 *
12468c2ecf20Sopenharmony_ci	 * 12 bytes minimum packet size
12478c2ecf20Sopenharmony_ci	 */
12488c2ecf20Sopenharmony_ci	if (unlikely(max_packet_size < 12)) {
12498c2ecf20Sopenharmony_ci		printk(KERN_ERR "Invalid max packet size; must be >=12\n");
12508c2ecf20Sopenharmony_ci		rc = -EINVAL;
12518c2ecf20Sopenharmony_ci		goto out;
12528c2ecf20Sopenharmony_ci	}
12538c2ecf20Sopenharmony_ci	if (data[(*packet_size)++] != ECRYPTFS_TAG_1_PACKET_TYPE) {
12548c2ecf20Sopenharmony_ci		printk(KERN_ERR "Enter w/ first byte != 0x%.2x\n",
12558c2ecf20Sopenharmony_ci		       ECRYPTFS_TAG_1_PACKET_TYPE);
12568c2ecf20Sopenharmony_ci		rc = -EINVAL;
12578c2ecf20Sopenharmony_ci		goto out;
12588c2ecf20Sopenharmony_ci	}
12598c2ecf20Sopenharmony_ci	/* Released: wipe_auth_tok_list called in ecryptfs_parse_packet_set or
12608c2ecf20Sopenharmony_ci	 * at end of function upon failure */
12618c2ecf20Sopenharmony_ci	auth_tok_list_item =
12628c2ecf20Sopenharmony_ci		kmem_cache_zalloc(ecryptfs_auth_tok_list_item_cache,
12638c2ecf20Sopenharmony_ci				  GFP_KERNEL);
12648c2ecf20Sopenharmony_ci	if (!auth_tok_list_item) {
12658c2ecf20Sopenharmony_ci		printk(KERN_ERR "Unable to allocate memory\n");
12668c2ecf20Sopenharmony_ci		rc = -ENOMEM;
12678c2ecf20Sopenharmony_ci		goto out;
12688c2ecf20Sopenharmony_ci	}
12698c2ecf20Sopenharmony_ci	(*new_auth_tok) = &auth_tok_list_item->auth_tok;
12708c2ecf20Sopenharmony_ci	rc = ecryptfs_parse_packet_length(&data[(*packet_size)], &body_size,
12718c2ecf20Sopenharmony_ci					  &length_size);
12728c2ecf20Sopenharmony_ci	if (rc) {
12738c2ecf20Sopenharmony_ci		printk(KERN_WARNING "Error parsing packet length; "
12748c2ecf20Sopenharmony_ci		       "rc = [%d]\n", rc);
12758c2ecf20Sopenharmony_ci		goto out_free;
12768c2ecf20Sopenharmony_ci	}
12778c2ecf20Sopenharmony_ci	if (unlikely(body_size < (ECRYPTFS_SIG_SIZE + 2))) {
12788c2ecf20Sopenharmony_ci		printk(KERN_WARNING "Invalid body size ([%td])\n", body_size);
12798c2ecf20Sopenharmony_ci		rc = -EINVAL;
12808c2ecf20Sopenharmony_ci		goto out_free;
12818c2ecf20Sopenharmony_ci	}
12828c2ecf20Sopenharmony_ci	(*packet_size) += length_size;
12838c2ecf20Sopenharmony_ci	if (unlikely((*packet_size) + body_size > max_packet_size)) {
12848c2ecf20Sopenharmony_ci		printk(KERN_WARNING "Packet size exceeds max\n");
12858c2ecf20Sopenharmony_ci		rc = -EINVAL;
12868c2ecf20Sopenharmony_ci		goto out_free;
12878c2ecf20Sopenharmony_ci	}
12888c2ecf20Sopenharmony_ci	if (unlikely(data[(*packet_size)++] != 0x03)) {
12898c2ecf20Sopenharmony_ci		printk(KERN_WARNING "Unknown version number [%d]\n",
12908c2ecf20Sopenharmony_ci		       data[(*packet_size) - 1]);
12918c2ecf20Sopenharmony_ci		rc = -EINVAL;
12928c2ecf20Sopenharmony_ci		goto out_free;
12938c2ecf20Sopenharmony_ci	}
12948c2ecf20Sopenharmony_ci	ecryptfs_to_hex((*new_auth_tok)->token.private_key.signature,
12958c2ecf20Sopenharmony_ci			&data[(*packet_size)], ECRYPTFS_SIG_SIZE);
12968c2ecf20Sopenharmony_ci	*packet_size += ECRYPTFS_SIG_SIZE;
12978c2ecf20Sopenharmony_ci	/* This byte is skipped because the kernel does not need to
12988c2ecf20Sopenharmony_ci	 * know which public key encryption algorithm was used */
12998c2ecf20Sopenharmony_ci	(*packet_size)++;
13008c2ecf20Sopenharmony_ci	(*new_auth_tok)->session_key.encrypted_key_size =
13018c2ecf20Sopenharmony_ci		body_size - (ECRYPTFS_SIG_SIZE + 2);
13028c2ecf20Sopenharmony_ci	if ((*new_auth_tok)->session_key.encrypted_key_size
13038c2ecf20Sopenharmony_ci	    > ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES) {
13048c2ecf20Sopenharmony_ci		printk(KERN_WARNING "Tag 1 packet contains key larger "
13058c2ecf20Sopenharmony_ci		       "than ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES\n");
13068c2ecf20Sopenharmony_ci		rc = -EINVAL;
13078c2ecf20Sopenharmony_ci		goto out_free;
13088c2ecf20Sopenharmony_ci	}
13098c2ecf20Sopenharmony_ci	memcpy((*new_auth_tok)->session_key.encrypted_key,
13108c2ecf20Sopenharmony_ci	       &data[(*packet_size)], (body_size - (ECRYPTFS_SIG_SIZE + 2)));
13118c2ecf20Sopenharmony_ci	(*packet_size) += (*new_auth_tok)->session_key.encrypted_key_size;
13128c2ecf20Sopenharmony_ci	(*new_auth_tok)->session_key.flags &=
13138c2ecf20Sopenharmony_ci		~ECRYPTFS_CONTAINS_DECRYPTED_KEY;
13148c2ecf20Sopenharmony_ci	(*new_auth_tok)->session_key.flags |=
13158c2ecf20Sopenharmony_ci		ECRYPTFS_CONTAINS_ENCRYPTED_KEY;
13168c2ecf20Sopenharmony_ci	(*new_auth_tok)->token_type = ECRYPTFS_PRIVATE_KEY;
13178c2ecf20Sopenharmony_ci	(*new_auth_tok)->flags = 0;
13188c2ecf20Sopenharmony_ci	(*new_auth_tok)->session_key.flags &=
13198c2ecf20Sopenharmony_ci		~(ECRYPTFS_USERSPACE_SHOULD_TRY_TO_DECRYPT);
13208c2ecf20Sopenharmony_ci	(*new_auth_tok)->session_key.flags &=
13218c2ecf20Sopenharmony_ci		~(ECRYPTFS_USERSPACE_SHOULD_TRY_TO_ENCRYPT);
13228c2ecf20Sopenharmony_ci	list_add(&auth_tok_list_item->list, auth_tok_list);
13238c2ecf20Sopenharmony_ci	goto out;
13248c2ecf20Sopenharmony_ciout_free:
13258c2ecf20Sopenharmony_ci	(*new_auth_tok) = NULL;
13268c2ecf20Sopenharmony_ci	memset(auth_tok_list_item, 0,
13278c2ecf20Sopenharmony_ci	       sizeof(struct ecryptfs_auth_tok_list_item));
13288c2ecf20Sopenharmony_ci	kmem_cache_free(ecryptfs_auth_tok_list_item_cache,
13298c2ecf20Sopenharmony_ci			auth_tok_list_item);
13308c2ecf20Sopenharmony_ciout:
13318c2ecf20Sopenharmony_ci	if (rc)
13328c2ecf20Sopenharmony_ci		(*packet_size) = 0;
13338c2ecf20Sopenharmony_ci	return rc;
13348c2ecf20Sopenharmony_ci}
13358c2ecf20Sopenharmony_ci
13368c2ecf20Sopenharmony_ci/**
13378c2ecf20Sopenharmony_ci * parse_tag_3_packet
13388c2ecf20Sopenharmony_ci * @crypt_stat: The cryptographic context to modify based on packet
13398c2ecf20Sopenharmony_ci *              contents.
13408c2ecf20Sopenharmony_ci * @data: The raw bytes of the packet.
13418c2ecf20Sopenharmony_ci * @auth_tok_list: eCryptfs parses packets into authentication tokens;
13428c2ecf20Sopenharmony_ci *                 a new authentication token will be placed at the end
13438c2ecf20Sopenharmony_ci *                 of this list for this packet.
13448c2ecf20Sopenharmony_ci * @new_auth_tok: Pointer to a pointer to memory that this function
13458c2ecf20Sopenharmony_ci *                allocates; sets the memory address of the pointer to
13468c2ecf20Sopenharmony_ci *                NULL on error. This object is added to the
13478c2ecf20Sopenharmony_ci *                auth_tok_list.
13488c2ecf20Sopenharmony_ci * @packet_size: This function writes the size of the parsed packet
13498c2ecf20Sopenharmony_ci *               into this memory location; zero on error.
13508c2ecf20Sopenharmony_ci * @max_packet_size: maximum number of bytes to parse
13518c2ecf20Sopenharmony_ci *
13528c2ecf20Sopenharmony_ci * Returns zero on success; non-zero on error.
13538c2ecf20Sopenharmony_ci */
13548c2ecf20Sopenharmony_cistatic int
13558c2ecf20Sopenharmony_ciparse_tag_3_packet(struct ecryptfs_crypt_stat *crypt_stat,
13568c2ecf20Sopenharmony_ci		   unsigned char *data, struct list_head *auth_tok_list,
13578c2ecf20Sopenharmony_ci		   struct ecryptfs_auth_tok **new_auth_tok,
13588c2ecf20Sopenharmony_ci		   size_t *packet_size, size_t max_packet_size)
13598c2ecf20Sopenharmony_ci{
13608c2ecf20Sopenharmony_ci	size_t body_size;
13618c2ecf20Sopenharmony_ci	struct ecryptfs_auth_tok_list_item *auth_tok_list_item;
13628c2ecf20Sopenharmony_ci	size_t length_size;
13638c2ecf20Sopenharmony_ci	int rc = 0;
13648c2ecf20Sopenharmony_ci
13658c2ecf20Sopenharmony_ci	(*packet_size) = 0;
13668c2ecf20Sopenharmony_ci	(*new_auth_tok) = NULL;
13678c2ecf20Sopenharmony_ci	/**
13688c2ecf20Sopenharmony_ci	 *This format is inspired by OpenPGP; see RFC 2440
13698c2ecf20Sopenharmony_ci	 * packet tag 3
13708c2ecf20Sopenharmony_ci	 *
13718c2ecf20Sopenharmony_ci	 * Tag 3 identifier (1 byte)
13728c2ecf20Sopenharmony_ci	 * Max Tag 3 packet size (max 3 bytes)
13738c2ecf20Sopenharmony_ci	 * Version (1 byte)
13748c2ecf20Sopenharmony_ci	 * Cipher code (1 byte)
13758c2ecf20Sopenharmony_ci	 * S2K specifier (1 byte)
13768c2ecf20Sopenharmony_ci	 * Hash identifier (1 byte)
13778c2ecf20Sopenharmony_ci	 * Salt (ECRYPTFS_SALT_SIZE)
13788c2ecf20Sopenharmony_ci	 * Hash iterations (1 byte)
13798c2ecf20Sopenharmony_ci	 * Encrypted key (arbitrary)
13808c2ecf20Sopenharmony_ci	 *
13818c2ecf20Sopenharmony_ci	 * (ECRYPTFS_SALT_SIZE + 7) minimum packet size
13828c2ecf20Sopenharmony_ci	 */
13838c2ecf20Sopenharmony_ci	if (max_packet_size < (ECRYPTFS_SALT_SIZE + 7)) {
13848c2ecf20Sopenharmony_ci		printk(KERN_ERR "Max packet size too large\n");
13858c2ecf20Sopenharmony_ci		rc = -EINVAL;
13868c2ecf20Sopenharmony_ci		goto out;
13878c2ecf20Sopenharmony_ci	}
13888c2ecf20Sopenharmony_ci	if (data[(*packet_size)++] != ECRYPTFS_TAG_3_PACKET_TYPE) {
13898c2ecf20Sopenharmony_ci		printk(KERN_ERR "First byte != 0x%.2x; invalid packet\n",
13908c2ecf20Sopenharmony_ci		       ECRYPTFS_TAG_3_PACKET_TYPE);
13918c2ecf20Sopenharmony_ci		rc = -EINVAL;
13928c2ecf20Sopenharmony_ci		goto out;
13938c2ecf20Sopenharmony_ci	}
13948c2ecf20Sopenharmony_ci	/* Released: wipe_auth_tok_list called in ecryptfs_parse_packet_set or
13958c2ecf20Sopenharmony_ci	 * at end of function upon failure */
13968c2ecf20Sopenharmony_ci	auth_tok_list_item =
13978c2ecf20Sopenharmony_ci	    kmem_cache_zalloc(ecryptfs_auth_tok_list_item_cache, GFP_KERNEL);
13988c2ecf20Sopenharmony_ci	if (!auth_tok_list_item) {
13998c2ecf20Sopenharmony_ci		printk(KERN_ERR "Unable to allocate memory\n");
14008c2ecf20Sopenharmony_ci		rc = -ENOMEM;
14018c2ecf20Sopenharmony_ci		goto out;
14028c2ecf20Sopenharmony_ci	}
14038c2ecf20Sopenharmony_ci	(*new_auth_tok) = &auth_tok_list_item->auth_tok;
14048c2ecf20Sopenharmony_ci	rc = ecryptfs_parse_packet_length(&data[(*packet_size)], &body_size,
14058c2ecf20Sopenharmony_ci					  &length_size);
14068c2ecf20Sopenharmony_ci	if (rc) {
14078c2ecf20Sopenharmony_ci		printk(KERN_WARNING "Error parsing packet length; rc = [%d]\n",
14088c2ecf20Sopenharmony_ci		       rc);
14098c2ecf20Sopenharmony_ci		goto out_free;
14108c2ecf20Sopenharmony_ci	}
14118c2ecf20Sopenharmony_ci	if (unlikely(body_size < (ECRYPTFS_SALT_SIZE + 5))) {
14128c2ecf20Sopenharmony_ci		printk(KERN_WARNING "Invalid body size ([%td])\n", body_size);
14138c2ecf20Sopenharmony_ci		rc = -EINVAL;
14148c2ecf20Sopenharmony_ci		goto out_free;
14158c2ecf20Sopenharmony_ci	}
14168c2ecf20Sopenharmony_ci	(*packet_size) += length_size;
14178c2ecf20Sopenharmony_ci	if (unlikely((*packet_size) + body_size > max_packet_size)) {
14188c2ecf20Sopenharmony_ci		printk(KERN_ERR "Packet size exceeds max\n");
14198c2ecf20Sopenharmony_ci		rc = -EINVAL;
14208c2ecf20Sopenharmony_ci		goto out_free;
14218c2ecf20Sopenharmony_ci	}
14228c2ecf20Sopenharmony_ci	(*new_auth_tok)->session_key.encrypted_key_size =
14238c2ecf20Sopenharmony_ci		(body_size - (ECRYPTFS_SALT_SIZE + 5));
14248c2ecf20Sopenharmony_ci	if ((*new_auth_tok)->session_key.encrypted_key_size
14258c2ecf20Sopenharmony_ci	    > ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES) {
14268c2ecf20Sopenharmony_ci		printk(KERN_WARNING "Tag 3 packet contains key larger "
14278c2ecf20Sopenharmony_ci		       "than ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES\n");
14288c2ecf20Sopenharmony_ci		rc = -EINVAL;
14298c2ecf20Sopenharmony_ci		goto out_free;
14308c2ecf20Sopenharmony_ci	}
14318c2ecf20Sopenharmony_ci	if (unlikely(data[(*packet_size)++] != 0x04)) {
14328c2ecf20Sopenharmony_ci		printk(KERN_WARNING "Unknown version number [%d]\n",
14338c2ecf20Sopenharmony_ci		       data[(*packet_size) - 1]);
14348c2ecf20Sopenharmony_ci		rc = -EINVAL;
14358c2ecf20Sopenharmony_ci		goto out_free;
14368c2ecf20Sopenharmony_ci	}
14378c2ecf20Sopenharmony_ci	rc = ecryptfs_cipher_code_to_string(crypt_stat->cipher,
14388c2ecf20Sopenharmony_ci					    (u16)data[(*packet_size)]);
14398c2ecf20Sopenharmony_ci	if (rc)
14408c2ecf20Sopenharmony_ci		goto out_free;
14418c2ecf20Sopenharmony_ci	/* A little extra work to differentiate among the AES key
14428c2ecf20Sopenharmony_ci	 * sizes; see RFC2440 */
14438c2ecf20Sopenharmony_ci	switch(data[(*packet_size)++]) {
14448c2ecf20Sopenharmony_ci	case RFC2440_CIPHER_AES_192:
14458c2ecf20Sopenharmony_ci		crypt_stat->key_size = 24;
14468c2ecf20Sopenharmony_ci		break;
14478c2ecf20Sopenharmony_ci	default:
14488c2ecf20Sopenharmony_ci		crypt_stat->key_size =
14498c2ecf20Sopenharmony_ci			(*new_auth_tok)->session_key.encrypted_key_size;
14508c2ecf20Sopenharmony_ci	}
14518c2ecf20Sopenharmony_ci	rc = ecryptfs_init_crypt_ctx(crypt_stat);
14528c2ecf20Sopenharmony_ci	if (rc)
14538c2ecf20Sopenharmony_ci		goto out_free;
14548c2ecf20Sopenharmony_ci	if (unlikely(data[(*packet_size)++] != 0x03)) {
14558c2ecf20Sopenharmony_ci		printk(KERN_WARNING "Only S2K ID 3 is currently supported\n");
14568c2ecf20Sopenharmony_ci		rc = -ENOSYS;
14578c2ecf20Sopenharmony_ci		goto out_free;
14588c2ecf20Sopenharmony_ci	}
14598c2ecf20Sopenharmony_ci	/* TODO: finish the hash mapping */
14608c2ecf20Sopenharmony_ci	switch (data[(*packet_size)++]) {
14618c2ecf20Sopenharmony_ci	case 0x01: /* See RFC2440 for these numbers and their mappings */
14628c2ecf20Sopenharmony_ci		/* Choose MD5 */
14638c2ecf20Sopenharmony_ci		memcpy((*new_auth_tok)->token.password.salt,
14648c2ecf20Sopenharmony_ci		       &data[(*packet_size)], ECRYPTFS_SALT_SIZE);
14658c2ecf20Sopenharmony_ci		(*packet_size) += ECRYPTFS_SALT_SIZE;
14668c2ecf20Sopenharmony_ci		/* This conversion was taken straight from RFC2440 */
14678c2ecf20Sopenharmony_ci		(*new_auth_tok)->token.password.hash_iterations =
14688c2ecf20Sopenharmony_ci			((u32) 16 + (data[(*packet_size)] & 15))
14698c2ecf20Sopenharmony_ci				<< ((data[(*packet_size)] >> 4) + 6);
14708c2ecf20Sopenharmony_ci		(*packet_size)++;
14718c2ecf20Sopenharmony_ci		/* Friendly reminder:
14728c2ecf20Sopenharmony_ci		 * (*new_auth_tok)->session_key.encrypted_key_size =
14738c2ecf20Sopenharmony_ci		 *         (body_size - (ECRYPTFS_SALT_SIZE + 5)); */
14748c2ecf20Sopenharmony_ci		memcpy((*new_auth_tok)->session_key.encrypted_key,
14758c2ecf20Sopenharmony_ci		       &data[(*packet_size)],
14768c2ecf20Sopenharmony_ci		       (*new_auth_tok)->session_key.encrypted_key_size);
14778c2ecf20Sopenharmony_ci		(*packet_size) +=
14788c2ecf20Sopenharmony_ci			(*new_auth_tok)->session_key.encrypted_key_size;
14798c2ecf20Sopenharmony_ci		(*new_auth_tok)->session_key.flags &=
14808c2ecf20Sopenharmony_ci			~ECRYPTFS_CONTAINS_DECRYPTED_KEY;
14818c2ecf20Sopenharmony_ci		(*new_auth_tok)->session_key.flags |=
14828c2ecf20Sopenharmony_ci			ECRYPTFS_CONTAINS_ENCRYPTED_KEY;
14838c2ecf20Sopenharmony_ci		(*new_auth_tok)->token.password.hash_algo = 0x01; /* MD5 */
14848c2ecf20Sopenharmony_ci		break;
14858c2ecf20Sopenharmony_ci	default:
14868c2ecf20Sopenharmony_ci		ecryptfs_printk(KERN_ERR, "Unsupported hash algorithm: "
14878c2ecf20Sopenharmony_ci				"[%d]\n", data[(*packet_size) - 1]);
14888c2ecf20Sopenharmony_ci		rc = -ENOSYS;
14898c2ecf20Sopenharmony_ci		goto out_free;
14908c2ecf20Sopenharmony_ci	}
14918c2ecf20Sopenharmony_ci	(*new_auth_tok)->token_type = ECRYPTFS_PASSWORD;
14928c2ecf20Sopenharmony_ci	/* TODO: Parametarize; we might actually want userspace to
14938c2ecf20Sopenharmony_ci	 * decrypt the session key. */
14948c2ecf20Sopenharmony_ci	(*new_auth_tok)->session_key.flags &=
14958c2ecf20Sopenharmony_ci			    ~(ECRYPTFS_USERSPACE_SHOULD_TRY_TO_DECRYPT);
14968c2ecf20Sopenharmony_ci	(*new_auth_tok)->session_key.flags &=
14978c2ecf20Sopenharmony_ci			    ~(ECRYPTFS_USERSPACE_SHOULD_TRY_TO_ENCRYPT);
14988c2ecf20Sopenharmony_ci	list_add(&auth_tok_list_item->list, auth_tok_list);
14998c2ecf20Sopenharmony_ci	goto out;
15008c2ecf20Sopenharmony_ciout_free:
15018c2ecf20Sopenharmony_ci	(*new_auth_tok) = NULL;
15028c2ecf20Sopenharmony_ci	memset(auth_tok_list_item, 0,
15038c2ecf20Sopenharmony_ci	       sizeof(struct ecryptfs_auth_tok_list_item));
15048c2ecf20Sopenharmony_ci	kmem_cache_free(ecryptfs_auth_tok_list_item_cache,
15058c2ecf20Sopenharmony_ci			auth_tok_list_item);
15068c2ecf20Sopenharmony_ciout:
15078c2ecf20Sopenharmony_ci	if (rc)
15088c2ecf20Sopenharmony_ci		(*packet_size) = 0;
15098c2ecf20Sopenharmony_ci	return rc;
15108c2ecf20Sopenharmony_ci}
15118c2ecf20Sopenharmony_ci
15128c2ecf20Sopenharmony_ci/**
15138c2ecf20Sopenharmony_ci * parse_tag_11_packet
15148c2ecf20Sopenharmony_ci * @data: The raw bytes of the packet
15158c2ecf20Sopenharmony_ci * @contents: This function writes the data contents of the literal
15168c2ecf20Sopenharmony_ci *            packet into this memory location
15178c2ecf20Sopenharmony_ci * @max_contents_bytes: The maximum number of bytes that this function
15188c2ecf20Sopenharmony_ci *                      is allowed to write into contents
15198c2ecf20Sopenharmony_ci * @tag_11_contents_size: This function writes the size of the parsed
15208c2ecf20Sopenharmony_ci *                        contents into this memory location; zero on
15218c2ecf20Sopenharmony_ci *                        error
15228c2ecf20Sopenharmony_ci * @packet_size: This function writes the size of the parsed packet
15238c2ecf20Sopenharmony_ci *               into this memory location; zero on error
15248c2ecf20Sopenharmony_ci * @max_packet_size: maximum number of bytes to parse
15258c2ecf20Sopenharmony_ci *
15268c2ecf20Sopenharmony_ci * Returns zero on success; non-zero on error.
15278c2ecf20Sopenharmony_ci */
15288c2ecf20Sopenharmony_cistatic int
15298c2ecf20Sopenharmony_ciparse_tag_11_packet(unsigned char *data, unsigned char *contents,
15308c2ecf20Sopenharmony_ci		    size_t max_contents_bytes, size_t *tag_11_contents_size,
15318c2ecf20Sopenharmony_ci		    size_t *packet_size, size_t max_packet_size)
15328c2ecf20Sopenharmony_ci{
15338c2ecf20Sopenharmony_ci	size_t body_size;
15348c2ecf20Sopenharmony_ci	size_t length_size;
15358c2ecf20Sopenharmony_ci	int rc = 0;
15368c2ecf20Sopenharmony_ci
15378c2ecf20Sopenharmony_ci	(*packet_size) = 0;
15388c2ecf20Sopenharmony_ci	(*tag_11_contents_size) = 0;
15398c2ecf20Sopenharmony_ci	/* This format is inspired by OpenPGP; see RFC 2440
15408c2ecf20Sopenharmony_ci	 * packet tag 11
15418c2ecf20Sopenharmony_ci	 *
15428c2ecf20Sopenharmony_ci	 * Tag 11 identifier (1 byte)
15438c2ecf20Sopenharmony_ci	 * Max Tag 11 packet size (max 3 bytes)
15448c2ecf20Sopenharmony_ci	 * Binary format specifier (1 byte)
15458c2ecf20Sopenharmony_ci	 * Filename length (1 byte)
15468c2ecf20Sopenharmony_ci	 * Filename ("_CONSOLE") (8 bytes)
15478c2ecf20Sopenharmony_ci	 * Modification date (4 bytes)
15488c2ecf20Sopenharmony_ci	 * Literal data (arbitrary)
15498c2ecf20Sopenharmony_ci	 *
15508c2ecf20Sopenharmony_ci	 * We need at least 16 bytes of data for the packet to even be
15518c2ecf20Sopenharmony_ci	 * valid.
15528c2ecf20Sopenharmony_ci	 */
15538c2ecf20Sopenharmony_ci	if (max_packet_size < 16) {
15548c2ecf20Sopenharmony_ci		printk(KERN_ERR "Maximum packet size too small\n");
15558c2ecf20Sopenharmony_ci		rc = -EINVAL;
15568c2ecf20Sopenharmony_ci		goto out;
15578c2ecf20Sopenharmony_ci	}
15588c2ecf20Sopenharmony_ci	if (data[(*packet_size)++] != ECRYPTFS_TAG_11_PACKET_TYPE) {
15598c2ecf20Sopenharmony_ci		printk(KERN_WARNING "Invalid tag 11 packet format\n");
15608c2ecf20Sopenharmony_ci		rc = -EINVAL;
15618c2ecf20Sopenharmony_ci		goto out;
15628c2ecf20Sopenharmony_ci	}
15638c2ecf20Sopenharmony_ci	rc = ecryptfs_parse_packet_length(&data[(*packet_size)], &body_size,
15648c2ecf20Sopenharmony_ci					  &length_size);
15658c2ecf20Sopenharmony_ci	if (rc) {
15668c2ecf20Sopenharmony_ci		printk(KERN_WARNING "Invalid tag 11 packet format\n");
15678c2ecf20Sopenharmony_ci		goto out;
15688c2ecf20Sopenharmony_ci	}
15698c2ecf20Sopenharmony_ci	if (body_size < 14) {
15708c2ecf20Sopenharmony_ci		printk(KERN_WARNING "Invalid body size ([%td])\n", body_size);
15718c2ecf20Sopenharmony_ci		rc = -EINVAL;
15728c2ecf20Sopenharmony_ci		goto out;
15738c2ecf20Sopenharmony_ci	}
15748c2ecf20Sopenharmony_ci	(*packet_size) += length_size;
15758c2ecf20Sopenharmony_ci	(*tag_11_contents_size) = (body_size - 14);
15768c2ecf20Sopenharmony_ci	if (unlikely((*packet_size) + body_size + 1 > max_packet_size)) {
15778c2ecf20Sopenharmony_ci		printk(KERN_ERR "Packet size exceeds max\n");
15788c2ecf20Sopenharmony_ci		rc = -EINVAL;
15798c2ecf20Sopenharmony_ci		goto out;
15808c2ecf20Sopenharmony_ci	}
15818c2ecf20Sopenharmony_ci	if (unlikely((*tag_11_contents_size) > max_contents_bytes)) {
15828c2ecf20Sopenharmony_ci		printk(KERN_ERR "Literal data section in tag 11 packet exceeds "
15838c2ecf20Sopenharmony_ci		       "expected size\n");
15848c2ecf20Sopenharmony_ci		rc = -EINVAL;
15858c2ecf20Sopenharmony_ci		goto out;
15868c2ecf20Sopenharmony_ci	}
15878c2ecf20Sopenharmony_ci	if (data[(*packet_size)++] != 0x62) {
15888c2ecf20Sopenharmony_ci		printk(KERN_WARNING "Unrecognizable packet\n");
15898c2ecf20Sopenharmony_ci		rc = -EINVAL;
15908c2ecf20Sopenharmony_ci		goto out;
15918c2ecf20Sopenharmony_ci	}
15928c2ecf20Sopenharmony_ci	if (data[(*packet_size)++] != 0x08) {
15938c2ecf20Sopenharmony_ci		printk(KERN_WARNING "Unrecognizable packet\n");
15948c2ecf20Sopenharmony_ci		rc = -EINVAL;
15958c2ecf20Sopenharmony_ci		goto out;
15968c2ecf20Sopenharmony_ci	}
15978c2ecf20Sopenharmony_ci	(*packet_size) += 12; /* Ignore filename and modification date */
15988c2ecf20Sopenharmony_ci	memcpy(contents, &data[(*packet_size)], (*tag_11_contents_size));
15998c2ecf20Sopenharmony_ci	(*packet_size) += (*tag_11_contents_size);
16008c2ecf20Sopenharmony_ciout:
16018c2ecf20Sopenharmony_ci	if (rc) {
16028c2ecf20Sopenharmony_ci		(*packet_size) = 0;
16038c2ecf20Sopenharmony_ci		(*tag_11_contents_size) = 0;
16048c2ecf20Sopenharmony_ci	}
16058c2ecf20Sopenharmony_ci	return rc;
16068c2ecf20Sopenharmony_ci}
16078c2ecf20Sopenharmony_ci
16088c2ecf20Sopenharmony_ciint ecryptfs_keyring_auth_tok_for_sig(struct key **auth_tok_key,
16098c2ecf20Sopenharmony_ci				      struct ecryptfs_auth_tok **auth_tok,
16108c2ecf20Sopenharmony_ci				      char *sig)
16118c2ecf20Sopenharmony_ci{
16128c2ecf20Sopenharmony_ci	int rc = 0;
16138c2ecf20Sopenharmony_ci
16148c2ecf20Sopenharmony_ci	(*auth_tok_key) = request_key(&key_type_user, sig, NULL);
16158c2ecf20Sopenharmony_ci	if (IS_ERR(*auth_tok_key)) {
16168c2ecf20Sopenharmony_ci		(*auth_tok_key) = ecryptfs_get_encrypted_key(sig);
16178c2ecf20Sopenharmony_ci		if (IS_ERR(*auth_tok_key)) {
16188c2ecf20Sopenharmony_ci			printk(KERN_ERR "Could not find key with description: [%s]\n",
16198c2ecf20Sopenharmony_ci			      sig);
16208c2ecf20Sopenharmony_ci			rc = process_request_key_err(PTR_ERR(*auth_tok_key));
16218c2ecf20Sopenharmony_ci			(*auth_tok_key) = NULL;
16228c2ecf20Sopenharmony_ci			goto out;
16238c2ecf20Sopenharmony_ci		}
16248c2ecf20Sopenharmony_ci	}
16258c2ecf20Sopenharmony_ci	down_write(&(*auth_tok_key)->sem);
16268c2ecf20Sopenharmony_ci	rc = ecryptfs_verify_auth_tok_from_key(*auth_tok_key, auth_tok);
16278c2ecf20Sopenharmony_ci	if (rc) {
16288c2ecf20Sopenharmony_ci		up_write(&(*auth_tok_key)->sem);
16298c2ecf20Sopenharmony_ci		key_put(*auth_tok_key);
16308c2ecf20Sopenharmony_ci		(*auth_tok_key) = NULL;
16318c2ecf20Sopenharmony_ci		goto out;
16328c2ecf20Sopenharmony_ci	}
16338c2ecf20Sopenharmony_ciout:
16348c2ecf20Sopenharmony_ci	return rc;
16358c2ecf20Sopenharmony_ci}
16368c2ecf20Sopenharmony_ci
16378c2ecf20Sopenharmony_ci/**
16388c2ecf20Sopenharmony_ci * decrypt_passphrase_encrypted_session_key - Decrypt the session key with the given auth_tok.
16398c2ecf20Sopenharmony_ci * @auth_tok: The passphrase authentication token to use to encrypt the FEK
16408c2ecf20Sopenharmony_ci * @crypt_stat: The cryptographic context
16418c2ecf20Sopenharmony_ci *
16428c2ecf20Sopenharmony_ci * Returns zero on success; non-zero error otherwise
16438c2ecf20Sopenharmony_ci */
16448c2ecf20Sopenharmony_cistatic int
16458c2ecf20Sopenharmony_cidecrypt_passphrase_encrypted_session_key(struct ecryptfs_auth_tok *auth_tok,
16468c2ecf20Sopenharmony_ci					 struct ecryptfs_crypt_stat *crypt_stat)
16478c2ecf20Sopenharmony_ci{
16488c2ecf20Sopenharmony_ci	struct scatterlist dst_sg[2];
16498c2ecf20Sopenharmony_ci	struct scatterlist src_sg[2];
16508c2ecf20Sopenharmony_ci	struct mutex *tfm_mutex;
16518c2ecf20Sopenharmony_ci	struct crypto_skcipher *tfm;
16528c2ecf20Sopenharmony_ci	struct skcipher_request *req = NULL;
16538c2ecf20Sopenharmony_ci	int rc = 0;
16548c2ecf20Sopenharmony_ci
16558c2ecf20Sopenharmony_ci	if (unlikely(ecryptfs_verbosity > 0)) {
16568c2ecf20Sopenharmony_ci		ecryptfs_printk(
16578c2ecf20Sopenharmony_ci			KERN_DEBUG, "Session key encryption key (size [%d]):\n",
16588c2ecf20Sopenharmony_ci			auth_tok->token.password.session_key_encryption_key_bytes);
16598c2ecf20Sopenharmony_ci		ecryptfs_dump_hex(
16608c2ecf20Sopenharmony_ci			auth_tok->token.password.session_key_encryption_key,
16618c2ecf20Sopenharmony_ci			auth_tok->token.password.session_key_encryption_key_bytes);
16628c2ecf20Sopenharmony_ci	}
16638c2ecf20Sopenharmony_ci	rc = ecryptfs_get_tfm_and_mutex_for_cipher_name(&tfm, &tfm_mutex,
16648c2ecf20Sopenharmony_ci							crypt_stat->cipher);
16658c2ecf20Sopenharmony_ci	if (unlikely(rc)) {
16668c2ecf20Sopenharmony_ci		printk(KERN_ERR "Internal error whilst attempting to get "
16678c2ecf20Sopenharmony_ci		       "tfm and mutex for cipher name [%s]; rc = [%d]\n",
16688c2ecf20Sopenharmony_ci		       crypt_stat->cipher, rc);
16698c2ecf20Sopenharmony_ci		goto out;
16708c2ecf20Sopenharmony_ci	}
16718c2ecf20Sopenharmony_ci	rc = virt_to_scatterlist(auth_tok->session_key.encrypted_key,
16728c2ecf20Sopenharmony_ci				 auth_tok->session_key.encrypted_key_size,
16738c2ecf20Sopenharmony_ci				 src_sg, 2);
16748c2ecf20Sopenharmony_ci	if (rc < 1 || rc > 2) {
16758c2ecf20Sopenharmony_ci		printk(KERN_ERR "Internal error whilst attempting to convert "
16768c2ecf20Sopenharmony_ci			"auth_tok->session_key.encrypted_key to scatterlist; "
16778c2ecf20Sopenharmony_ci			"expected rc = 1; got rc = [%d]. "
16788c2ecf20Sopenharmony_ci		       "auth_tok->session_key.encrypted_key_size = [%d]\n", rc,
16798c2ecf20Sopenharmony_ci			auth_tok->session_key.encrypted_key_size);
16808c2ecf20Sopenharmony_ci		goto out;
16818c2ecf20Sopenharmony_ci	}
16828c2ecf20Sopenharmony_ci	auth_tok->session_key.decrypted_key_size =
16838c2ecf20Sopenharmony_ci		auth_tok->session_key.encrypted_key_size;
16848c2ecf20Sopenharmony_ci	rc = virt_to_scatterlist(auth_tok->session_key.decrypted_key,
16858c2ecf20Sopenharmony_ci				 auth_tok->session_key.decrypted_key_size,
16868c2ecf20Sopenharmony_ci				 dst_sg, 2);
16878c2ecf20Sopenharmony_ci	if (rc < 1 || rc > 2) {
16888c2ecf20Sopenharmony_ci		printk(KERN_ERR "Internal error whilst attempting to convert "
16898c2ecf20Sopenharmony_ci			"auth_tok->session_key.decrypted_key to scatterlist; "
16908c2ecf20Sopenharmony_ci			"expected rc = 1; got rc = [%d]\n", rc);
16918c2ecf20Sopenharmony_ci		goto out;
16928c2ecf20Sopenharmony_ci	}
16938c2ecf20Sopenharmony_ci	mutex_lock(tfm_mutex);
16948c2ecf20Sopenharmony_ci	req = skcipher_request_alloc(tfm, GFP_KERNEL);
16958c2ecf20Sopenharmony_ci	if (!req) {
16968c2ecf20Sopenharmony_ci		mutex_unlock(tfm_mutex);
16978c2ecf20Sopenharmony_ci		printk(KERN_ERR "%s: Out of kernel memory whilst attempting to "
16988c2ecf20Sopenharmony_ci		       "skcipher_request_alloc for %s\n", __func__,
16998c2ecf20Sopenharmony_ci		       crypto_skcipher_driver_name(tfm));
17008c2ecf20Sopenharmony_ci		rc = -ENOMEM;
17018c2ecf20Sopenharmony_ci		goto out;
17028c2ecf20Sopenharmony_ci	}
17038c2ecf20Sopenharmony_ci
17048c2ecf20Sopenharmony_ci	skcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_SLEEP,
17058c2ecf20Sopenharmony_ci				      NULL, NULL);
17068c2ecf20Sopenharmony_ci	rc = crypto_skcipher_setkey(
17078c2ecf20Sopenharmony_ci		tfm, auth_tok->token.password.session_key_encryption_key,
17088c2ecf20Sopenharmony_ci		crypt_stat->key_size);
17098c2ecf20Sopenharmony_ci	if (unlikely(rc < 0)) {
17108c2ecf20Sopenharmony_ci		mutex_unlock(tfm_mutex);
17118c2ecf20Sopenharmony_ci		printk(KERN_ERR "Error setting key for crypto context\n");
17128c2ecf20Sopenharmony_ci		rc = -EINVAL;
17138c2ecf20Sopenharmony_ci		goto out;
17148c2ecf20Sopenharmony_ci	}
17158c2ecf20Sopenharmony_ci	skcipher_request_set_crypt(req, src_sg, dst_sg,
17168c2ecf20Sopenharmony_ci				   auth_tok->session_key.encrypted_key_size,
17178c2ecf20Sopenharmony_ci				   NULL);
17188c2ecf20Sopenharmony_ci	rc = crypto_skcipher_decrypt(req);
17198c2ecf20Sopenharmony_ci	mutex_unlock(tfm_mutex);
17208c2ecf20Sopenharmony_ci	if (unlikely(rc)) {
17218c2ecf20Sopenharmony_ci		printk(KERN_ERR "Error decrypting; rc = [%d]\n", rc);
17228c2ecf20Sopenharmony_ci		goto out;
17238c2ecf20Sopenharmony_ci	}
17248c2ecf20Sopenharmony_ci	auth_tok->session_key.flags |= ECRYPTFS_CONTAINS_DECRYPTED_KEY;
17258c2ecf20Sopenharmony_ci	memcpy(crypt_stat->key, auth_tok->session_key.decrypted_key,
17268c2ecf20Sopenharmony_ci	       auth_tok->session_key.decrypted_key_size);
17278c2ecf20Sopenharmony_ci	crypt_stat->flags |= ECRYPTFS_KEY_VALID;
17288c2ecf20Sopenharmony_ci	if (unlikely(ecryptfs_verbosity > 0)) {
17298c2ecf20Sopenharmony_ci		ecryptfs_printk(KERN_DEBUG, "FEK of size [%zd]:\n",
17308c2ecf20Sopenharmony_ci				crypt_stat->key_size);
17318c2ecf20Sopenharmony_ci		ecryptfs_dump_hex(crypt_stat->key,
17328c2ecf20Sopenharmony_ci				  crypt_stat->key_size);
17338c2ecf20Sopenharmony_ci	}
17348c2ecf20Sopenharmony_ciout:
17358c2ecf20Sopenharmony_ci	skcipher_request_free(req);
17368c2ecf20Sopenharmony_ci	return rc;
17378c2ecf20Sopenharmony_ci}
17388c2ecf20Sopenharmony_ci
17398c2ecf20Sopenharmony_ci/**
17408c2ecf20Sopenharmony_ci * ecryptfs_parse_packet_set
17418c2ecf20Sopenharmony_ci * @crypt_stat: The cryptographic context
17428c2ecf20Sopenharmony_ci * @src: Virtual address of region of memory containing the packets
17438c2ecf20Sopenharmony_ci * @ecryptfs_dentry: The eCryptfs dentry associated with the packet set
17448c2ecf20Sopenharmony_ci *
17458c2ecf20Sopenharmony_ci * Get crypt_stat to have the file's session key if the requisite key
17468c2ecf20Sopenharmony_ci * is available to decrypt the session key.
17478c2ecf20Sopenharmony_ci *
17488c2ecf20Sopenharmony_ci * Returns Zero if a valid authentication token was retrieved and
17498c2ecf20Sopenharmony_ci * processed; negative value for file not encrypted or for error
17508c2ecf20Sopenharmony_ci * conditions.
17518c2ecf20Sopenharmony_ci */
17528c2ecf20Sopenharmony_ciint ecryptfs_parse_packet_set(struct ecryptfs_crypt_stat *crypt_stat,
17538c2ecf20Sopenharmony_ci			      unsigned char *src,
17548c2ecf20Sopenharmony_ci			      struct dentry *ecryptfs_dentry)
17558c2ecf20Sopenharmony_ci{
17568c2ecf20Sopenharmony_ci	size_t i = 0;
17578c2ecf20Sopenharmony_ci	size_t found_auth_tok;
17588c2ecf20Sopenharmony_ci	size_t next_packet_is_auth_tok_packet;
17598c2ecf20Sopenharmony_ci	struct list_head auth_tok_list;
17608c2ecf20Sopenharmony_ci	struct ecryptfs_auth_tok *matching_auth_tok;
17618c2ecf20Sopenharmony_ci	struct ecryptfs_auth_tok *candidate_auth_tok;
17628c2ecf20Sopenharmony_ci	char *candidate_auth_tok_sig;
17638c2ecf20Sopenharmony_ci	size_t packet_size;
17648c2ecf20Sopenharmony_ci	struct ecryptfs_auth_tok *new_auth_tok;
17658c2ecf20Sopenharmony_ci	unsigned char sig_tmp_space[ECRYPTFS_SIG_SIZE];
17668c2ecf20Sopenharmony_ci	struct ecryptfs_auth_tok_list_item *auth_tok_list_item;
17678c2ecf20Sopenharmony_ci	size_t tag_11_contents_size;
17688c2ecf20Sopenharmony_ci	size_t tag_11_packet_size;
17698c2ecf20Sopenharmony_ci	struct key *auth_tok_key = NULL;
17708c2ecf20Sopenharmony_ci	int rc = 0;
17718c2ecf20Sopenharmony_ci
17728c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&auth_tok_list);
17738c2ecf20Sopenharmony_ci	/* Parse the header to find as many packets as we can; these will be
17748c2ecf20Sopenharmony_ci	 * added the our &auth_tok_list */
17758c2ecf20Sopenharmony_ci	next_packet_is_auth_tok_packet = 1;
17768c2ecf20Sopenharmony_ci	while (next_packet_is_auth_tok_packet) {
17778c2ecf20Sopenharmony_ci		size_t max_packet_size = ((PAGE_SIZE - 8) - i);
17788c2ecf20Sopenharmony_ci
17798c2ecf20Sopenharmony_ci		switch (src[i]) {
17808c2ecf20Sopenharmony_ci		case ECRYPTFS_TAG_3_PACKET_TYPE:
17818c2ecf20Sopenharmony_ci			rc = parse_tag_3_packet(crypt_stat,
17828c2ecf20Sopenharmony_ci						(unsigned char *)&src[i],
17838c2ecf20Sopenharmony_ci						&auth_tok_list, &new_auth_tok,
17848c2ecf20Sopenharmony_ci						&packet_size, max_packet_size);
17858c2ecf20Sopenharmony_ci			if (rc) {
17868c2ecf20Sopenharmony_ci				ecryptfs_printk(KERN_ERR, "Error parsing "
17878c2ecf20Sopenharmony_ci						"tag 3 packet\n");
17888c2ecf20Sopenharmony_ci				rc = -EIO;
17898c2ecf20Sopenharmony_ci				goto out_wipe_list;
17908c2ecf20Sopenharmony_ci			}
17918c2ecf20Sopenharmony_ci			i += packet_size;
17928c2ecf20Sopenharmony_ci			rc = parse_tag_11_packet((unsigned char *)&src[i],
17938c2ecf20Sopenharmony_ci						 sig_tmp_space,
17948c2ecf20Sopenharmony_ci						 ECRYPTFS_SIG_SIZE,
17958c2ecf20Sopenharmony_ci						 &tag_11_contents_size,
17968c2ecf20Sopenharmony_ci						 &tag_11_packet_size,
17978c2ecf20Sopenharmony_ci						 max_packet_size);
17988c2ecf20Sopenharmony_ci			if (rc) {
17998c2ecf20Sopenharmony_ci				ecryptfs_printk(KERN_ERR, "No valid "
18008c2ecf20Sopenharmony_ci						"(ecryptfs-specific) literal "
18018c2ecf20Sopenharmony_ci						"packet containing "
18028c2ecf20Sopenharmony_ci						"authentication token "
18038c2ecf20Sopenharmony_ci						"signature found after "
18048c2ecf20Sopenharmony_ci						"tag 3 packet\n");
18058c2ecf20Sopenharmony_ci				rc = -EIO;
18068c2ecf20Sopenharmony_ci				goto out_wipe_list;
18078c2ecf20Sopenharmony_ci			}
18088c2ecf20Sopenharmony_ci			i += tag_11_packet_size;
18098c2ecf20Sopenharmony_ci			if (ECRYPTFS_SIG_SIZE != tag_11_contents_size) {
18108c2ecf20Sopenharmony_ci				ecryptfs_printk(KERN_ERR, "Expected "
18118c2ecf20Sopenharmony_ci						"signature of size [%d]; "
18128c2ecf20Sopenharmony_ci						"read size [%zd]\n",
18138c2ecf20Sopenharmony_ci						ECRYPTFS_SIG_SIZE,
18148c2ecf20Sopenharmony_ci						tag_11_contents_size);
18158c2ecf20Sopenharmony_ci				rc = -EIO;
18168c2ecf20Sopenharmony_ci				goto out_wipe_list;
18178c2ecf20Sopenharmony_ci			}
18188c2ecf20Sopenharmony_ci			ecryptfs_to_hex(new_auth_tok->token.password.signature,
18198c2ecf20Sopenharmony_ci					sig_tmp_space, tag_11_contents_size);
18208c2ecf20Sopenharmony_ci			new_auth_tok->token.password.signature[
18218c2ecf20Sopenharmony_ci				ECRYPTFS_PASSWORD_SIG_SIZE] = '\0';
18228c2ecf20Sopenharmony_ci			crypt_stat->flags |= ECRYPTFS_ENCRYPTED;
18238c2ecf20Sopenharmony_ci			break;
18248c2ecf20Sopenharmony_ci		case ECRYPTFS_TAG_1_PACKET_TYPE:
18258c2ecf20Sopenharmony_ci			rc = parse_tag_1_packet(crypt_stat,
18268c2ecf20Sopenharmony_ci						(unsigned char *)&src[i],
18278c2ecf20Sopenharmony_ci						&auth_tok_list, &new_auth_tok,
18288c2ecf20Sopenharmony_ci						&packet_size, max_packet_size);
18298c2ecf20Sopenharmony_ci			if (rc) {
18308c2ecf20Sopenharmony_ci				ecryptfs_printk(KERN_ERR, "Error parsing "
18318c2ecf20Sopenharmony_ci						"tag 1 packet\n");
18328c2ecf20Sopenharmony_ci				rc = -EIO;
18338c2ecf20Sopenharmony_ci				goto out_wipe_list;
18348c2ecf20Sopenharmony_ci			}
18358c2ecf20Sopenharmony_ci			i += packet_size;
18368c2ecf20Sopenharmony_ci			crypt_stat->flags |= ECRYPTFS_ENCRYPTED;
18378c2ecf20Sopenharmony_ci			break;
18388c2ecf20Sopenharmony_ci		case ECRYPTFS_TAG_11_PACKET_TYPE:
18398c2ecf20Sopenharmony_ci			ecryptfs_printk(KERN_WARNING, "Invalid packet set "
18408c2ecf20Sopenharmony_ci					"(Tag 11 not allowed by itself)\n");
18418c2ecf20Sopenharmony_ci			rc = -EIO;
18428c2ecf20Sopenharmony_ci			goto out_wipe_list;
18438c2ecf20Sopenharmony_ci		default:
18448c2ecf20Sopenharmony_ci			ecryptfs_printk(KERN_DEBUG, "No packet at offset [%zd] "
18458c2ecf20Sopenharmony_ci					"of the file header; hex value of "
18468c2ecf20Sopenharmony_ci					"character is [0x%.2x]\n", i, src[i]);
18478c2ecf20Sopenharmony_ci			next_packet_is_auth_tok_packet = 0;
18488c2ecf20Sopenharmony_ci		}
18498c2ecf20Sopenharmony_ci	}
18508c2ecf20Sopenharmony_ci	if (list_empty(&auth_tok_list)) {
18518c2ecf20Sopenharmony_ci		printk(KERN_ERR "The lower file appears to be a non-encrypted "
18528c2ecf20Sopenharmony_ci		       "eCryptfs file; this is not supported in this version "
18538c2ecf20Sopenharmony_ci		       "of the eCryptfs kernel module\n");
18548c2ecf20Sopenharmony_ci		rc = -EINVAL;
18558c2ecf20Sopenharmony_ci		goto out;
18568c2ecf20Sopenharmony_ci	}
18578c2ecf20Sopenharmony_ci	/* auth_tok_list contains the set of authentication tokens
18588c2ecf20Sopenharmony_ci	 * parsed from the metadata. We need to find a matching
18598c2ecf20Sopenharmony_ci	 * authentication token that has the secret component(s)
18608c2ecf20Sopenharmony_ci	 * necessary to decrypt the EFEK in the auth_tok parsed from
18618c2ecf20Sopenharmony_ci	 * the metadata. There may be several potential matches, but
18628c2ecf20Sopenharmony_ci	 * just one will be sufficient to decrypt to get the FEK. */
18638c2ecf20Sopenharmony_cifind_next_matching_auth_tok:
18648c2ecf20Sopenharmony_ci	found_auth_tok = 0;
18658c2ecf20Sopenharmony_ci	list_for_each_entry(auth_tok_list_item, &auth_tok_list, list) {
18668c2ecf20Sopenharmony_ci		candidate_auth_tok = &auth_tok_list_item->auth_tok;
18678c2ecf20Sopenharmony_ci		if (unlikely(ecryptfs_verbosity > 0)) {
18688c2ecf20Sopenharmony_ci			ecryptfs_printk(KERN_DEBUG,
18698c2ecf20Sopenharmony_ci					"Considering candidate auth tok:\n");
18708c2ecf20Sopenharmony_ci			ecryptfs_dump_auth_tok(candidate_auth_tok);
18718c2ecf20Sopenharmony_ci		}
18728c2ecf20Sopenharmony_ci		rc = ecryptfs_get_auth_tok_sig(&candidate_auth_tok_sig,
18738c2ecf20Sopenharmony_ci					       candidate_auth_tok);
18748c2ecf20Sopenharmony_ci		if (rc) {
18758c2ecf20Sopenharmony_ci			printk(KERN_ERR
18768c2ecf20Sopenharmony_ci			       "Unrecognized candidate auth tok type: [%d]\n",
18778c2ecf20Sopenharmony_ci			       candidate_auth_tok->token_type);
18788c2ecf20Sopenharmony_ci			rc = -EINVAL;
18798c2ecf20Sopenharmony_ci			goto out_wipe_list;
18808c2ecf20Sopenharmony_ci		}
18818c2ecf20Sopenharmony_ci		rc = ecryptfs_find_auth_tok_for_sig(&auth_tok_key,
18828c2ecf20Sopenharmony_ci					       &matching_auth_tok,
18838c2ecf20Sopenharmony_ci					       crypt_stat->mount_crypt_stat,
18848c2ecf20Sopenharmony_ci					       candidate_auth_tok_sig);
18858c2ecf20Sopenharmony_ci		if (!rc) {
18868c2ecf20Sopenharmony_ci			found_auth_tok = 1;
18878c2ecf20Sopenharmony_ci			goto found_matching_auth_tok;
18888c2ecf20Sopenharmony_ci		}
18898c2ecf20Sopenharmony_ci	}
18908c2ecf20Sopenharmony_ci	if (!found_auth_tok) {
18918c2ecf20Sopenharmony_ci		ecryptfs_printk(KERN_ERR, "Could not find a usable "
18928c2ecf20Sopenharmony_ci				"authentication token\n");
18938c2ecf20Sopenharmony_ci		rc = -EIO;
18948c2ecf20Sopenharmony_ci		goto out_wipe_list;
18958c2ecf20Sopenharmony_ci	}
18968c2ecf20Sopenharmony_cifound_matching_auth_tok:
18978c2ecf20Sopenharmony_ci	if (candidate_auth_tok->token_type == ECRYPTFS_PRIVATE_KEY) {
18988c2ecf20Sopenharmony_ci		memcpy(&(candidate_auth_tok->token.private_key),
18998c2ecf20Sopenharmony_ci		       &(matching_auth_tok->token.private_key),
19008c2ecf20Sopenharmony_ci		       sizeof(struct ecryptfs_private_key));
19018c2ecf20Sopenharmony_ci		up_write(&(auth_tok_key->sem));
19028c2ecf20Sopenharmony_ci		key_put(auth_tok_key);
19038c2ecf20Sopenharmony_ci		rc = decrypt_pki_encrypted_session_key(candidate_auth_tok,
19048c2ecf20Sopenharmony_ci						       crypt_stat);
19058c2ecf20Sopenharmony_ci	} else if (candidate_auth_tok->token_type == ECRYPTFS_PASSWORD) {
19068c2ecf20Sopenharmony_ci		memcpy(&(candidate_auth_tok->token.password),
19078c2ecf20Sopenharmony_ci		       &(matching_auth_tok->token.password),
19088c2ecf20Sopenharmony_ci		       sizeof(struct ecryptfs_password));
19098c2ecf20Sopenharmony_ci		up_write(&(auth_tok_key->sem));
19108c2ecf20Sopenharmony_ci		key_put(auth_tok_key);
19118c2ecf20Sopenharmony_ci		rc = decrypt_passphrase_encrypted_session_key(
19128c2ecf20Sopenharmony_ci			candidate_auth_tok, crypt_stat);
19138c2ecf20Sopenharmony_ci	} else {
19148c2ecf20Sopenharmony_ci		up_write(&(auth_tok_key->sem));
19158c2ecf20Sopenharmony_ci		key_put(auth_tok_key);
19168c2ecf20Sopenharmony_ci		rc = -EINVAL;
19178c2ecf20Sopenharmony_ci	}
19188c2ecf20Sopenharmony_ci	if (rc) {
19198c2ecf20Sopenharmony_ci		struct ecryptfs_auth_tok_list_item *auth_tok_list_item_tmp;
19208c2ecf20Sopenharmony_ci
19218c2ecf20Sopenharmony_ci		ecryptfs_printk(KERN_WARNING, "Error decrypting the "
19228c2ecf20Sopenharmony_ci				"session key for authentication token with sig "
19238c2ecf20Sopenharmony_ci				"[%.*s]; rc = [%d]. Removing auth tok "
19248c2ecf20Sopenharmony_ci				"candidate from the list and searching for "
19258c2ecf20Sopenharmony_ci				"the next match.\n", ECRYPTFS_SIG_SIZE_HEX,
19268c2ecf20Sopenharmony_ci				candidate_auth_tok_sig,	rc);
19278c2ecf20Sopenharmony_ci		list_for_each_entry_safe(auth_tok_list_item,
19288c2ecf20Sopenharmony_ci					 auth_tok_list_item_tmp,
19298c2ecf20Sopenharmony_ci					 &auth_tok_list, list) {
19308c2ecf20Sopenharmony_ci			if (candidate_auth_tok
19318c2ecf20Sopenharmony_ci			    == &auth_tok_list_item->auth_tok) {
19328c2ecf20Sopenharmony_ci				list_del(&auth_tok_list_item->list);
19338c2ecf20Sopenharmony_ci				kmem_cache_free(
19348c2ecf20Sopenharmony_ci					ecryptfs_auth_tok_list_item_cache,
19358c2ecf20Sopenharmony_ci					auth_tok_list_item);
19368c2ecf20Sopenharmony_ci				goto find_next_matching_auth_tok;
19378c2ecf20Sopenharmony_ci			}
19388c2ecf20Sopenharmony_ci		}
19398c2ecf20Sopenharmony_ci		BUG();
19408c2ecf20Sopenharmony_ci	}
19418c2ecf20Sopenharmony_ci	rc = ecryptfs_compute_root_iv(crypt_stat);
19428c2ecf20Sopenharmony_ci	if (rc) {
19438c2ecf20Sopenharmony_ci		ecryptfs_printk(KERN_ERR, "Error computing "
19448c2ecf20Sopenharmony_ci				"the root IV\n");
19458c2ecf20Sopenharmony_ci		goto out_wipe_list;
19468c2ecf20Sopenharmony_ci	}
19478c2ecf20Sopenharmony_ci	rc = ecryptfs_init_crypt_ctx(crypt_stat);
19488c2ecf20Sopenharmony_ci	if (rc) {
19498c2ecf20Sopenharmony_ci		ecryptfs_printk(KERN_ERR, "Error initializing crypto "
19508c2ecf20Sopenharmony_ci				"context for cipher [%s]; rc = [%d]\n",
19518c2ecf20Sopenharmony_ci				crypt_stat->cipher, rc);
19528c2ecf20Sopenharmony_ci	}
19538c2ecf20Sopenharmony_ciout_wipe_list:
19548c2ecf20Sopenharmony_ci	wipe_auth_tok_list(&auth_tok_list);
19558c2ecf20Sopenharmony_ciout:
19568c2ecf20Sopenharmony_ci	return rc;
19578c2ecf20Sopenharmony_ci}
19588c2ecf20Sopenharmony_ci
19598c2ecf20Sopenharmony_cistatic int
19608c2ecf20Sopenharmony_cipki_encrypt_session_key(struct key *auth_tok_key,
19618c2ecf20Sopenharmony_ci			struct ecryptfs_auth_tok *auth_tok,
19628c2ecf20Sopenharmony_ci			struct ecryptfs_crypt_stat *crypt_stat,
19638c2ecf20Sopenharmony_ci			struct ecryptfs_key_record *key_rec)
19648c2ecf20Sopenharmony_ci{
19658c2ecf20Sopenharmony_ci	struct ecryptfs_msg_ctx *msg_ctx = NULL;
19668c2ecf20Sopenharmony_ci	char *payload = NULL;
19678c2ecf20Sopenharmony_ci	size_t payload_len = 0;
19688c2ecf20Sopenharmony_ci	struct ecryptfs_message *msg;
19698c2ecf20Sopenharmony_ci	int rc;
19708c2ecf20Sopenharmony_ci
19718c2ecf20Sopenharmony_ci	rc = write_tag_66_packet(auth_tok->token.private_key.signature,
19728c2ecf20Sopenharmony_ci				 ecryptfs_code_for_cipher_string(
19738c2ecf20Sopenharmony_ci					 crypt_stat->cipher,
19748c2ecf20Sopenharmony_ci					 crypt_stat->key_size),
19758c2ecf20Sopenharmony_ci				 crypt_stat, &payload, &payload_len);
19768c2ecf20Sopenharmony_ci	up_write(&(auth_tok_key->sem));
19778c2ecf20Sopenharmony_ci	key_put(auth_tok_key);
19788c2ecf20Sopenharmony_ci	if (rc) {
19798c2ecf20Sopenharmony_ci		ecryptfs_printk(KERN_ERR, "Error generating tag 66 packet\n");
19808c2ecf20Sopenharmony_ci		goto out;
19818c2ecf20Sopenharmony_ci	}
19828c2ecf20Sopenharmony_ci	rc = ecryptfs_send_message(payload, payload_len, &msg_ctx);
19838c2ecf20Sopenharmony_ci	if (rc) {
19848c2ecf20Sopenharmony_ci		ecryptfs_printk(KERN_ERR, "Error sending message to "
19858c2ecf20Sopenharmony_ci				"ecryptfsd: %d\n", rc);
19868c2ecf20Sopenharmony_ci		goto out;
19878c2ecf20Sopenharmony_ci	}
19888c2ecf20Sopenharmony_ci	rc = ecryptfs_wait_for_response(msg_ctx, &msg);
19898c2ecf20Sopenharmony_ci	if (rc) {
19908c2ecf20Sopenharmony_ci		ecryptfs_printk(KERN_ERR, "Failed to receive tag 67 packet "
19918c2ecf20Sopenharmony_ci				"from the user space daemon\n");
19928c2ecf20Sopenharmony_ci		rc = -EIO;
19938c2ecf20Sopenharmony_ci		goto out;
19948c2ecf20Sopenharmony_ci	}
19958c2ecf20Sopenharmony_ci	rc = parse_tag_67_packet(key_rec, msg);
19968c2ecf20Sopenharmony_ci	if (rc)
19978c2ecf20Sopenharmony_ci		ecryptfs_printk(KERN_ERR, "Error parsing tag 67 packet\n");
19988c2ecf20Sopenharmony_ci	kfree(msg);
19998c2ecf20Sopenharmony_ciout:
20008c2ecf20Sopenharmony_ci	kfree(payload);
20018c2ecf20Sopenharmony_ci	return rc;
20028c2ecf20Sopenharmony_ci}
20038c2ecf20Sopenharmony_ci/**
20048c2ecf20Sopenharmony_ci * write_tag_1_packet - Write an RFC2440-compatible tag 1 (public key) packet
20058c2ecf20Sopenharmony_ci * @dest: Buffer into which to write the packet
20068c2ecf20Sopenharmony_ci * @remaining_bytes: Maximum number of bytes that can be writtn
20078c2ecf20Sopenharmony_ci * @auth_tok_key: The authentication token key to unlock and put when done with
20088c2ecf20Sopenharmony_ci *                @auth_tok
20098c2ecf20Sopenharmony_ci * @auth_tok: The authentication token used for generating the tag 1 packet
20108c2ecf20Sopenharmony_ci * @crypt_stat: The cryptographic context
20118c2ecf20Sopenharmony_ci * @key_rec: The key record struct for the tag 1 packet
20128c2ecf20Sopenharmony_ci * @packet_size: This function will write the number of bytes that end
20138c2ecf20Sopenharmony_ci *               up constituting the packet; set to zero on error
20148c2ecf20Sopenharmony_ci *
20158c2ecf20Sopenharmony_ci * Returns zero on success; non-zero on error.
20168c2ecf20Sopenharmony_ci */
20178c2ecf20Sopenharmony_cistatic int
20188c2ecf20Sopenharmony_ciwrite_tag_1_packet(char *dest, size_t *remaining_bytes,
20198c2ecf20Sopenharmony_ci		   struct key *auth_tok_key, struct ecryptfs_auth_tok *auth_tok,
20208c2ecf20Sopenharmony_ci		   struct ecryptfs_crypt_stat *crypt_stat,
20218c2ecf20Sopenharmony_ci		   struct ecryptfs_key_record *key_rec, size_t *packet_size)
20228c2ecf20Sopenharmony_ci{
20238c2ecf20Sopenharmony_ci	size_t i;
20248c2ecf20Sopenharmony_ci	size_t encrypted_session_key_valid = 0;
20258c2ecf20Sopenharmony_ci	size_t packet_size_length;
20268c2ecf20Sopenharmony_ci	size_t max_packet_size;
20278c2ecf20Sopenharmony_ci	int rc = 0;
20288c2ecf20Sopenharmony_ci
20298c2ecf20Sopenharmony_ci	(*packet_size) = 0;
20308c2ecf20Sopenharmony_ci	ecryptfs_from_hex(key_rec->sig, auth_tok->token.private_key.signature,
20318c2ecf20Sopenharmony_ci			  ECRYPTFS_SIG_SIZE);
20328c2ecf20Sopenharmony_ci	encrypted_session_key_valid = 0;
20338c2ecf20Sopenharmony_ci	for (i = 0; i < crypt_stat->key_size; i++)
20348c2ecf20Sopenharmony_ci		encrypted_session_key_valid |=
20358c2ecf20Sopenharmony_ci			auth_tok->session_key.encrypted_key[i];
20368c2ecf20Sopenharmony_ci	if (encrypted_session_key_valid) {
20378c2ecf20Sopenharmony_ci		memcpy(key_rec->enc_key,
20388c2ecf20Sopenharmony_ci		       auth_tok->session_key.encrypted_key,
20398c2ecf20Sopenharmony_ci		       auth_tok->session_key.encrypted_key_size);
20408c2ecf20Sopenharmony_ci		up_write(&(auth_tok_key->sem));
20418c2ecf20Sopenharmony_ci		key_put(auth_tok_key);
20428c2ecf20Sopenharmony_ci		goto encrypted_session_key_set;
20438c2ecf20Sopenharmony_ci	}
20448c2ecf20Sopenharmony_ci	if (auth_tok->session_key.encrypted_key_size == 0)
20458c2ecf20Sopenharmony_ci		auth_tok->session_key.encrypted_key_size =
20468c2ecf20Sopenharmony_ci			auth_tok->token.private_key.key_size;
20478c2ecf20Sopenharmony_ci	rc = pki_encrypt_session_key(auth_tok_key, auth_tok, crypt_stat,
20488c2ecf20Sopenharmony_ci				     key_rec);
20498c2ecf20Sopenharmony_ci	if (rc) {
20508c2ecf20Sopenharmony_ci		printk(KERN_ERR "Failed to encrypt session key via a key "
20518c2ecf20Sopenharmony_ci		       "module; rc = [%d]\n", rc);
20528c2ecf20Sopenharmony_ci		goto out;
20538c2ecf20Sopenharmony_ci	}
20548c2ecf20Sopenharmony_ci	if (ecryptfs_verbosity > 0) {
20558c2ecf20Sopenharmony_ci		ecryptfs_printk(KERN_DEBUG, "Encrypted key:\n");
20568c2ecf20Sopenharmony_ci		ecryptfs_dump_hex(key_rec->enc_key, key_rec->enc_key_size);
20578c2ecf20Sopenharmony_ci	}
20588c2ecf20Sopenharmony_ciencrypted_session_key_set:
20598c2ecf20Sopenharmony_ci	/* This format is inspired by OpenPGP; see RFC 2440
20608c2ecf20Sopenharmony_ci	 * packet tag 1 */
20618c2ecf20Sopenharmony_ci	max_packet_size = (1                         /* Tag 1 identifier */
20628c2ecf20Sopenharmony_ci			   + 3                       /* Max Tag 1 packet size */
20638c2ecf20Sopenharmony_ci			   + 1                       /* Version */
20648c2ecf20Sopenharmony_ci			   + ECRYPTFS_SIG_SIZE       /* Key identifier */
20658c2ecf20Sopenharmony_ci			   + 1                       /* Cipher identifier */
20668c2ecf20Sopenharmony_ci			   + key_rec->enc_key_size); /* Encrypted key size */
20678c2ecf20Sopenharmony_ci	if (max_packet_size > (*remaining_bytes)) {
20688c2ecf20Sopenharmony_ci		printk(KERN_ERR "Packet length larger than maximum allowable; "
20698c2ecf20Sopenharmony_ci		       "need up to [%td] bytes, but there are only [%td] "
20708c2ecf20Sopenharmony_ci		       "available\n", max_packet_size, (*remaining_bytes));
20718c2ecf20Sopenharmony_ci		rc = -EINVAL;
20728c2ecf20Sopenharmony_ci		goto out;
20738c2ecf20Sopenharmony_ci	}
20748c2ecf20Sopenharmony_ci	dest[(*packet_size)++] = ECRYPTFS_TAG_1_PACKET_TYPE;
20758c2ecf20Sopenharmony_ci	rc = ecryptfs_write_packet_length(&dest[(*packet_size)],
20768c2ecf20Sopenharmony_ci					  (max_packet_size - 4),
20778c2ecf20Sopenharmony_ci					  &packet_size_length);
20788c2ecf20Sopenharmony_ci	if (rc) {
20798c2ecf20Sopenharmony_ci		ecryptfs_printk(KERN_ERR, "Error generating tag 1 packet "
20808c2ecf20Sopenharmony_ci				"header; cannot generate packet length\n");
20818c2ecf20Sopenharmony_ci		goto out;
20828c2ecf20Sopenharmony_ci	}
20838c2ecf20Sopenharmony_ci	(*packet_size) += packet_size_length;
20848c2ecf20Sopenharmony_ci	dest[(*packet_size)++] = 0x03; /* version 3 */
20858c2ecf20Sopenharmony_ci	memcpy(&dest[(*packet_size)], key_rec->sig, ECRYPTFS_SIG_SIZE);
20868c2ecf20Sopenharmony_ci	(*packet_size) += ECRYPTFS_SIG_SIZE;
20878c2ecf20Sopenharmony_ci	dest[(*packet_size)++] = RFC2440_CIPHER_RSA;
20888c2ecf20Sopenharmony_ci	memcpy(&dest[(*packet_size)], key_rec->enc_key,
20898c2ecf20Sopenharmony_ci	       key_rec->enc_key_size);
20908c2ecf20Sopenharmony_ci	(*packet_size) += key_rec->enc_key_size;
20918c2ecf20Sopenharmony_ciout:
20928c2ecf20Sopenharmony_ci	if (rc)
20938c2ecf20Sopenharmony_ci		(*packet_size) = 0;
20948c2ecf20Sopenharmony_ci	else
20958c2ecf20Sopenharmony_ci		(*remaining_bytes) -= (*packet_size);
20968c2ecf20Sopenharmony_ci	return rc;
20978c2ecf20Sopenharmony_ci}
20988c2ecf20Sopenharmony_ci
20998c2ecf20Sopenharmony_ci/**
21008c2ecf20Sopenharmony_ci * write_tag_11_packet
21018c2ecf20Sopenharmony_ci * @dest: Target into which Tag 11 packet is to be written
21028c2ecf20Sopenharmony_ci * @remaining_bytes: Maximum packet length
21038c2ecf20Sopenharmony_ci * @contents: Byte array of contents to copy in
21048c2ecf20Sopenharmony_ci * @contents_length: Number of bytes in contents
21058c2ecf20Sopenharmony_ci * @packet_length: Length of the Tag 11 packet written; zero on error
21068c2ecf20Sopenharmony_ci *
21078c2ecf20Sopenharmony_ci * Returns zero on success; non-zero on error.
21088c2ecf20Sopenharmony_ci */
21098c2ecf20Sopenharmony_cistatic int
21108c2ecf20Sopenharmony_ciwrite_tag_11_packet(char *dest, size_t *remaining_bytes, char *contents,
21118c2ecf20Sopenharmony_ci		    size_t contents_length, size_t *packet_length)
21128c2ecf20Sopenharmony_ci{
21138c2ecf20Sopenharmony_ci	size_t packet_size_length;
21148c2ecf20Sopenharmony_ci	size_t max_packet_size;
21158c2ecf20Sopenharmony_ci	int rc = 0;
21168c2ecf20Sopenharmony_ci
21178c2ecf20Sopenharmony_ci	(*packet_length) = 0;
21188c2ecf20Sopenharmony_ci	/* This format is inspired by OpenPGP; see RFC 2440
21198c2ecf20Sopenharmony_ci	 * packet tag 11 */
21208c2ecf20Sopenharmony_ci	max_packet_size = (1                   /* Tag 11 identifier */
21218c2ecf20Sopenharmony_ci			   + 3                 /* Max Tag 11 packet size */
21228c2ecf20Sopenharmony_ci			   + 1                 /* Binary format specifier */
21238c2ecf20Sopenharmony_ci			   + 1                 /* Filename length */
21248c2ecf20Sopenharmony_ci			   + 8                 /* Filename ("_CONSOLE") */
21258c2ecf20Sopenharmony_ci			   + 4                 /* Modification date */
21268c2ecf20Sopenharmony_ci			   + contents_length); /* Literal data */
21278c2ecf20Sopenharmony_ci	if (max_packet_size > (*remaining_bytes)) {
21288c2ecf20Sopenharmony_ci		printk(KERN_ERR "Packet length larger than maximum allowable; "
21298c2ecf20Sopenharmony_ci		       "need up to [%td] bytes, but there are only [%td] "
21308c2ecf20Sopenharmony_ci		       "available\n", max_packet_size, (*remaining_bytes));
21318c2ecf20Sopenharmony_ci		rc = -EINVAL;
21328c2ecf20Sopenharmony_ci		goto out;
21338c2ecf20Sopenharmony_ci	}
21348c2ecf20Sopenharmony_ci	dest[(*packet_length)++] = ECRYPTFS_TAG_11_PACKET_TYPE;
21358c2ecf20Sopenharmony_ci	rc = ecryptfs_write_packet_length(&dest[(*packet_length)],
21368c2ecf20Sopenharmony_ci					  (max_packet_size - 4),
21378c2ecf20Sopenharmony_ci					  &packet_size_length);
21388c2ecf20Sopenharmony_ci	if (rc) {
21398c2ecf20Sopenharmony_ci		printk(KERN_ERR "Error generating tag 11 packet header; cannot "
21408c2ecf20Sopenharmony_ci		       "generate packet length. rc = [%d]\n", rc);
21418c2ecf20Sopenharmony_ci		goto out;
21428c2ecf20Sopenharmony_ci	}
21438c2ecf20Sopenharmony_ci	(*packet_length) += packet_size_length;
21448c2ecf20Sopenharmony_ci	dest[(*packet_length)++] = 0x62; /* binary data format specifier */
21458c2ecf20Sopenharmony_ci	dest[(*packet_length)++] = 8;
21468c2ecf20Sopenharmony_ci	memcpy(&dest[(*packet_length)], "_CONSOLE", 8);
21478c2ecf20Sopenharmony_ci	(*packet_length) += 8;
21488c2ecf20Sopenharmony_ci	memset(&dest[(*packet_length)], 0x00, 4);
21498c2ecf20Sopenharmony_ci	(*packet_length) += 4;
21508c2ecf20Sopenharmony_ci	memcpy(&dest[(*packet_length)], contents, contents_length);
21518c2ecf20Sopenharmony_ci	(*packet_length) += contents_length;
21528c2ecf20Sopenharmony_ci out:
21538c2ecf20Sopenharmony_ci	if (rc)
21548c2ecf20Sopenharmony_ci		(*packet_length) = 0;
21558c2ecf20Sopenharmony_ci	else
21568c2ecf20Sopenharmony_ci		(*remaining_bytes) -= (*packet_length);
21578c2ecf20Sopenharmony_ci	return rc;
21588c2ecf20Sopenharmony_ci}
21598c2ecf20Sopenharmony_ci
21608c2ecf20Sopenharmony_ci/**
21618c2ecf20Sopenharmony_ci * write_tag_3_packet
21628c2ecf20Sopenharmony_ci * @dest: Buffer into which to write the packet
21638c2ecf20Sopenharmony_ci * @remaining_bytes: Maximum number of bytes that can be written
21648c2ecf20Sopenharmony_ci * @auth_tok: Authentication token
21658c2ecf20Sopenharmony_ci * @crypt_stat: The cryptographic context
21668c2ecf20Sopenharmony_ci * @key_rec: encrypted key
21678c2ecf20Sopenharmony_ci * @packet_size: This function will write the number of bytes that end
21688c2ecf20Sopenharmony_ci *               up constituting the packet; set to zero on error
21698c2ecf20Sopenharmony_ci *
21708c2ecf20Sopenharmony_ci * Returns zero on success; non-zero on error.
21718c2ecf20Sopenharmony_ci */
21728c2ecf20Sopenharmony_cistatic int
21738c2ecf20Sopenharmony_ciwrite_tag_3_packet(char *dest, size_t *remaining_bytes,
21748c2ecf20Sopenharmony_ci		   struct ecryptfs_auth_tok *auth_tok,
21758c2ecf20Sopenharmony_ci		   struct ecryptfs_crypt_stat *crypt_stat,
21768c2ecf20Sopenharmony_ci		   struct ecryptfs_key_record *key_rec, size_t *packet_size)
21778c2ecf20Sopenharmony_ci{
21788c2ecf20Sopenharmony_ci	size_t i;
21798c2ecf20Sopenharmony_ci	size_t encrypted_session_key_valid = 0;
21808c2ecf20Sopenharmony_ci	char session_key_encryption_key[ECRYPTFS_MAX_KEY_BYTES];
21818c2ecf20Sopenharmony_ci	struct scatterlist dst_sg[2];
21828c2ecf20Sopenharmony_ci	struct scatterlist src_sg[2];
21838c2ecf20Sopenharmony_ci	struct mutex *tfm_mutex = NULL;
21848c2ecf20Sopenharmony_ci	u8 cipher_code;
21858c2ecf20Sopenharmony_ci	size_t packet_size_length;
21868c2ecf20Sopenharmony_ci	size_t max_packet_size;
21878c2ecf20Sopenharmony_ci	struct ecryptfs_mount_crypt_stat *mount_crypt_stat =
21888c2ecf20Sopenharmony_ci		crypt_stat->mount_crypt_stat;
21898c2ecf20Sopenharmony_ci	struct crypto_skcipher *tfm;
21908c2ecf20Sopenharmony_ci	struct skcipher_request *req;
21918c2ecf20Sopenharmony_ci	int rc = 0;
21928c2ecf20Sopenharmony_ci
21938c2ecf20Sopenharmony_ci	(*packet_size) = 0;
21948c2ecf20Sopenharmony_ci	ecryptfs_from_hex(key_rec->sig, auth_tok->token.password.signature,
21958c2ecf20Sopenharmony_ci			  ECRYPTFS_SIG_SIZE);
21968c2ecf20Sopenharmony_ci	rc = ecryptfs_get_tfm_and_mutex_for_cipher_name(&tfm, &tfm_mutex,
21978c2ecf20Sopenharmony_ci							crypt_stat->cipher);
21988c2ecf20Sopenharmony_ci	if (unlikely(rc)) {
21998c2ecf20Sopenharmony_ci		printk(KERN_ERR "Internal error whilst attempting to get "
22008c2ecf20Sopenharmony_ci		       "tfm and mutex for cipher name [%s]; rc = [%d]\n",
22018c2ecf20Sopenharmony_ci		       crypt_stat->cipher, rc);
22028c2ecf20Sopenharmony_ci		goto out;
22038c2ecf20Sopenharmony_ci	}
22048c2ecf20Sopenharmony_ci	if (mount_crypt_stat->global_default_cipher_key_size == 0) {
22058c2ecf20Sopenharmony_ci		printk(KERN_WARNING "No key size specified at mount; "
22068c2ecf20Sopenharmony_ci		       "defaulting to [%d]\n",
22078c2ecf20Sopenharmony_ci		       crypto_skcipher_max_keysize(tfm));
22088c2ecf20Sopenharmony_ci		mount_crypt_stat->global_default_cipher_key_size =
22098c2ecf20Sopenharmony_ci			crypto_skcipher_max_keysize(tfm);
22108c2ecf20Sopenharmony_ci	}
22118c2ecf20Sopenharmony_ci	if (crypt_stat->key_size == 0)
22128c2ecf20Sopenharmony_ci		crypt_stat->key_size =
22138c2ecf20Sopenharmony_ci			mount_crypt_stat->global_default_cipher_key_size;
22148c2ecf20Sopenharmony_ci	if (auth_tok->session_key.encrypted_key_size == 0)
22158c2ecf20Sopenharmony_ci		auth_tok->session_key.encrypted_key_size =
22168c2ecf20Sopenharmony_ci			crypt_stat->key_size;
22178c2ecf20Sopenharmony_ci	if (crypt_stat->key_size == 24
22188c2ecf20Sopenharmony_ci	    && strcmp("aes", crypt_stat->cipher) == 0) {
22198c2ecf20Sopenharmony_ci		memset((crypt_stat->key + 24), 0, 8);
22208c2ecf20Sopenharmony_ci		auth_tok->session_key.encrypted_key_size = 32;
22218c2ecf20Sopenharmony_ci	} else
22228c2ecf20Sopenharmony_ci		auth_tok->session_key.encrypted_key_size = crypt_stat->key_size;
22238c2ecf20Sopenharmony_ci	key_rec->enc_key_size =
22248c2ecf20Sopenharmony_ci		auth_tok->session_key.encrypted_key_size;
22258c2ecf20Sopenharmony_ci	encrypted_session_key_valid = 0;
22268c2ecf20Sopenharmony_ci	for (i = 0; i < auth_tok->session_key.encrypted_key_size; i++)
22278c2ecf20Sopenharmony_ci		encrypted_session_key_valid |=
22288c2ecf20Sopenharmony_ci			auth_tok->session_key.encrypted_key[i];
22298c2ecf20Sopenharmony_ci	if (encrypted_session_key_valid) {
22308c2ecf20Sopenharmony_ci		ecryptfs_printk(KERN_DEBUG, "encrypted_session_key_valid != 0; "
22318c2ecf20Sopenharmony_ci				"using auth_tok->session_key.encrypted_key, "
22328c2ecf20Sopenharmony_ci				"where key_rec->enc_key_size = [%zd]\n",
22338c2ecf20Sopenharmony_ci				key_rec->enc_key_size);
22348c2ecf20Sopenharmony_ci		memcpy(key_rec->enc_key,
22358c2ecf20Sopenharmony_ci		       auth_tok->session_key.encrypted_key,
22368c2ecf20Sopenharmony_ci		       key_rec->enc_key_size);
22378c2ecf20Sopenharmony_ci		goto encrypted_session_key_set;
22388c2ecf20Sopenharmony_ci	}
22398c2ecf20Sopenharmony_ci	if (auth_tok->token.password.flags &
22408c2ecf20Sopenharmony_ci	    ECRYPTFS_SESSION_KEY_ENCRYPTION_KEY_SET) {
22418c2ecf20Sopenharmony_ci		ecryptfs_printk(KERN_DEBUG, "Using previously generated "
22428c2ecf20Sopenharmony_ci				"session key encryption key of size [%d]\n",
22438c2ecf20Sopenharmony_ci				auth_tok->token.password.
22448c2ecf20Sopenharmony_ci				session_key_encryption_key_bytes);
22458c2ecf20Sopenharmony_ci		memcpy(session_key_encryption_key,
22468c2ecf20Sopenharmony_ci		       auth_tok->token.password.session_key_encryption_key,
22478c2ecf20Sopenharmony_ci		       crypt_stat->key_size);
22488c2ecf20Sopenharmony_ci		ecryptfs_printk(KERN_DEBUG,
22498c2ecf20Sopenharmony_ci				"Cached session key encryption key:\n");
22508c2ecf20Sopenharmony_ci		if (ecryptfs_verbosity > 0)
22518c2ecf20Sopenharmony_ci			ecryptfs_dump_hex(session_key_encryption_key, 16);
22528c2ecf20Sopenharmony_ci	}
22538c2ecf20Sopenharmony_ci	if (unlikely(ecryptfs_verbosity > 0)) {
22548c2ecf20Sopenharmony_ci		ecryptfs_printk(KERN_DEBUG, "Session key encryption key:\n");
22558c2ecf20Sopenharmony_ci		ecryptfs_dump_hex(session_key_encryption_key, 16);
22568c2ecf20Sopenharmony_ci	}
22578c2ecf20Sopenharmony_ci	rc = virt_to_scatterlist(crypt_stat->key, key_rec->enc_key_size,
22588c2ecf20Sopenharmony_ci				 src_sg, 2);
22598c2ecf20Sopenharmony_ci	if (rc < 1 || rc > 2) {
22608c2ecf20Sopenharmony_ci		ecryptfs_printk(KERN_ERR, "Error generating scatterlist "
22618c2ecf20Sopenharmony_ci				"for crypt_stat session key; expected rc = 1; "
22628c2ecf20Sopenharmony_ci				"got rc = [%d]. key_rec->enc_key_size = [%zd]\n",
22638c2ecf20Sopenharmony_ci				rc, key_rec->enc_key_size);
22648c2ecf20Sopenharmony_ci		rc = -ENOMEM;
22658c2ecf20Sopenharmony_ci		goto out;
22668c2ecf20Sopenharmony_ci	}
22678c2ecf20Sopenharmony_ci	rc = virt_to_scatterlist(key_rec->enc_key, key_rec->enc_key_size,
22688c2ecf20Sopenharmony_ci				 dst_sg, 2);
22698c2ecf20Sopenharmony_ci	if (rc < 1 || rc > 2) {
22708c2ecf20Sopenharmony_ci		ecryptfs_printk(KERN_ERR, "Error generating scatterlist "
22718c2ecf20Sopenharmony_ci				"for crypt_stat encrypted session key; "
22728c2ecf20Sopenharmony_ci				"expected rc = 1; got rc = [%d]. "
22738c2ecf20Sopenharmony_ci				"key_rec->enc_key_size = [%zd]\n", rc,
22748c2ecf20Sopenharmony_ci				key_rec->enc_key_size);
22758c2ecf20Sopenharmony_ci		rc = -ENOMEM;
22768c2ecf20Sopenharmony_ci		goto out;
22778c2ecf20Sopenharmony_ci	}
22788c2ecf20Sopenharmony_ci	mutex_lock(tfm_mutex);
22798c2ecf20Sopenharmony_ci	rc = crypto_skcipher_setkey(tfm, session_key_encryption_key,
22808c2ecf20Sopenharmony_ci				    crypt_stat->key_size);
22818c2ecf20Sopenharmony_ci	if (rc < 0) {
22828c2ecf20Sopenharmony_ci		mutex_unlock(tfm_mutex);
22838c2ecf20Sopenharmony_ci		ecryptfs_printk(KERN_ERR, "Error setting key for crypto "
22848c2ecf20Sopenharmony_ci				"context; rc = [%d]\n", rc);
22858c2ecf20Sopenharmony_ci		goto out;
22868c2ecf20Sopenharmony_ci	}
22878c2ecf20Sopenharmony_ci
22888c2ecf20Sopenharmony_ci	req = skcipher_request_alloc(tfm, GFP_KERNEL);
22898c2ecf20Sopenharmony_ci	if (!req) {
22908c2ecf20Sopenharmony_ci		mutex_unlock(tfm_mutex);
22918c2ecf20Sopenharmony_ci		ecryptfs_printk(KERN_ERR, "Out of kernel memory whilst "
22928c2ecf20Sopenharmony_ci				"attempting to skcipher_request_alloc for "
22938c2ecf20Sopenharmony_ci				"%s\n", crypto_skcipher_driver_name(tfm));
22948c2ecf20Sopenharmony_ci		rc = -ENOMEM;
22958c2ecf20Sopenharmony_ci		goto out;
22968c2ecf20Sopenharmony_ci	}
22978c2ecf20Sopenharmony_ci
22988c2ecf20Sopenharmony_ci	skcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_SLEEP,
22998c2ecf20Sopenharmony_ci				      NULL, NULL);
23008c2ecf20Sopenharmony_ci
23018c2ecf20Sopenharmony_ci	rc = 0;
23028c2ecf20Sopenharmony_ci	ecryptfs_printk(KERN_DEBUG, "Encrypting [%zd] bytes of the key\n",
23038c2ecf20Sopenharmony_ci			crypt_stat->key_size);
23048c2ecf20Sopenharmony_ci	skcipher_request_set_crypt(req, src_sg, dst_sg,
23058c2ecf20Sopenharmony_ci				   (*key_rec).enc_key_size, NULL);
23068c2ecf20Sopenharmony_ci	rc = crypto_skcipher_encrypt(req);
23078c2ecf20Sopenharmony_ci	mutex_unlock(tfm_mutex);
23088c2ecf20Sopenharmony_ci	skcipher_request_free(req);
23098c2ecf20Sopenharmony_ci	if (rc) {
23108c2ecf20Sopenharmony_ci		printk(KERN_ERR "Error encrypting; rc = [%d]\n", rc);
23118c2ecf20Sopenharmony_ci		goto out;
23128c2ecf20Sopenharmony_ci	}
23138c2ecf20Sopenharmony_ci	ecryptfs_printk(KERN_DEBUG, "This should be the encrypted key:\n");
23148c2ecf20Sopenharmony_ci	if (ecryptfs_verbosity > 0) {
23158c2ecf20Sopenharmony_ci		ecryptfs_printk(KERN_DEBUG, "EFEK of size [%zd]:\n",
23168c2ecf20Sopenharmony_ci				key_rec->enc_key_size);
23178c2ecf20Sopenharmony_ci		ecryptfs_dump_hex(key_rec->enc_key,
23188c2ecf20Sopenharmony_ci				  key_rec->enc_key_size);
23198c2ecf20Sopenharmony_ci	}
23208c2ecf20Sopenharmony_ciencrypted_session_key_set:
23218c2ecf20Sopenharmony_ci	/* This format is inspired by OpenPGP; see RFC 2440
23228c2ecf20Sopenharmony_ci	 * packet tag 3 */
23238c2ecf20Sopenharmony_ci	max_packet_size = (1                         /* Tag 3 identifier */
23248c2ecf20Sopenharmony_ci			   + 3                       /* Max Tag 3 packet size */
23258c2ecf20Sopenharmony_ci			   + 1                       /* Version */
23268c2ecf20Sopenharmony_ci			   + 1                       /* Cipher code */
23278c2ecf20Sopenharmony_ci			   + 1                       /* S2K specifier */
23288c2ecf20Sopenharmony_ci			   + 1                       /* Hash identifier */
23298c2ecf20Sopenharmony_ci			   + ECRYPTFS_SALT_SIZE      /* Salt */
23308c2ecf20Sopenharmony_ci			   + 1                       /* Hash iterations */
23318c2ecf20Sopenharmony_ci			   + key_rec->enc_key_size); /* Encrypted key size */
23328c2ecf20Sopenharmony_ci	if (max_packet_size > (*remaining_bytes)) {
23338c2ecf20Sopenharmony_ci		printk(KERN_ERR "Packet too large; need up to [%td] bytes, but "
23348c2ecf20Sopenharmony_ci		       "there are only [%td] available\n", max_packet_size,
23358c2ecf20Sopenharmony_ci		       (*remaining_bytes));
23368c2ecf20Sopenharmony_ci		rc = -EINVAL;
23378c2ecf20Sopenharmony_ci		goto out;
23388c2ecf20Sopenharmony_ci	}
23398c2ecf20Sopenharmony_ci	dest[(*packet_size)++] = ECRYPTFS_TAG_3_PACKET_TYPE;
23408c2ecf20Sopenharmony_ci	/* Chop off the Tag 3 identifier(1) and Tag 3 packet size(3)
23418c2ecf20Sopenharmony_ci	 * to get the number of octets in the actual Tag 3 packet */
23428c2ecf20Sopenharmony_ci	rc = ecryptfs_write_packet_length(&dest[(*packet_size)],
23438c2ecf20Sopenharmony_ci					  (max_packet_size - 4),
23448c2ecf20Sopenharmony_ci					  &packet_size_length);
23458c2ecf20Sopenharmony_ci	if (rc) {
23468c2ecf20Sopenharmony_ci		printk(KERN_ERR "Error generating tag 3 packet header; cannot "
23478c2ecf20Sopenharmony_ci		       "generate packet length. rc = [%d]\n", rc);
23488c2ecf20Sopenharmony_ci		goto out;
23498c2ecf20Sopenharmony_ci	}
23508c2ecf20Sopenharmony_ci	(*packet_size) += packet_size_length;
23518c2ecf20Sopenharmony_ci	dest[(*packet_size)++] = 0x04; /* version 4 */
23528c2ecf20Sopenharmony_ci	/* TODO: Break from RFC2440 so that arbitrary ciphers can be
23538c2ecf20Sopenharmony_ci	 * specified with strings */
23548c2ecf20Sopenharmony_ci	cipher_code = ecryptfs_code_for_cipher_string(crypt_stat->cipher,
23558c2ecf20Sopenharmony_ci						      crypt_stat->key_size);
23568c2ecf20Sopenharmony_ci	if (cipher_code == 0) {
23578c2ecf20Sopenharmony_ci		ecryptfs_printk(KERN_WARNING, "Unable to generate code for "
23588c2ecf20Sopenharmony_ci				"cipher [%s]\n", crypt_stat->cipher);
23598c2ecf20Sopenharmony_ci		rc = -EINVAL;
23608c2ecf20Sopenharmony_ci		goto out;
23618c2ecf20Sopenharmony_ci	}
23628c2ecf20Sopenharmony_ci	dest[(*packet_size)++] = cipher_code;
23638c2ecf20Sopenharmony_ci	dest[(*packet_size)++] = 0x03;	/* S2K */
23648c2ecf20Sopenharmony_ci	dest[(*packet_size)++] = 0x01;	/* MD5 (TODO: parameterize) */
23658c2ecf20Sopenharmony_ci	memcpy(&dest[(*packet_size)], auth_tok->token.password.salt,
23668c2ecf20Sopenharmony_ci	       ECRYPTFS_SALT_SIZE);
23678c2ecf20Sopenharmony_ci	(*packet_size) += ECRYPTFS_SALT_SIZE;	/* salt */
23688c2ecf20Sopenharmony_ci	dest[(*packet_size)++] = 0x60;	/* hash iterations (65536) */
23698c2ecf20Sopenharmony_ci	memcpy(&dest[(*packet_size)], key_rec->enc_key,
23708c2ecf20Sopenharmony_ci	       key_rec->enc_key_size);
23718c2ecf20Sopenharmony_ci	(*packet_size) += key_rec->enc_key_size;
23728c2ecf20Sopenharmony_ciout:
23738c2ecf20Sopenharmony_ci	if (rc)
23748c2ecf20Sopenharmony_ci		(*packet_size) = 0;
23758c2ecf20Sopenharmony_ci	else
23768c2ecf20Sopenharmony_ci		(*remaining_bytes) -= (*packet_size);
23778c2ecf20Sopenharmony_ci	return rc;
23788c2ecf20Sopenharmony_ci}
23798c2ecf20Sopenharmony_ci
23808c2ecf20Sopenharmony_cistruct kmem_cache *ecryptfs_key_record_cache;
23818c2ecf20Sopenharmony_ci
23828c2ecf20Sopenharmony_ci/**
23838c2ecf20Sopenharmony_ci * ecryptfs_generate_key_packet_set
23848c2ecf20Sopenharmony_ci * @dest_base: Virtual address from which to write the key record set
23858c2ecf20Sopenharmony_ci * @crypt_stat: The cryptographic context from which the
23868c2ecf20Sopenharmony_ci *              authentication tokens will be retrieved
23878c2ecf20Sopenharmony_ci * @ecryptfs_dentry: The dentry, used to retrieve the mount crypt stat
23888c2ecf20Sopenharmony_ci *                   for the global parameters
23898c2ecf20Sopenharmony_ci * @len: The amount written
23908c2ecf20Sopenharmony_ci * @max: The maximum amount of data allowed to be written
23918c2ecf20Sopenharmony_ci *
23928c2ecf20Sopenharmony_ci * Generates a key packet set and writes it to the virtual address
23938c2ecf20Sopenharmony_ci * passed in.
23948c2ecf20Sopenharmony_ci *
23958c2ecf20Sopenharmony_ci * Returns zero on success; non-zero on error.
23968c2ecf20Sopenharmony_ci */
23978c2ecf20Sopenharmony_ciint
23988c2ecf20Sopenharmony_ciecryptfs_generate_key_packet_set(char *dest_base,
23998c2ecf20Sopenharmony_ci				 struct ecryptfs_crypt_stat *crypt_stat,
24008c2ecf20Sopenharmony_ci				 struct dentry *ecryptfs_dentry, size_t *len,
24018c2ecf20Sopenharmony_ci				 size_t max)
24028c2ecf20Sopenharmony_ci{
24038c2ecf20Sopenharmony_ci	struct ecryptfs_auth_tok *auth_tok;
24048c2ecf20Sopenharmony_ci	struct key *auth_tok_key = NULL;
24058c2ecf20Sopenharmony_ci	struct ecryptfs_mount_crypt_stat *mount_crypt_stat =
24068c2ecf20Sopenharmony_ci		&ecryptfs_superblock_to_private(
24078c2ecf20Sopenharmony_ci			ecryptfs_dentry->d_sb)->mount_crypt_stat;
24088c2ecf20Sopenharmony_ci	size_t written;
24098c2ecf20Sopenharmony_ci	struct ecryptfs_key_record *key_rec;
24108c2ecf20Sopenharmony_ci	struct ecryptfs_key_sig *key_sig;
24118c2ecf20Sopenharmony_ci	int rc = 0;
24128c2ecf20Sopenharmony_ci
24138c2ecf20Sopenharmony_ci	(*len) = 0;
24148c2ecf20Sopenharmony_ci	mutex_lock(&crypt_stat->keysig_list_mutex);
24158c2ecf20Sopenharmony_ci	key_rec = kmem_cache_alloc(ecryptfs_key_record_cache, GFP_KERNEL);
24168c2ecf20Sopenharmony_ci	if (!key_rec) {
24178c2ecf20Sopenharmony_ci		rc = -ENOMEM;
24188c2ecf20Sopenharmony_ci		goto out;
24198c2ecf20Sopenharmony_ci	}
24208c2ecf20Sopenharmony_ci	list_for_each_entry(key_sig, &crypt_stat->keysig_list,
24218c2ecf20Sopenharmony_ci			    crypt_stat_list) {
24228c2ecf20Sopenharmony_ci		memset(key_rec, 0, sizeof(*key_rec));
24238c2ecf20Sopenharmony_ci		rc = ecryptfs_find_global_auth_tok_for_sig(&auth_tok_key,
24248c2ecf20Sopenharmony_ci							   &auth_tok,
24258c2ecf20Sopenharmony_ci							   mount_crypt_stat,
24268c2ecf20Sopenharmony_ci							   key_sig->keysig);
24278c2ecf20Sopenharmony_ci		if (rc) {
24288c2ecf20Sopenharmony_ci			printk(KERN_WARNING "Unable to retrieve auth tok with "
24298c2ecf20Sopenharmony_ci			       "sig = [%s]\n", key_sig->keysig);
24308c2ecf20Sopenharmony_ci			rc = process_find_global_auth_tok_for_sig_err(rc);
24318c2ecf20Sopenharmony_ci			goto out_free;
24328c2ecf20Sopenharmony_ci		}
24338c2ecf20Sopenharmony_ci		if (auth_tok->token_type == ECRYPTFS_PASSWORD) {
24348c2ecf20Sopenharmony_ci			rc = write_tag_3_packet((dest_base + (*len)),
24358c2ecf20Sopenharmony_ci						&max, auth_tok,
24368c2ecf20Sopenharmony_ci						crypt_stat, key_rec,
24378c2ecf20Sopenharmony_ci						&written);
24388c2ecf20Sopenharmony_ci			up_write(&(auth_tok_key->sem));
24398c2ecf20Sopenharmony_ci			key_put(auth_tok_key);
24408c2ecf20Sopenharmony_ci			if (rc) {
24418c2ecf20Sopenharmony_ci				ecryptfs_printk(KERN_WARNING, "Error "
24428c2ecf20Sopenharmony_ci						"writing tag 3 packet\n");
24438c2ecf20Sopenharmony_ci				goto out_free;
24448c2ecf20Sopenharmony_ci			}
24458c2ecf20Sopenharmony_ci			(*len) += written;
24468c2ecf20Sopenharmony_ci			/* Write auth tok signature packet */
24478c2ecf20Sopenharmony_ci			rc = write_tag_11_packet((dest_base + (*len)), &max,
24488c2ecf20Sopenharmony_ci						 key_rec->sig,
24498c2ecf20Sopenharmony_ci						 ECRYPTFS_SIG_SIZE, &written);
24508c2ecf20Sopenharmony_ci			if (rc) {
24518c2ecf20Sopenharmony_ci				ecryptfs_printk(KERN_ERR, "Error writing "
24528c2ecf20Sopenharmony_ci						"auth tok signature packet\n");
24538c2ecf20Sopenharmony_ci				goto out_free;
24548c2ecf20Sopenharmony_ci			}
24558c2ecf20Sopenharmony_ci			(*len) += written;
24568c2ecf20Sopenharmony_ci		} else if (auth_tok->token_type == ECRYPTFS_PRIVATE_KEY) {
24578c2ecf20Sopenharmony_ci			rc = write_tag_1_packet(dest_base + (*len), &max,
24588c2ecf20Sopenharmony_ci						auth_tok_key, auth_tok,
24598c2ecf20Sopenharmony_ci						crypt_stat, key_rec, &written);
24608c2ecf20Sopenharmony_ci			if (rc) {
24618c2ecf20Sopenharmony_ci				ecryptfs_printk(KERN_WARNING, "Error "
24628c2ecf20Sopenharmony_ci						"writing tag 1 packet\n");
24638c2ecf20Sopenharmony_ci				goto out_free;
24648c2ecf20Sopenharmony_ci			}
24658c2ecf20Sopenharmony_ci			(*len) += written;
24668c2ecf20Sopenharmony_ci		} else {
24678c2ecf20Sopenharmony_ci			up_write(&(auth_tok_key->sem));
24688c2ecf20Sopenharmony_ci			key_put(auth_tok_key);
24698c2ecf20Sopenharmony_ci			ecryptfs_printk(KERN_WARNING, "Unsupported "
24708c2ecf20Sopenharmony_ci					"authentication token type\n");
24718c2ecf20Sopenharmony_ci			rc = -EINVAL;
24728c2ecf20Sopenharmony_ci			goto out_free;
24738c2ecf20Sopenharmony_ci		}
24748c2ecf20Sopenharmony_ci	}
24758c2ecf20Sopenharmony_ci	if (likely(max > 0)) {
24768c2ecf20Sopenharmony_ci		dest_base[(*len)] = 0x00;
24778c2ecf20Sopenharmony_ci	} else {
24788c2ecf20Sopenharmony_ci		ecryptfs_printk(KERN_ERR, "Error writing boundary byte\n");
24798c2ecf20Sopenharmony_ci		rc = -EIO;
24808c2ecf20Sopenharmony_ci	}
24818c2ecf20Sopenharmony_ciout_free:
24828c2ecf20Sopenharmony_ci	kmem_cache_free(ecryptfs_key_record_cache, key_rec);
24838c2ecf20Sopenharmony_ciout:
24848c2ecf20Sopenharmony_ci	if (rc)
24858c2ecf20Sopenharmony_ci		(*len) = 0;
24868c2ecf20Sopenharmony_ci	mutex_unlock(&crypt_stat->keysig_list_mutex);
24878c2ecf20Sopenharmony_ci	return rc;
24888c2ecf20Sopenharmony_ci}
24898c2ecf20Sopenharmony_ci
24908c2ecf20Sopenharmony_cistruct kmem_cache *ecryptfs_key_sig_cache;
24918c2ecf20Sopenharmony_ci
24928c2ecf20Sopenharmony_ciint ecryptfs_add_keysig(struct ecryptfs_crypt_stat *crypt_stat, char *sig)
24938c2ecf20Sopenharmony_ci{
24948c2ecf20Sopenharmony_ci	struct ecryptfs_key_sig *new_key_sig;
24958c2ecf20Sopenharmony_ci
24968c2ecf20Sopenharmony_ci	new_key_sig = kmem_cache_alloc(ecryptfs_key_sig_cache, GFP_KERNEL);
24978c2ecf20Sopenharmony_ci	if (!new_key_sig)
24988c2ecf20Sopenharmony_ci		return -ENOMEM;
24998c2ecf20Sopenharmony_ci
25008c2ecf20Sopenharmony_ci	memcpy(new_key_sig->keysig, sig, ECRYPTFS_SIG_SIZE_HEX);
25018c2ecf20Sopenharmony_ci	new_key_sig->keysig[ECRYPTFS_SIG_SIZE_HEX] = '\0';
25028c2ecf20Sopenharmony_ci	/* Caller must hold keysig_list_mutex */
25038c2ecf20Sopenharmony_ci	list_add(&new_key_sig->crypt_stat_list, &crypt_stat->keysig_list);
25048c2ecf20Sopenharmony_ci
25058c2ecf20Sopenharmony_ci	return 0;
25068c2ecf20Sopenharmony_ci}
25078c2ecf20Sopenharmony_ci
25088c2ecf20Sopenharmony_cistruct kmem_cache *ecryptfs_global_auth_tok_cache;
25098c2ecf20Sopenharmony_ci
25108c2ecf20Sopenharmony_ciint
25118c2ecf20Sopenharmony_ciecryptfs_add_global_auth_tok(struct ecryptfs_mount_crypt_stat *mount_crypt_stat,
25128c2ecf20Sopenharmony_ci			     char *sig, u32 global_auth_tok_flags)
25138c2ecf20Sopenharmony_ci{
25148c2ecf20Sopenharmony_ci	struct ecryptfs_global_auth_tok *new_auth_tok;
25158c2ecf20Sopenharmony_ci
25168c2ecf20Sopenharmony_ci	new_auth_tok = kmem_cache_zalloc(ecryptfs_global_auth_tok_cache,
25178c2ecf20Sopenharmony_ci					GFP_KERNEL);
25188c2ecf20Sopenharmony_ci	if (!new_auth_tok)
25198c2ecf20Sopenharmony_ci		return -ENOMEM;
25208c2ecf20Sopenharmony_ci
25218c2ecf20Sopenharmony_ci	memcpy(new_auth_tok->sig, sig, ECRYPTFS_SIG_SIZE_HEX);
25228c2ecf20Sopenharmony_ci	new_auth_tok->flags = global_auth_tok_flags;
25238c2ecf20Sopenharmony_ci	new_auth_tok->sig[ECRYPTFS_SIG_SIZE_HEX] = '\0';
25248c2ecf20Sopenharmony_ci	mutex_lock(&mount_crypt_stat->global_auth_tok_list_mutex);
25258c2ecf20Sopenharmony_ci	list_add(&new_auth_tok->mount_crypt_stat_list,
25268c2ecf20Sopenharmony_ci		 &mount_crypt_stat->global_auth_tok_list);
25278c2ecf20Sopenharmony_ci	mutex_unlock(&mount_crypt_stat->global_auth_tok_list_mutex);
25288c2ecf20Sopenharmony_ci	return 0;
25298c2ecf20Sopenharmony_ci}
25308c2ecf20Sopenharmony_ci
2531