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