/** * Copyright (C) 2006-2007 International Business Machines Corp. * Author(s): Trevor S. Highland * Mike Halcrow * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "../include/ecryptfs.h" #include "../include/decision_graph.h" struct openssl_data { char *path; char *passphrase; }; #if OPENSSL_VERSION_NUMBER < 0x10100000L static void RSA_get0_key(const RSA *r, const BIGNUM **n, const BIGNUM **e, const BIGNUM **d) { if (n != NULL) *n = r->n; if (e != NULL) *e = r->e; if (d != NULL) *d = r->d; } #endif static void ecryptfs_openssl_destroy_openssl_data(struct openssl_data *openssl_data) { free(openssl_data->path); free(openssl_data->passphrase); memset(openssl_data, 0, sizeof(struct openssl_data)); } /** * ecryptfs_openssl_deserialize * @openssl_data: The deserialized version of the key module data; * internal components pointed to blob memory * @blob: The key module-specific state blob * */ static int ecryptfs_openssl_deserialize(struct openssl_data *openssl_data, unsigned char *blob) { size_t path_length; size_t passphrase_length; size_t i = 0; path_length = blob[i++] % 256; path_length += blob[i++] << 8; i += path_length; passphrase_length = blob[i++] % 256; passphrase_length += blob[i++] << 8; openssl_data->path = (char *) blob + 2; openssl_data->passphrase = (openssl_data->path + path_length + 2); return 0; } /** * @blob: Callee allocates this memory */ static int ecryptfs_openssl_serialize(unsigned char *blob, size_t *blob_size, struct openssl_data *openssl_data) { size_t path_length; size_t passphrase_length; size_t i = 0; int rc = 0; (*blob_size) = 0; if (!openssl_data->path || !openssl_data->passphrase) { rc = -EINVAL; syslog(LOG_ERR, "openssl_data internal structure not " "properly filled in\n"); goto out; } path_length = strlen(openssl_data->path) + 1; /* + '\0' */ passphrase_length = strlen(openssl_data->passphrase) + 1; (*blob_size) = (2 + path_length + 2 + passphrase_length); if (!blob) goto out; blob[i++] = path_length % 256; blob[i++] = path_length >> 8; memcpy(&blob[i], openssl_data->path, path_length); i += path_length; blob[i++] = passphrase_length % 256; blob[i++] = passphrase_length >> 8; memcpy(&blob[i], openssl_data->passphrase, passphrase_length); out: return rc; } struct ecryptfs_subgraph_ctx { struct ecryptfs_key_mod *key_mod; struct openssl_data openssl_data; }; static void ecryptfs_openssl_destroy_subgraph_ctx(struct ecryptfs_subgraph_ctx *ctx) { ecryptfs_openssl_destroy_openssl_data(&ctx->openssl_data); memset(ctx, 0, sizeof(struct ecryptfs_subgraph_ctx)); } /** * ecryptfs_openssl_generate_signature * @sig: Generated sig (ECRYPTFS_SIG_SIZE_HEX + 1 bytes of allocated memory) * @key: RSA key from which to generate sig */ static int ecryptfs_openssl_generate_signature(char *sig, RSA *key) { int len, nbits, ebits, i; int nbytes, ebytes; const BIGNUM *key_n, *key_e; unsigned char *hash; unsigned char *data = NULL; int rc = 0; hash = malloc(SHA_DIGEST_LENGTH); if (!hash) { syslog(LOG_ERR, "Out of memory\n"); rc = -ENOMEM; goto out; } RSA_get0_key(key, &key_n, NULL, NULL); nbits = BN_num_bits(key_n); nbytes = nbits / 8; if (nbits % 8) nbytes++; RSA_get0_key(key, NULL, &key_e, NULL); ebits = BN_num_bits(key_e); ebytes = ebits / 8; if (ebits % 8) ebytes++; len = 10 + nbytes + ebytes; data = malloc(3 + len); if (!data) { syslog(LOG_ERR, "Out of memory\n"); rc = -ENOMEM; goto out; } i = 0; data[i++] = '\x99'; data[i++] = (len >> 8); data[i++] = len; data[i++] = '\x04'; data[i++] = '\00'; data[i++] = '\00'; data[i++] = '\00'; data[i++] = '\00'; data[i++] = '\02'; data[i++] = (nbits >> 8); data[i++] = nbits; RSA_get0_key(key, &key_n, NULL, NULL); BN_bn2bin(key_n, &(data[i])); i += nbytes; data[i++] = (ebits >> 8); data[i++] = ebits; RSA_get0_key(key, NULL, &key_e, NULL); BN_bn2bin(key_e, &(data[i])); i += ebytes; SHA1(data, len + 3, hash); to_hex(sig, (char *)hash, ECRYPTFS_SIG_SIZE); sig[ECRYPTFS_SIG_SIZE_HEX] = '\0'; out: free(data); free(hash); return rc; } static int ecryptfs_openssl_mkdir_recursive(char *dir, mode_t mode) { char *temp = NULL; char *parent = NULL; int rc = 0; if (!strcmp(dir, ".") || !strcmp(dir, "/")) goto out; temp = strdup(dir); if (temp == NULL) { rc = -ENOMEM; goto out; } parent = dirname(temp); rc = ecryptfs_openssl_mkdir_recursive(parent, mode); if (rc) goto out; if (mkdir(dir, mode) == -1) { if (errno != EEXIST) { rc = -errno; goto out; } } rc = 0; out: free(temp); return rc; } static int ecryptfs_openssl_write_key_to_file(RSA *rsa, char *filename, char *passphrase) { char *tmp_filename; char *openssl_dir; BIO *out; const EVP_CIPHER *enc = EVP_aes_256_cbc(); int rc = 0; tmp_filename = strdup(filename); if (tmp_filename == NULL) { rc = -ENOMEM; goto out; } openssl_dir = dirname(tmp_filename); rc = ecryptfs_openssl_mkdir_recursive(openssl_dir, 0700); if (rc) { syslog(LOG_WARNING, "%s: Error attempting to mkdir [%s]; " "rc = [%d]\n", __FUNCTION__, openssl_dir, rc); } if ((out = BIO_new(BIO_s_file())) == NULL) { syslog(LOG_ERR, "Unable to create BIO for output\n"); rc= -EIO; goto out; } if (BIO_write_filename(out, filename) <= 0) { syslog(LOG_ERR, "Failed to open file for reading\n"); rc = -EIO; goto out_free_bio; } if (!PEM_write_bio_RSAPrivateKey(out, rsa, enc, NULL, 0, NULL, (void *)passphrase)) { syslog(LOG_ERR, "Failed to write key to file\n"); rc = -EIO; goto out_free_bio; } out_free_bio: BIO_free_all(out); out: free(tmp_filename); return rc; } /** * ecryptfs_openssl_read_key * @rsa: RSA key to allocate * @blob: Key module data to use in finding the key */ static int ecryptfs_openssl_read_key(RSA **rsa, unsigned char *blob) { struct openssl_data *openssl_data = NULL; BIO *in = NULL; int rc; #if OPENSSL_VERSION_NUMBER < 0x10100000L CRYPTO_malloc_init(); #endif ERR_load_crypto_strings(); OpenSSL_add_all_algorithms(); ENGINE_load_builtin_engines(); openssl_data = malloc(sizeof(struct openssl_data)); if (!openssl_data) { syslog(LOG_ERR, "Out of memory\n"); rc = -ENOMEM; goto out; } ecryptfs_openssl_deserialize(openssl_data, blob); if ((in = BIO_new(BIO_s_file())) == NULL) { syslog(LOG_ERR, "Unable to create BIO for output\n"); rc = -EIO; goto out; } if (BIO_read_filename(in, openssl_data->path) <= 0) { syslog(LOG_ERR, "Unable to read filename [%s]\n", openssl_data->path); rc = -EIO; goto out; } if ((*rsa = PEM_read_bio_RSAPrivateKey(in, NULL, NULL, openssl_data->passphrase)) == NULL) { syslog(LOG_ERR, "%s: Unable to read private key from file [%s]\n", __FUNCTION__, openssl_data->path); rc = -ENOKEY; goto out; } rc = 0; out: free(openssl_data); BIO_free_all(in); EVP_cleanup(); CRYPTO_cleanup_all_ex_data(); ERR_remove_state(0); ERR_free_strings(); return rc; } int ecryptfs_openssl_get_key_sig(unsigned char *sig, unsigned char *blob) { RSA *rsa = NULL; int rc; if ((rc = ecryptfs_openssl_read_key(&rsa, blob))) { syslog(LOG_ERR, "Error attempting to read RSA key from file;" " rc = [%d]\n", rc); goto out; } if ((rc = ecryptfs_openssl_generate_signature((char *)sig, rsa))) { syslog(LOG_ERR, "%s: Error attempting to generate key " "signature; rc = [%d]\n", __FUNCTION__, rc); goto out_free_rsa; } out_free_rsa: RSA_free(rsa); out: return rc; } /** * ecryptfs_openssl_generate_key * @filename: File into which to write the newly generated key * * Generate a new key and write it out to a file. */ static int ecryptfs_openssl_generate_key(struct openssl_data *openssl_data) { RSA *rsa; int rc = 0; if ((rsa = RSA_generate_key(1024, 65537, NULL, NULL)) == NULL) { syslog(LOG_ERR, "Error generating new RSA key\n"); rc = -ENOMEM; goto out; } if ((rc = ecryptfs_openssl_write_key_to_file( rsa, openssl_data->path, openssl_data->passphrase))) { syslog(LOG_ERR, "Error writing key to file; rc = [%d]\n", rc); rc = -EIO; goto out_free_rsa; } out_free_rsa: RSA_free(rsa); out: return rc; } /** * ecryptfs_openssl_encrypt * @to: Where to write encrypted data * @size: Number of bytes to encrypt * @from: Data to encrypt * @blob: Arbitrary blob specific to this key module * * Encrypt @size bytes of data in @from, writing the encrypted data * into @to, using @blob as the parameters for the * encryption. */ static int ecryptfs_openssl_encrypt(char *to, size_t *to_size, char *from, size_t from_size, unsigned char *blob, int blob_type) { RSA *rsa = NULL; int rc; (*to_size) = 0; if ((rc = ecryptfs_openssl_read_key(&rsa, blob))) { rc = -(int)ERR_get_error(); syslog(LOG_ERR, "Error attempting to read RSA key from file;" " rc = [%d]\n", rc); goto out; } (*to_size) = RSA_size(rsa); if (to) { if ((rc = RSA_public_encrypt(from_size, (unsigned char *)from, (unsigned char *)to, rsa, RSA_PKCS1_OAEP_PADDING)) == -1) { rc = -(int)ERR_get_error(); syslog(LOG_ERR, "Error attempting to perform RSA " "public key encryption; rc = [%d]\n", rc); goto out_free_rsa; } else { (*to_size) = rc; rc = 0; } } out_free_rsa: RSA_free(rsa); out: return rc; } /** * ecryptfs_openssl_dencrypt * @from: Data to decrypt * @to: Where to write decrypted data * @decrypted_key_size: Number of bytes decrypted * @blob: Arbitrary blob specific to this key module * * Decrypt data in @from, writing the decrypted data into @to, using * @blob as the parameters for the encryption. */ static int ecryptfs_openssl_decrypt(char *to, size_t *to_size, char *from, size_t from_size, unsigned char *blob, int blob_type) { RSA *rsa = NULL; int rc; (*to_size) = 0; if ((rc = ecryptfs_openssl_read_key(&rsa, blob))) { rc = -(int)ERR_get_error(); syslog(LOG_ERR, "Error attempting to read RSA key from file;" " rc = [%d]\n", rc); goto out; } (*to_size) = RSA_size(rsa); if (to) { if ((rc = RSA_private_decrypt(from_size, (unsigned char *)from, (unsigned char *)to, rsa, RSA_PKCS1_OAEP_PADDING)) == -1) { rc = -(int)ERR_get_error(); syslog(LOG_ERR, "Error attempting to perform RSA " "public key decryption; rc = [%d]\n", rc); goto out_free_rsa; } else { (*to_size) = rc; rc = 0; } } out_free_rsa: RSA_free(rsa); out: return rc; } int ecryptfs_openssl_init_from_param_vals(struct openssl_data *, struct key_mod_param_val *, uint32_t); static int ecryptfs_openssl_get_blob(unsigned char *blob, size_t *blob_size, struct key_mod_param_val *param_vals, uint32_t num_param_vals) { struct openssl_data openssl_data; int rc = 0; if ((rc = ecryptfs_openssl_init_from_param_vals(&openssl_data, param_vals, num_param_vals))) { syslog(LOG_ERR, "Error parsing parameter values; rc = [%d]\n", rc); goto out; } if (blob == NULL) { if ((rc = ecryptfs_openssl_serialize(NULL, blob_size, &openssl_data))) { syslog(LOG_ERR, "Error serializing openssl; rc = [%d]\n", rc); goto out; } goto out; } if ((rc = ecryptfs_openssl_serialize(blob, blob_size, &openssl_data))) { syslog(LOG_ERR, "Error serializing openssl; rc = [%d]\n", rc); goto out; } out: return rc; } static int tf_ssl_keyfile(struct ecryptfs_ctx *ctx, struct param_node *node, struct val_node **mnt_params, void **foo) { struct ecryptfs_subgraph_ctx *subgraph_ctx; int rc; subgraph_ctx = (struct ecryptfs_subgraph_ctx *)(*foo); if ((rc = asprintf(&subgraph_ctx->openssl_data.path, "%s", node->val)) == -1) { rc = -ENOMEM; goto out; } rc = DEFAULT_TOK; free(node->val); node->val = NULL; out: return rc; } static int ecryptfs_openssl_process_key(struct ecryptfs_subgraph_ctx *subgraph_ctx, struct val_node **mnt_params) { size_t blob_size; char *sig_mnt_opt; char sig[ECRYPTFS_SIG_SIZE_HEX + 1]; int rc; if ((rc = ecryptfs_openssl_serialize(NULL, &blob_size, &subgraph_ctx->openssl_data))) { syslog(LOG_ERR, "Error serializing openssl; rc = [%d]\n", rc); rc = MOUNT_ERROR; goto out; } if (blob_size == 0) { syslog(LOG_ERR, "Error serializing openssl\n"); rc = MOUNT_ERROR; goto out; } if ((subgraph_ctx->key_mod->blob = malloc(blob_size)) == NULL) { syslog(LOG_ERR, "Out of memory\n"); rc = -ENOMEM; goto out; } if ((rc = ecryptfs_openssl_serialize((unsigned char *) subgraph_ctx->key_mod->blob, &subgraph_ctx->key_mod->blob_size, &subgraph_ctx->openssl_data))) { syslog(LOG_ERR, "Error serializing openssl; rc = [%d]\n", rc); rc = MOUNT_ERROR; goto out; } if (subgraph_ctx->key_mod->blob_size != blob_size) { syslog(LOG_ERR, "%s: Internal error\n", __FUNCTION__); exit(1); } if ((rc = ecryptfs_add_key_module_key_to_keyring( sig, subgraph_ctx->key_mod)) < 0) { syslog(LOG_ERR, "Error attempting to add key to keyring for " "key module [%s]; rc = [%d]\n", subgraph_ctx->key_mod->alias, rc); goto out; } if ((rc = asprintf(&sig_mnt_opt, "ecryptfs_sig=%s", sig)) == -1) { rc = -ENOMEM; goto out; } rc = stack_push(mnt_params, sig_mnt_opt); out: return rc; } static int limit_key_size(struct val_node **params, struct ecryptfs_subgraph_ctx *subgraph_ctx) { char *buf; int rc; RSA *rsa = NULL; if ((rc=ecryptfs_openssl_read_key(&rsa, (unsigned char *)subgraph_ctx->key_mod->blob))) return rc; /* 41 is for padding and 3 are for additional data send from * kernel (1 for cipher type and 2 for checksum */ if ((rc = asprintf(&buf, "max_key_bytes=%d", RSA_size(rsa)-41-3)) == -1) { rc = -ENOMEM; goto out; } rc = stack_push(params, buf); out: RSA_free(rsa); return rc; } /** * * */ static int tf_ssl_passwd(struct ecryptfs_ctx *ctx, struct param_node *node, struct val_node **mnt_params, void **foo) { struct ecryptfs_subgraph_ctx *subgraph_ctx; int rc; if (ecryptfs_verbosity) syslog(LOG_INFO, "%s: Called w/ node->val = [%s]\n", __FUNCTION__, node->val); subgraph_ctx = (struct ecryptfs_subgraph_ctx *)(*foo); if ((rc = asprintf(&subgraph_ctx->openssl_data.passphrase, "%s", node->val)) == -1) { rc = -ENOMEM; goto out; } free(node->val); node->val = NULL; if ((rc = ecryptfs_openssl_process_key(subgraph_ctx, mnt_params))) { syslog(LOG_ERR, "Error processing OpenSSL key; rc = [%d]", rc); goto out; } limit_key_size(mnt_params, subgraph_ctx); ecryptfs_openssl_destroy_subgraph_ctx(subgraph_ctx); free(subgraph_ctx); (*foo) = NULL; rc = DEFAULT_TOK; out: return rc; } static int tf_ssl_passwd_file(struct ecryptfs_ctx *ctx, struct param_node *node, struct val_node **mnt_params, void **foo) { int rc = 0; int fd; struct ecryptfs_subgraph_ctx *subgraph_ctx; struct ecryptfs_name_val_pair file_head = { 0, }; struct ecryptfs_name_val_pair *walker = NULL; syslog(LOG_INFO, "%s: Called\n", __FUNCTION__); subgraph_ctx = (struct ecryptfs_subgraph_ctx *)(*foo); if (strcmp(node->mnt_opt_names[0], "openssl_passwd_file") == 0) fd = open(node->val, O_RDONLY); else if (strcmp(node->mnt_opt_names[0], "openssl_passwd_fd") == 0) fd = strtol(node->val, NULL, 0); else { rc = MOUNT_ERROR; goto out; } if (fd == -1) { syslog(LOG_ERR, "%s: Error attempting to open file\n", __FUNCTION__); rc = MOUNT_ERROR; goto out; } rc = parse_options_file(fd, &file_head); close(fd); if (rc) { syslog(LOG_ERR, "%s: Error attempting to parse options out " "of file\n", __FUNCTION__); goto out; } walker = file_head.next; while (walker) { if (strcmp(walker->name, "openssl_passwd") == 0) { if ((rc = asprintf(&subgraph_ctx->openssl_data.passphrase, "%s", walker->value)) == -1) { rc = -ENOMEM; goto out; } break; } walker = walker->next; } if (!walker) { syslog(LOG_ERR, "%s: No openssl_passwd option found in file\n", __FUNCTION__); rc = MOUNT_ERROR; goto out; } walker = NULL; if ((rc = ecryptfs_openssl_process_key(subgraph_ctx, mnt_params))) { syslog(LOG_ERR, "Error processing OpenSSL key; rc = [%d]", rc); goto out; } limit_key_size(mnt_params, subgraph_ctx); ecryptfs_openssl_destroy_subgraph_ctx(subgraph_ctx); free(subgraph_ctx); (*foo) = NULL; rc = DEFAULT_TOK; out: free_name_val_pairs(file_head.next); free(file_head.name); free(file_head.value); free(node->val); node->val = NULL; syslog(LOG_INFO, "%s: Exiting\n", __FUNCTION__); return rc; } static int tf_ssl_passwd_fd(struct ecryptfs_ctx *ctx, struct param_node *node, struct val_node **mnt_params, void **foo) { return ENOSYS; } static int tf_ecryptfs_openssl_gen_key_param_node_keyfile( struct ecryptfs_ctx *ctx, struct param_node *node, struct val_node **mnt_params, void **foo) { struct ecryptfs_subgraph_ctx *subgraph_ctx; int rc = DEFAULT_TOK; subgraph_ctx = (struct ecryptfs_subgraph_ctx *)(*foo); if ((rc = asprintf(&subgraph_ctx->openssl_data.path, "%s", node->val)) == -1) { rc = -ENOMEM; goto out; } rc = DEFAULT_TOK; out: return rc; } static int tf_ecryptfs_openssl_gen_key_param_node_passphrase( struct ecryptfs_ctx *ctx, struct param_node *node, struct val_node **mnt_params, void **foo) { struct ecryptfs_subgraph_ctx *subgraph_ctx; int rc = DEFAULT_TOK; subgraph_ctx = (struct ecryptfs_subgraph_ctx *)(*foo); if ((rc = asprintf(&subgraph_ctx->openssl_data.passphrase, "%s", node->val)) == -1) { rc = -ENOMEM; goto out; } if ((rc = ecryptfs_openssl_generate_key(&subgraph_ctx->openssl_data))) { syslog(LOG_ERR, "%s: Error generating key to file [%s]; " "rc = [%d]\n", __FUNCTION__, subgraph_ctx->openssl_data.path, rc); rc = MOUNT_ERROR; goto out; } out: return rc; } #define ECRYPTFS_OPENSSL_GEN_KEY_PARAM_NODE_KEYFILE 0 #define ECRYPTFS_OPENSSL_GEN_KEY_PARAM_NODE_PASSPHRASE 1 static struct param_node ecryptfs_openssl_gen_key_param_nodes[] = { {.num_mnt_opt_names = 1, .mnt_opt_names = {"keyfile"}, .prompt = "SSL key file path", .val_type = VAL_STR, .val = NULL, .display_opts = NULL, .default_val = NULL, .suggested_val = NULL, .flags = ECRYPTFS_PARAM_FLAG_ECHO_INPUT, .num_transitions = 1, .tl = {{.val = "default", .pretty_val = "", .next_token = &ecryptfs_openssl_gen_key_param_nodes[ ECRYPTFS_OPENSSL_GEN_KEY_PARAM_NODE_PASSPHRASE], .trans_func = &tf_ecryptfs_openssl_gen_key_param_node_keyfile}}}, {.num_mnt_opt_names = 1, .mnt_opt_names = {"passphrase"}, .prompt = "Passphrase", .val_type = VAL_STR, .val = NULL, .display_opts = NULL, .default_val = NULL, .suggested_val = NULL, .flags = ECRYPTFS_PARAM_FLAG_MASK_OUTPUT | VERIFY_VALUE, .num_transitions = 1, .tl = {{.val = NULL, .pretty_val = NULL, .next_token = NULL, .trans_func = &tf_ecryptfs_openssl_gen_key_param_node_passphrase}}} }; #define SSL_KEY_SOURCE_TOK 0 #define SSL_KEY_FILE_TOK 1 #define SSL_PASSPHRASE_METHOD_TOK 2 #define SSL_USER_PROVIDED_PASSWD_TOK 3 #define SSL_FILE_PASSWD_TOK 4 #define SSL_FD_PASSWD_TOK 5 static struct param_node ssl_param_nodes[] = { {.num_mnt_opt_names = 2, .mnt_opt_names = {"openssl_keysource", "keysource"}, .prompt = "Key source", .val_type = VAL_STR, .val = NULL, .display_opts = NULL, .default_val = "keyfile", .flags = ECRYPTFS_PARAM_FLAG_NO_VALUE, .num_transitions = 1, .tl = {{.val = "default", .pretty_val = "OpenSSL Key File", .next_token = &ssl_param_nodes[SSL_KEY_FILE_TOK], .trans_func = NULL}}}, /* Add more options here later */ {.num_mnt_opt_names = 2, .mnt_opt_names = {"openssl_keyfile", "keyfile"}, .prompt = "PEM key file", .val_type = VAL_STR, .val = NULL, .display_opts = NULL, .default_val = NULL, .flags = ECRYPTFS_PARAM_FLAG_ECHO_INPUT, .num_transitions = 1, .tl = {{.val = "default", /* The decision graph code will * just follow a "default" * transition node */ .pretty_val = "Passphrase Method", .next_token = &ssl_param_nodes[SSL_PASSPHRASE_METHOD_TOK], .trans_func = tf_ssl_keyfile}}}, {.num_mnt_opt_names = 2, .mnt_opt_names = {"openssl_passwd_specification_method", "passwd_specification_method"}, .prompt = "Method of providing the passphrase", .val_type = VAL_STR, .val = NULL, .display_opts = NULL, .default_val = NULL, .suggested_val = "openssl_passwd", /* An implicit transition takes place if one of the key * module parameters that are the target of one of the * transition nodes already exists in the provided parameter * list. */ .flags = (DISPLAY_TRANSITION_NODE_VALS | ECRYPTFS_DISPLAY_PRETTY_VALS | ECRYPTFS_PARAM_FLAG_ECHO_INPUT | ECRYPTFS_ALLOW_IMPLICIT_TRANSITION), .num_transitions = 3, .tl = {{.val = "openssl_passwd", .pretty_val = "openssl_passwd: Enter on Console", .next_token = &ssl_param_nodes[SSL_USER_PROVIDED_PASSWD_TOK], .trans_func = NULL}, {.val = "openssl_passwd_file", .pretty_val = "openssl_passwd_file: File Containing Passphrase", .next_token = &ssl_param_nodes[SSL_FILE_PASSWD_TOK], .trans_func = NULL}, {.val = "openssl_passwd_fd", .pretty_val = ("openssl_passwd_fd: File Descriptor for File " "Containing Passphrase"), .next_token = &ssl_param_nodes[SSL_FD_PASSWD_TOK], .trans_func = NULL}}}, {.num_mnt_opt_names = 2, .mnt_opt_names = {"openssl_passwd", "passwd"}, .prompt = "Passphrase", .val_type = VAL_STR, .val = NULL, .display_opts = NULL, .default_val = NULL, .flags = STDIN_REQUIRED | ECRYPTFS_PARAM_FLAG_MASK_OUTPUT, .num_transitions = 1, .tl = {{.val = NULL, .pretty_val = NULL, .next_token = NULL, .trans_func = tf_ssl_passwd}}}, {.num_mnt_opt_names = 2, .mnt_opt_names = {"openssl_passwd_file", "passwd_file"}, .prompt = "Passphrase File", .val_type = VAL_STR, .val = NULL, .display_opts = NULL, .default_val = NULL, .flags = STDIN_REQUIRED | ECRYPTFS_PARAM_FLAG_ECHO_INPUT | ECRYPTFS_NONEMPTY_VALUE_REQUIRED, .num_transitions = 1, .tl = {{.val = NULL, .pretty_val = NULL, .next_token = NULL, .trans_func = tf_ssl_passwd_file}}}, {.num_mnt_opt_names = 2, .mnt_opt_names = {"openssl_passwd_fd", "passwd_fd"}, .prompt = "Passphrase File Descriptor", .val_type = VAL_STR, .val = NULL, .display_opts = NULL, .default_val = NULL, .flags = STDIN_REQUIRED | ECRYPTFS_PARAM_FLAG_ECHO_INPUT | ECRYPTFS_NONEMPTY_VALUE_REQUIRED, .num_transitions = 1, .tl = {{.val = NULL, .pretty_val = NULL, .next_token = NULL, .trans_func = tf_ssl_passwd_fd}}} }; /** * tf_openssl_enter * @ctx: The current applicable libecryptfs context struct * @node: The param_node from which we are transitioning * @head: The head of the name/value pair list that is being * constructed as the decision graph is being traversed * @foo: Arbitrary state information for the current subgraph * * Each transition from one node in the decision graph to another node * can have a function executed on the transition event. A transition * into any given subgraph may require certain housekeeping and * initialization functions to occur. * * The decision graph engine forwards along an arbitrary data * structure among the nodes of any subgraph. The logic in the * subgraph can use that data structure to access and maintain * arbitrary status information that is unique to the function of that * subgraph. */ static int tf_openssl_enter(struct ecryptfs_ctx *ctx, struct param_node *param_node, struct val_node **mnt_params, void **foo) { struct ecryptfs_subgraph_ctx *subgraph_ctx; int rc; if ((subgraph_ctx = malloc(sizeof(struct ecryptfs_subgraph_ctx))) == NULL) { rc = -ENOMEM; goto out; } memset(subgraph_ctx, 0, sizeof(struct ecryptfs_subgraph_ctx)); if ((rc = ecryptfs_find_key_mod(&subgraph_ctx->key_mod, ctx, param_node->val))) { syslog(LOG_ERR, "%s: Cannot find key_mod for param_node with " "val = [%s]\n", __FUNCTION__, param_node->val); free(subgraph_ctx); goto out; } (*foo) = (void *)subgraph_ctx; out: return rc; } struct transition_node openssl_transition = { .val = "openssl", .pretty_val = "OpenSSL module", .next_token = &(ssl_param_nodes[SSL_KEY_SOURCE_TOK]), .trans_func = tf_openssl_enter }; static int ecryptfs_openssl_get_param_subgraph_trans_node( struct transition_node **trans, uint32_t version) { if ((version & ECRYPTFS_VERSIONING_PUBKEY) == 0) return -1; (*trans) = &openssl_transition; return 0; } struct transition_node openssl_gen_key_transition = { .val = "openssl", .pretty_val = "OpenSSL module", .next_token = &(ecryptfs_openssl_gen_key_param_nodes[ ECRYPTFS_OPENSSL_GEN_KEY_PARAM_NODE_KEYFILE]), .trans_func = tf_openssl_enter }; static int ecryptfs_openssl_get_gen_key_param_subgraph_trans_node( struct transition_node **trans, uint32_t version) { if ((version & ECRYPTFS_VERSIONING_PUBKEY) == 0) return -1; (*trans) = &openssl_gen_key_transition; return 0; } int ecryptfs_openssl_finalize(void) { return 0; } static int ecryptfs_openssl_init(char **alias) { uid_t id; struct passwd *pw; struct param_node *gen_key_keyfile_param_node = &ecryptfs_openssl_gen_key_param_nodes[ ECRYPTFS_OPENSSL_GEN_KEY_PARAM_NODE_KEYFILE]; int rc = 0; if (asprintf(alias, "openssl") == -1) { rc = -ENOMEM; syslog(LOG_ERR, "Out of memory\n"); goto out; } id = getuid(); pw = getpwuid(id); if (!pw) { rc = -EIO; goto out; } if ((rc = asprintf(&ssl_param_nodes[SSL_KEY_FILE_TOK].suggested_val, "%s/.ecryptfs/pki/openssl/key.pem", pw->pw_dir)) == -1) { rc = -ENOMEM; goto out; } if ((rc = asprintf(&gen_key_keyfile_param_node->suggested_val, "%s/.ecryptfs/pki/openssl/key.pem", pw->pw_dir)) == -1) { rc = -ENOMEM; goto out; } rc = 0; out: return rc; } static struct ecryptfs_key_mod_ops ecryptfs_openssl_ops = { &ecryptfs_openssl_init, NULL, &ecryptfs_openssl_get_gen_key_param_subgraph_trans_node, NULL, &ecryptfs_openssl_get_param_subgraph_trans_node, &ecryptfs_openssl_get_blob, NULL, &ecryptfs_openssl_get_key_sig, NULL, &ecryptfs_openssl_encrypt, &ecryptfs_openssl_decrypt, NULL, &ecryptfs_openssl_finalize }; struct ecryptfs_key_mod_ops *get_key_mod_ops(void) { return &ecryptfs_openssl_ops; }