// SPDX-License-Identifier: GPL-2.0-or-later/* * eCryptfs: Linux filesystem encryption layer * In-kernel key management code. Includes functions to parse and * write authentication token-related packets with the underlying * file. * * Copyright (C) 2004-2006 International Business Machines Corp. * Author(s): Michael A. Halcrow <mhalcrow@us.ibm.com> * Michael C. Thompson <mcthomps@us.ibm.com> * Trevor S. Highland <trevor.highland@gmail.com> */ #include <crypto/skcipher.h>#include <linux/string.h>#include <linux/pagemap.h>#include <linux/key.h>#include <linux/random.h>#include <linux/scatterlist.h>#include <linux/slab.h>#include "ecryptfs_kernel.h" /* * request_key returned an error instead of a valid key address; * determine the type of error, make appropriate log entries, and * return an error code. */static int process_request_key_err(long err_code){ int rc = 0; switch (err_code) { case -ENOKEY: ecryptfs_printk(KERN_WARNING, "No key\n"); rc = -ENOENT; break; case -EKEYEXPIRED: ecryptfs_printk(KERN_WARNING, "Key expired\n"); rc = -ETIME; break; case -EKEYREVOKED: ecryptfs_printk(KERN_WARNING, "Key revoked\n"); rc = -EINVAL; break; default: ecryptfs_printk(KERN_WARNING, "Unknown error code: " "[0x%.16lx]\n", err_code); rc = -EINVAL; } return rc;} static int process_find_global_auth_tok_for_sig_err(int err_code){ int rc = err_code; switch (err_code) { case -ENOENT: ecryptfs_printk(KERN_WARNING, "Missing auth tok\n"); break; case -EINVAL: ecryptfs_printk(KERN_WARNING, "Invalid auth tok\n"); break; default: rc = process_request_key_err(err_code); break; } return rc;} /** * ecryptfs_parse_packet_length * @data: Pointer to memory containing length at offset * @size: This function writes the decoded size to this memory * address; zero on error * @length_size: The number of bytes occupied by the encoded length * * Returns zero on success; non-zero on error */int ecryptfs_parse_packet_length(unsigned char *data, size_t *size, size_t *length_size){ int rc = 0; (*length_size) = 0; (*size) = 0; if (data[0] < 192) { /* One-byte length */ (*size) = data[0]; (*length_size) = 1; } else if (data[0] < 224) { /* Two-byte length */ (*size) = (data[0] - 192) * 256; (*size) += data[1] + 192; (*length_size) = 2; } else if (data[0] == 255) { /* If support is added, adjust ECRYPTFS_MAX_PKT_LEN_SIZE */ ecryptfs_printk(KERN_ERR, "Five-byte packet length not " "supported\n"); rc = -EINVAL; goto out; } else { ecryptfs_printk(KERN_ERR, "Error parsing packet length\n"); rc = -EINVAL; goto out; }out: return rc;} /** * ecryptfs_write_packet_length * @dest: The byte array target into which to write the length. Must * have at least ECRYPTFS_MAX_PKT_LEN_SIZE bytes allocated. * @size: The length to write. * @packet_size_length: The number of bytes used to encode the packet * length is written to this address. * * Returns zero on success; non-zero on error. */int ecryptfs_write_packet_length(char *dest, size_t size, size_t *packet_size_length){ int rc = 0; if (size < 192) { dest[0] = size; (*packet_size_length) = 1; } else if (size < 65536) { dest[0] = (((size - 192) / 256) + 192); dest[1] = ((size - 192) % 256); (*packet_size_length) = 2; } else { /* If support is added, adjust ECRYPTFS_MAX_PKT_LEN_SIZE */ rc = -EINVAL; ecryptfs_printk(KERN_WARNING, "Unsupported packet size: [%zd]\n", size); } return rc;} static intwrite_tag_64_packet(char *signature, struct ecryptfs_session_key *session_key, char **packet, size_t *packet_len){ size_t i = 0; size_t data_len; size_t packet_size_len; char *message; int rc; /* * ***** TAG 64 Packet Format ***** * | Content Type | 1 byte | * | Key Identifier Size | 1 or 2 bytes | * | Key Identifier | arbitrary | * | Encrypted File Encryption Key Size | 1 or 2 bytes | * | Encrypted File Encryption Key | arbitrary | */ data_len = (5 + ECRYPTFS_SIG_SIZE_HEX + session_key->encrypted_key_size); *packet = kmalloc(data_len, GFP_KERNEL); message = *packet; if (!message) { ecryptfs_printk(KERN_ERR, "Unable to allocate memory\n"); rc = -ENOMEM; goto out; } message[i++] = ECRYPTFS_TAG_64_PACKET_TYPE; rc = ecryptfs_write_packet_length(&message[i], ECRYPTFS_SIG_SIZE_HEX, &packet_size_len); if (rc) { ecryptfs_printk(KERN_ERR, "Error generating tag 64 packet " "header; cannot generate packet length\n"); goto out; } i += packet_size_len; memcpy(&message[i], signature, ECRYPTFS_SIG_SIZE_HEX); i += ECRYPTFS_SIG_SIZE_HEX; rc = ecryptfs_write_packet_length(&message[i], session_key->encrypted_key_size, &packet_size_len); if (rc) { ecryptfs_printk(KERN_ERR, "Error generating tag 64 packet " "header; cannot generate packet length\n"); goto out; } i += packet_size_len; memcpy(&message[i], session_key->encrypted_key, session_key->encrypted_key_size); i += session_key->encrypted_key_size; *packet_len = i;out: return rc;} static intparse_tag_65_packet(struct ecryptfs_session_key *session_key, u8 *cipher_code, struct ecryptfs_message *msg){ size_t i = 0; char *data; size_t data_len; size_t m_size; size_t message_len; u16 checksum = 0; u16 expected_checksum = 0; int rc; /* * ***** TAG 65 Packet Format ***** * | Content Type | 1 byte | * | Status Indicator | 1 byte | * | File Encryption Key Size | 1 or 2 bytes | * | File Encryption Key | arbitrary | */ message_len = msg->data_len; data = msg->data; if (message_len < 4) { rc = -EIO; goto out; } if (data[i++] != ECRYPTFS_TAG_65_PACKET_TYPE) { ecryptfs_printk(KERN_ERR, "Type should be ECRYPTFS_TAG_65\n"); rc = -EIO; goto out; } if (data[i++]) { ecryptfs_printk(KERN_ERR, "Status indicator has non-zero value " "[%d]\n", data[i-1]); rc = -EIO; goto out; } rc = ecryptfs_parse_packet_length(&data[i], &m_size, &data_len); if (rc) { ecryptfs_printk(KERN_WARNING, "Error parsing packet length; " "rc = [%d]\n", rc); goto out; } i += data_len; if (message_len < (i + m_size)) { ecryptfs_printk(KERN_ERR, "The message received from ecryptfsd " "is shorter than expected\n"); rc = -EIO; goto out; } if (m_size < 3) { ecryptfs_printk(KERN_ERR, "The decrypted key is not long enough to " "include a cipher code and checksum\n"); rc = -EIO; goto out; } *cipher_code = data[i++]; /* The decrypted key includes 1 byte cipher code and 2 byte checksum */ session_key->decrypted_key_size = m_size - 3; if (session_key->decrypted_key_size > ECRYPTFS_MAX_KEY_BYTES) { ecryptfs_printk(KERN_ERR, "key_size [%d] larger than " "the maximum key size [%d]\n", session_key->decrypted_key_size, ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES); rc = -EIO; goto out; } memcpy(session_key->decrypted_key, &data[i], session_key->decrypted_key_size); i += session_key->decrypted_key_size; expected_checksum += (unsigned char)(data[i++]) << 8; expected_checksum += (unsigned char)(data[i++]); for (i = 0; i < session_key->decrypted_key_size; i++) checksum += session_key->decrypted_key[i]; if (expected_checksum != checksum) { ecryptfs_printk(KERN_ERR, "Invalid checksum for file " "encryption key; expected [%x]; calculated " "[%x]\n", expected_checksum, checksum); rc = -EIO; }out: return rc;} static intwrite_tag_66_packet(char *signature, u8 cipher_code, struct ecryptfs_crypt_stat *crypt_stat, char **packet, size_t *packet_len){ size_t i = 0; size_t j; size_t data_len; size_t checksum = 0; size_t packet_size_len; char *message; int rc; /* * ***** TAG 66 Packet Format ***** * | Content Type | 1 byte | * | Key Identifier Size | 1 or 2 bytes | * | Key Identifier | arbitrary | * | File Encryption Key Size | 1 or 2 bytes | * | Cipher Code | 1 byte | * | File Encryption Key | arbitrary | * | Checksum | 2 bytes | */ data_len = (8 + ECRYPTFS_SIG_SIZE_HEX + crypt_stat->key_size); *packet = kmalloc(data_len, GFP_KERNEL); message = *packet; if (!message) { ecryptfs_printk(KERN_ERR, "Unable to allocate memory\n"); rc = -ENOMEM; goto out; } message[i++] = ECRYPTFS_TAG_66_PACKET_TYPE; rc = ecryptfs_write_packet_length(&message[i], ECRYPTFS_SIG_SIZE_HEX, &packet_size_len); if (rc) { ecryptfs_printk(KERN_ERR, "Error generating tag 66 packet " "header; cannot generate packet length\n"); goto out; } i += packet_size_len; memcpy(&message[i], signature, ECRYPTFS_SIG_SIZE_HEX); i += ECRYPTFS_SIG_SIZE_HEX; /* The encrypted key includes 1 byte cipher code and 2 byte checksum */ rc = ecryptfs_write_packet_length(&message[i], crypt_stat->key_size + 3, &packet_size_len); if (rc) { ecryptfs_printk(KERN_ERR, "Error generating tag 66 packet " "header; cannot generate packet length\n"); goto out; } i += packet_size_len; message[i++] = cipher_code; memcpy(&message[i], crypt_stat->key, crypt_stat->key_size); i += crypt_stat->key_size; for (j = 0; j < crypt_stat->key_size; j++) checksum += crypt_stat->key[j]; message[i++] = (checksum / 256) % 256; message[i++] = (checksum % 256); *packet_len = i;out: return rc;} static intparse_tag_67_packet(struct ecryptfs_key_record *key_rec, struct ecryptfs_message *msg){ size_t i = 0; char *data; size_t data_len; size_t message_len; int rc; /* * ***** TAG 67 Packet Format ***** * | Content Type | 1 byte | * | Status Indicator | 1 byte | * | Encrypted File Encryption Key Size | 1 or 2 bytes | * | Encrypted File Encryption Key | arbitrary | */ message_len = msg->data_len; data = msg->data; /* verify that everything through the encrypted FEK size is present */ if (message_len < 4) { rc = -EIO; printk(KERN_ERR "%s: message_len is [%zd]; minimum acceptable " "message length is [%d]\n", __func__, message_len, 4); goto out; } if (data[i++] != ECRYPTFS_TAG_67_PACKET_TYPE) { rc = -EIO; printk(KERN_ERR "%s: Type should be ECRYPTFS_TAG_67\n", __func__); goto out; } if (data[i++]) { rc = -EIO; printk(KERN_ERR "%s: Status indicator has non zero " "value [%d]\n", __func__, data[i-1]); goto out; } rc = ecryptfs_parse_packet_length(&data[i], &key_rec->enc_key_size, &data_len); if (rc) { ecryptfs_printk(KERN_WARNING, "Error parsing packet length; " "rc = [%d]\n", rc); goto out; } i += data_len; if (message_len < (i + key_rec->enc_key_size)) { rc = -EIO; printk(KERN_ERR "%s: message_len [%zd]; max len is [%zd]\n", __func__, message_len, (i + key_rec->enc_key_size)); goto out; } if (key_rec->enc_key_size > ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES) { rc = -EIO; printk(KERN_ERR "%s: Encrypted key_size [%zd] larger than " "the maximum key size [%d]\n", __func__, key_rec->enc_key_size, ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES); goto out; } memcpy(key_rec->enc_key, &data[i], key_rec->enc_key_size);out: return rc;} /** * ecryptfs_verify_version * @version: The version number to confirm * * Returns zero on good version; non-zero otherwise */static int ecryptfs_verify_version(u16 version){ int rc = 0; unsigned char major; unsigned char minor; major = ((version >> 8) & 0xFF); minor = (version & 0xFF); if (major != ECRYPTFS_VERSION_MAJOR) { ecryptfs_printk(KERN_ERR, "Major version number mismatch. " "Expected [%d]; got [%d]\n", ECRYPTFS_VERSION_MAJOR, major); rc = -EINVAL; goto out; } if (minor != ECRYPTFS_VERSION_MINOR) { ecryptfs_printk(KERN_ERR, "Minor version number mismatch. " "Expected [%d]; got [%d]\n", ECRYPTFS_VERSION_MINOR, minor); rc = -EINVAL; goto out; }out: return rc;} /** * ecryptfs_verify_auth_tok_from_key * @auth_tok_key: key containing the authentication token * @auth_tok: authentication token * * Returns zero on valid auth tok; -EINVAL if the payload is invalid; or * -EKEYREVOKED if the key was revoked before we acquired its semaphore. */static intecryptfs_verify_auth_tok_from_key(struct key *auth_tok_key, struct ecryptfs_auth_tok **auth_tok){ int rc = 0; (*auth_tok) = ecryptfs_get_key_payload_data(auth_tok_key); if (IS_ERR(*auth_tok)) { rc = PTR_ERR(*auth_tok); *auth_tok = NULL; goto out; } if (ecryptfs_verify_version((*auth_tok)->version)) { printk(KERN_ERR "Data structure version mismatch. Userspace " "tools must match eCryptfs kernel module with major " "version [%d] and minor version [%d]\n", ECRYPTFS_VERSION_MAJOR, ECRYPTFS_VERSION_MINOR); rc = -EINVAL; goto out; } if ((*auth_tok)->token_type != ECRYPTFS_PASSWORD && (*auth_tok)->token_type != ECRYPTFS_PRIVATE_KEY) { printk(KERN_ERR "Invalid auth_tok structure " "returned from key query\n"); rc = -EINVAL; goto out; }out: return rc;} static intecryptfs_find_global_auth_tok_for_sig( struct key **auth_tok_key, struct ecryptfs_auth_tok **auth_tok, struct ecryptfs_mount_crypt_stat *mount_crypt_stat, char *sig){ struct ecryptfs_global_auth_tok *walker; int rc = 0; (*auth_tok_key) = NULL; (*auth_tok) = NULL; mutex_lock(&mount_crypt_stat->global_auth_tok_list_mutex); list_for_each_entry(walker, &mount_crypt_stat->global_auth_tok_list, mount_crypt_stat_list) { if (memcmp(walker->sig, sig, ECRYPTFS_SIG_SIZE_HEX)) continue;Lines 1–500 of 2516. Load more
// SPDX-License-Identifier: GPL-2.0-or-later /* * eCryptfs: Linux filesystem encryption layer * In-kernel key management code. Includes functions to parse and * write authentication token-related packets with the underlying * file. * * Copyright (C) 2004-2006 International Business Machines Corp. * Author(s): Michael A. Halcrow <mhalcrow@us.ibm.com> * Michael C. Thompson <mcthomps@us.ibm.com> * Trevor S. Highland <trevor.highland@gmail.com> */ #include <crypto/skcipher.h> #include <linux/string.h> #include <linux/pagemap.h> #include <linux/key.h> #include <linux/random.h> #include <linux/scatterlist.h> #include <linux/slab.h> #include "ecryptfs_kernel.h" /* * request_key returned an error instead of a valid key address; * determine the type of error, make appropriate log entries, and * return an error code. */ static int process_request_key_err(long err_code) { int rc = 0; switch (err_code) { case -ENOKEY: ecryptfs_printk(KERN_WARNING, "No key\n"); rc = -ENOENT; break; case -EKEYEXPIRED: ecryptfs_printk(KERN_WARNING, "Key expired\n"); rc = -ETIME; break; case -EKEYREVOKED: ecryptfs_printk(KERN_WARNING, "Key revoked\n"); rc = -EINVAL; break; default: ecryptfs_printk(KERN_WARNING, "Unknown error code: " "[0x%.16lx]\n", err_code); rc = -EINVAL; } return rc; } static int process_find_global_auth_tok_for_sig_err(int err_code) { int rc = err_code; switch (err_code) { case -ENOENT: ecryptfs_printk(KERN_WARNING, "Missing auth tok\n"); break; case -EINVAL: ecryptfs_printk(KERN_WARNING, "Invalid auth tok\n"); break; default: rc = process_request_key_err(err_code); break; } return rc; } /** * ecryptfs_parse_packet_length * @data: Pointer to memory containing length at offset * @size: This function writes the decoded size to this memory * address; zero on error * @length_size: The number of bytes occupied by the encoded length * * Returns zero on success; non-zero on error */ int ecryptfs_parse_packet_length(unsigned char *data, size_t *size, size_t *length_size) { int rc = 0; (*length_size) = 0; (*size) = 0; if (data[0] < 192) { /* One-byte length */ (*size) = data[0]; (*length_size) = 1; } else if (data[0] < 224) { /* Two-byte length */ (*size) = (data[0] - 192) * 256; (*size) += data[1] + 192; (*length_size) = 2; } else if (data[0] == 255) { /* If support is added, adjust ECRYPTFS_MAX_PKT_LEN_SIZE */ ecryptfs_printk(KERN_ERR, "Five-byte packet length not " "supported\n"); rc = -EINVAL; goto out; } else { ecryptfs_printk(KERN_ERR, "Error parsing packet length\n"); rc = -EINVAL; goto out; } out: return rc; } /** * ecryptfs_write_packet_length * @dest: The byte array target into which to write the length. Must * have at least ECRYPTFS_MAX_PKT_LEN_SIZE bytes allocated. * @size: The length to write. * @packet_size_length: The number of bytes used to encode the packet * length is written to this address. * * Returns zero on success; non-zero on error. */ int ecryptfs_write_packet_length(char *dest, size_t size, size_t *packet_size_length) { int rc = 0; if (size < 192) { dest[0] = size; (*packet_size_length) = 1; } else if (size < 65536) { dest[0] = (((size - 192) / 256) + 192); dest[1] = ((size - 192) % 256); (*packet_size_length) = 2; } else { /* If support is added, adjust ECRYPTFS_MAX_PKT_LEN_SIZE */ rc = -EINVAL; ecryptfs_printk(KERN_WARNING, "Unsupported packet size: [%zd]\n", size); } return rc; } static int write_tag_64_packet(char *signature, struct ecryptfs_session_key *session_key, char **packet, size_t *packet_len) { size_t i = 0; size_t data_len; size_t packet_size_len; char *message; int rc; /* * ***** TAG 64 Packet Format ***** * | Content Type | 1 byte | * | Key Identifier Size | 1 or 2 bytes | * | Key Identifier | arbitrary | * | Encrypted File Encryption Key Size | 1 or 2 bytes | * | Encrypted File Encryption Key | arbitrary | */ data_len = (5 + ECRYPTFS_SIG_SIZE_HEX + session_key->encrypted_key_size); *packet = kmalloc(data_len, GFP_KERNEL); message = *packet; if (!message) { ecryptfs_printk(KERN_ERR, "Unable to allocate memory\n"); rc = -ENOMEM; goto out; } message[i++] = ECRYPTFS_TAG_64_PACKET_TYPE; rc = ecryptfs_write_packet_length(&message[i], ECRYPTFS_SIG_SIZE_HEX, &packet_size_len); if (rc) { ecryptfs_printk(KERN_ERR, "Error generating tag 64 packet " "header; cannot generate packet length\n"); goto out; } i += packet_size_len; memcpy(&message[i], signature, ECRYPTFS_SIG_SIZE_HEX); i += ECRYPTFS_SIG_SIZE_HEX; rc = ecryptfs_write_packet_length(&message[i], session_key->encrypted_key_size, &packet_size_len); if (rc) { ecryptfs_printk(KERN_ERR, "Error generating tag 64 packet " "header; cannot generate packet length\n"); goto out; } i += packet_size_len; memcpy(&message[i], session_key->encrypted_key, session_key->encrypted_key_size); i += session_key->encrypted_key_size; *packet_len = i; out: return rc; } static int parse_tag_65_packet(struct ecryptfs_session_key *session_key, u8 *cipher_code, struct ecryptfs_message *msg) { size_t i = 0; char *data; size_t data_len; size_t m_size; size_t message_len; u16 checksum = 0; u16 expected_checksum = 0; int rc; /* * ***** TAG 65 Packet Format ***** * | Content Type | 1 byte | * | Status Indicator | 1 byte | * | File Encryption Key Size | 1 or 2 bytes | * | File Encryption Key | arbitrary | */ message_len = msg->data_len; data = msg->data; if (message_len < 4) { rc = -EIO; goto out; } if (data[i++] != ECRYPTFS_TAG_65_PACKET_TYPE) { ecryptfs_printk(KERN_ERR, "Type should be ECRYPTFS_TAG_65\n"); rc = -EIO; goto out; } if (data[i++]) { ecryptfs_printk(KERN_ERR, "Status indicator has non-zero value " "[%d]\n", data[i-1]); rc = -EIO; goto out; } rc = ecryptfs_parse_packet_length(&data[i], &m_size, &data_len); if (rc) { ecryptfs_printk(KERN_WARNING, "Error parsing packet length; " "rc = [%d]\n", rc); goto out; } i += data_len; if (message_len < (i + m_size)) { ecryptfs_printk(KERN_ERR, "The message received from ecryptfsd " "is shorter than expected\n"); rc = -EIO; goto out; } if (m_size < 3) { ecryptfs_printk(KERN_ERR, "The decrypted key is not long enough to " "include a cipher code and checksum\n"); rc = -EIO; goto out; } *cipher_code = data[i++]; /* The decrypted key includes 1 byte cipher code and 2 byte checksum */ session_key->decrypted_key_size = m_size - 3; if (session_key->decrypted_key_size > ECRYPTFS_MAX_KEY_BYTES) { ecryptfs_printk(KERN_ERR, "key_size [%d] larger than " "the maximum key size [%d]\n", session_key->decrypted_key_size, ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES); rc = -EIO; goto out; } memcpy(session_key->decrypted_key, &data[i], session_key->decrypted_key_size); i += session_key->decrypted_key_size; expected_checksum += (unsigned char)(data[i++]) << 8; expected_checksum += (unsigned char)(data[i++]); for (i = 0; i < session_key->decrypted_key_size; i++) checksum += session_key->decrypted_key[i]; if (expected_checksum != checksum) { ecryptfs_printk(KERN_ERR, "Invalid checksum for file " "encryption key; expected [%x]; calculated " "[%x]\n", expected_checksum, checksum); rc = -EIO; } out: return rc; } static int write_tag_66_packet(char *signature, u8 cipher_code, struct ecryptfs_crypt_stat *crypt_stat, char **packet, size_t *packet_len) { size_t i = 0; size_t j; size_t data_len; size_t checksum = 0; size_t packet_size_len; char *message; int rc; /* * ***** TAG 66 Packet Format ***** * | Content Type | 1 byte | * | Key Identifier Size | 1 or 2 bytes | * | Key Identifier | arbitrary | * | File Encryption Key Size | 1 or 2 bytes | * | Cipher Code | 1 byte | * | File Encryption Key | arbitrary | * | Checksum | 2 bytes | */ data_len = (8 + ECRYPTFS_SIG_SIZE_HEX + crypt_stat->key_size); *packet = kmalloc(data_len, GFP_KERNEL); message = *packet; if (!message) { ecryptfs_printk(KERN_ERR, "Unable to allocate memory\n"); rc = -ENOMEM; goto out; } message[i++] = ECRYPTFS_TAG_66_PACKET_TYPE; rc = ecryptfs_write_packet_length(&message[i], ECRYPTFS_SIG_SIZE_HEX, &packet_size_len); if (rc) { ecryptfs_printk(KERN_ERR, "Error generating tag 66 packet " "header; cannot generate packet length\n"); goto out; } i += packet_size_len; memcpy(&message[i], signature, ECRYPTFS_SIG_SIZE_HEX); i += ECRYPTFS_SIG_SIZE_HEX; /* The encrypted key includes 1 byte cipher code and 2 byte checksum */ rc = ecryptfs_write_packet_length(&message[i], crypt_stat->key_size + 3, &packet_size_len); if (rc) { ecryptfs_printk(KERN_ERR, "Error generating tag 66 packet " "header; cannot generate packet length\n"); goto out; } i += packet_size_len; message[i++] = cipher_code; memcpy(&message[i], crypt_stat->key, crypt_stat->key_size); i += crypt_stat->key_size; for (j = 0; j < crypt_stat->key_size; j++) checksum += crypt_stat->key[j]; message[i++] = (checksum / 256) % 256; message[i++] = (checksum % 256); *packet_len = i; out: return rc; } static int parse_tag_67_packet(struct ecryptfs_key_record *key_rec, struct ecryptfs_message *msg) { size_t i = 0; char *data; size_t data_len; size_t message_len; int rc; /* * ***** TAG 67 Packet Format ***** * | Content Type | 1 byte | * | Status Indicator | 1 byte | * | Encrypted File Encryption Key Size | 1 or 2 bytes | * | Encrypted File Encryption Key | arbitrary | */ message_len = msg->data_len; data = msg->data; /* verify that everything through the encrypted FEK size is present */ if (message_len < 4) { rc = -EIO; printk(KERN_ERR "%s: message_len is [%zd]; minimum acceptable " "message length is [%d]\n", __func__, message_len, 4); goto out; } if (data[i++] != ECRYPTFS_TAG_67_PACKET_TYPE) { rc = -EIO; printk(KERN_ERR "%s: Type should be ECRYPTFS_TAG_67\n", __func__); goto out; } if (data[i++]) { rc = -EIO; printk(KERN_ERR "%s: Status indicator has non zero " "value [%d]\n", __func__, data[i-1]); goto out; } rc = ecryptfs_parse_packet_length(&data[i], &key_rec->enc_key_size, &data_len); if (rc) { ecryptfs_printk(KERN_WARNING, "Error parsing packet length; " "rc = [%d]\n", rc); goto out; } i += data_len; if (message_len < (i + key_rec->enc_key_size)) { rc = -EIO; printk(KERN_ERR "%s: message_len [%zd]; max len is [%zd]\n", __func__, message_len, (i + key_rec->enc_key_size)); goto out; } if (key_rec->enc_key_size > ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES) { rc = -EIO; printk(KERN_ERR "%s: Encrypted key_size [%zd] larger than " "the maximum key size [%d]\n", __func__, key_rec->enc_key_size, ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES); goto out; } memcpy(key_rec->enc_key, &data[i], key_rec->enc_key_size); out: return rc; } /** * ecryptfs_verify_version * @version: The version number to confirm * * Returns zero on good version; non-zero otherwise */ static int ecryptfs_verify_version(u16 version) { int rc = 0; unsigned char major; unsigned char minor; major = ((version >> 8) & 0xFF); minor = (version & 0xFF); if (major != ECRYPTFS_VERSION_MAJOR) { ecryptfs_printk(KERN_ERR, "Major version number mismatch. " "Expected [%d]; got [%d]\n", ECRYPTFS_VERSION_MAJOR, major); rc = -EINVAL; goto out; } if (minor != ECRYPTFS_VERSION_MINOR) { ecryptfs_printk(KERN_ERR, "Minor version number mismatch. " "Expected [%d]; got [%d]\n", ECRYPTFS_VERSION_MINOR, minor); rc = -EINVAL; goto out; } out: return rc; } /** * ecryptfs_verify_auth_tok_from_key * @auth_tok_key: key containing the authentication token * @auth_tok: authentication token * * Returns zero on valid auth tok; -EINVAL if the payload is invalid; or * -EKEYREVOKED if the key was revoked before we acquired its semaphore. */ static int ecryptfs_verify_auth_tok_from_key(struct key *auth_tok_key, struct ecryptfs_auth_tok **auth_tok) { int rc = 0; (*auth_tok) = ecryptfs_get_key_payload_data(auth_tok_key); if (IS_ERR(*auth_tok)) { rc = PTR_ERR(*auth_tok); *auth_tok = NULL; goto out; } if (ecryptfs_verify_version((*auth_tok)->version)) { printk(KERN_ERR "Data structure version mismatch. Userspace " "tools must match eCryptfs kernel module with major " "version [%d] and minor version [%d]\n", ECRYPTFS_VERSION_MAJOR, ECRYPTFS_VERSION_MINOR); rc = -EINVAL; goto out; } if ((*auth_tok)->token_type != ECRYPTFS_PASSWORD && (*auth_tok)->token_type != ECRYPTFS_PRIVATE_KEY) { printk(KERN_ERR "Invalid auth_tok structure " "returned from key query\n"); rc = -EINVAL; goto out; } out: return rc; } static int ecryptfs_find_global_auth_tok_for_sig( struct key **auth_tok_key, struct ecryptfs_auth_tok **auth_tok, struct ecryptfs_mount_crypt_stat *mount_crypt_stat, char *sig) { struct ecryptfs_global_auth_tok *walker; int rc = 0; (*auth_tok_key) = NULL; (*auth_tok) = NULL; mutex_lock(&mount_crypt_stat->global_auth_tok_list_mutex); list_for_each_entry(walker, &mount_crypt_stat->global_auth_tok_list, mount_crypt_stat_list) { if (memcmp(walker->sig, sig, ECRYPTFS_SIG_SIZE_HEX)) continue;