Logo Search packages:      
Sourcecode: ecryptfs-utils version File versions

ecryptfs_pki_openssl.c

/**
 * Copyright (C) 2006-2007 International Business Machines Corp.
 * Author(s): Trevor S. Highland <trevor.highland@gmail.com>
 *            Mike Halcrow <mhalcrow@us.ibm.com>
 *
 * 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.
 */

#include <fcntl.h>
#include <pwd.h>
#include <stdio.h>
#include <string.h>
#include <syslog.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <openssl/pem.h>
#include <openssl/rsa.h>
#include <openssl/err.h>
#include <openssl/engine.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "../include/ecryptfs.h"
#include "../include/decision_graph.h"

struct pki_openssl {
      char *path;
      char *password;
      char *signature;
};

/**
 * ecryptfs_openssl_deserialize
 * @blob: The key module-specific state blob
 * @pki_data: The deserialized version of the key module data
 */
static int
ecryptfs_openssl_deserialize(unsigned char *blob, struct pki_openssl *pki_data)
{
      size_t path_length;
      size_t pass_length;
      size_t i = 0;

      path_length = blob[i++] % 256;
      path_length += blob[i++] << 8;
      i += path_length;
      pass_length = blob[i++] % 256;
      pass_length += blob[i++] << 8;
      pki_data->path = blob + 2;
      pki_data->password = pki_data->path + path_length + 2;
      pki_data->signature = pki_data->password + pass_length + 2;
      return 0;
}

/**
 * generate_signature
 * @key: RSA key from which to generate sig
 * @sig: Generated sig
 */
static int generate_signature(RSA *key, char *sig)
{
      int len, nbits, ebits, i;
      int nbytes, ebytes;
      char *hash;
      char *data = NULL;
      int rc = 0;

      hash = malloc(SHA_DIGEST_LENGTH);
      if (!hash) {
            syslog(LOG_ERR, "Out of memory\n");
            rc = -ENOMEM;
            goto out;
      }
      nbits = BN_num_bits(key->n);
      nbytes = nbits / 8;
      if (nbits % 8)
            nbytes++;
      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++] = (char)(len >> 8);
      data[i++] = (char)len;
      data[i++] = '\x04';
      data[i++] = '\00';
      data[i++] = '\00';
      data[i++] = '\00';
      data[i++] = '\00';
      data[i++] = '\02';
      data[i++] = (char)(nbits >> 8);
      data[i++] = (char)nbits;
      BN_bn2bin(key->n, &(data[i]));
      i += nbytes;
      data[i++] = (char)(ebits >> 8);
      data[i++] = (char)ebits;
      BN_bn2bin(key->e, &(data[i]));
      i += ebytes;
      SHA1(data, len + 3, hash);
      to_hex(sig, hash, ECRYPTFS_SIG_SIZE);
      sig[ECRYPTFS_SIG_SIZE_HEX] = '\0';
out:
      free(data);
      free(hash);
      return rc;
}

static int write_key_to_file(RSA *rsa, char *filename, char *pass)
{
      BIO *out;
      const EVP_CIPHER *enc = EVP_aes_256_cbc();
      int rc = 0;

      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;
      }
      if (!PEM_write_bio_RSAPrivateKey(out, rsa, enc, NULL, 0, NULL, pass)) {
            rc = -1;
            syslog(LOG_ERR, "Failed to write key to file\n");
            goto out;
      }
out:
      if (out)
            BIO_free_all(out);
      return rc;
}

/**
 * read_key
 * @rsa: RSA key to allocate
 * @blob: Key module data to use in finding the key
 */
static int read_key(RSA **rsa, unsigned char *blob)
{
      struct pki_openssl *pki_data = NULL;
      char *read_key_sig = NULL;
      BIO *in = NULL;
      int rc;

      CRYPTO_malloc_init();
      ERR_load_crypto_strings();
      OpenSSL_add_all_algorithms();
      ENGINE_load_builtin_engines();
      pki_data = malloc(sizeof(struct pki_openssl));
      if (!pki_data) {
            syslog(LOG_ERR, "Out of memory\n");
            rc = -ENOMEM;
            goto out;
      }
      ecryptfs_openssl_deserialize(blob, pki_data);
      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, pki_data->path) <= 0) {
            syslog(LOG_ERR, "Unable to read filename [%s]\n",
                   pki_data->path);
            rc = -EIO;
            goto out;
      }
      if ((*rsa = PEM_read_bio_RSAPrivateKey(in, NULL, NULL,
                                     pki_data->password )) == NULL) {
            syslog(LOG_ERR, "Unable to read private key from file [%s]\n",
                   pki_data->password);
            rc = -EIO;
            goto out;
      }
      read_key_sig = malloc(ECRYPTFS_SIG_SIZE_HEX);
      if (!read_key_sig) {
            syslog(LOG_ERR, "Out of memory\n");
            rc = -ENOMEM;
            goto out;
      }
      rc = generate_signature(*rsa, read_key_sig);
      if (strcmp(pki_data->signature, read_key_sig)) {
            syslog(LOG_ERR, "The loaded key has incorrect signature\n");
            rc = -EINVAL;
      }
out:
      free(read_key_sig);
      free(pki_data);
      BIO_free_all(in);
      EVP_cleanup();
      CRYPTO_cleanup_all_ex_data();
      ERR_remove_state(0);
      ERR_free_strings();
      return rc;
}

/**
 * ecryptfs_openssl_get_key_metadata
 * @sig: The signature for the key
 * @length: The length of the key
 * @blob: The arbitrary data block specific to this key module
 *
 * The get_key_metadata() function has the responsibility of taking
 * the arbitrary data blob specific to the key module, converting it
 * into an interpretable internal form, calculating key attributes
 * from that information, and then setting the @sig and @length to
 * reflect the key attributes.
 */
static int ecryptfs_openssl_get_key_metadata(char *sig, int *length,
                                   unsigned char *blob)
{
      struct pki_openssl *pki_data = NULL;
      BIO *in = NULL;
      RSA *rsa = NULL;
      int rc;

      CRYPTO_malloc_init();
      ERR_load_crypto_strings();
      OpenSSL_add_all_algorithms();
      ENGINE_load_builtin_engines();
      pki_data = malloc(sizeof(pki_data));
      if (!pki_data) {
            syslog(LOG_ERR, "Out of memory\n");
            rc = -ENOMEM;
            goto out;
      }
      ecryptfs_openssl_deserialize(blob, pki_data);
      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, pki_data->path) <= 0) {
            syslog(LOG_ERR, "Unable to read filename [%s]\n",
                   pki_data->path);
            rc = -EIO;
            goto out;
      }
      if ((rsa = PEM_read_bio_RSAPrivateKey(in, NULL, NULL,
                                    pki_data->password)) == NULL) {
            syslog(LOG_ERR, "Unable to read private key from file\n");
            rc = -EIO;
            goto out;
      }
      *length = RSA_size(rsa);
      rc = generate_signature(rsa, pki_data->signature);
      memcpy(sig, pki_data->signature, ECRYPTFS_SIG_SIZE_HEX + 1);
out:
      free(pki_data);
      RSA_free(rsa);
      BIO_free_all(in);
      EVP_cleanup();
      CRYPTO_cleanup_all_ex_data();
      ERR_remove_state(0);
      ERR_free_strings();
      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(char *filename)
{
      RSA *rsa;
      BIGNUM *e;
      int rc = 0;

      rsa = RSA_new();
      if (!rsa) {
            rc = -ENOMEM;
            goto out;
      }
      e = BN_new();
      if (!rsa) {
            rc = -ENOMEM;
            goto out;
      }
      /* Set e to 65537 */
      if (BN_set_bit(e, 0) == 0 || BN_set_bit(e, 16) == 0) {
            rc = -EINVAL;
            goto out;
      }
      rsa = RSA_generate_key(1024, 65537, NULL, NULL);
      if (write_key_to_file(rsa, filename, NULL))
            rc = -EIO;
out:
      BN_free(e);
      RSA_free(rsa);
      if (rc)
            syslog(LOG_ERR, "Failed to write key file rc = [%x]\n", rc);
      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, int size, char *from,
                            unsigned char *blob)
{
      RSA *rsa = NULL;
      int rc;

      rc = read_key(&rsa, blob);
      if (rc) {
            rc = -(int)ERR_get_error();
            syslog(LOG_ERR, "Error attempting to read RSA key from file;"
                   " rc = [%d]\n", rc);
            goto out;
      }
      rc = RSA_public_encrypt(size, from, to, rsa,
                        RSA_PKCS1_OAEP_PADDING);
      if (rc == -1) {
            rc = -(int)ERR_get_error();
            syslog(LOG_ERR, "Error attempting to perform RSA public key "
                   "encryption; rc = [%d]\n", rc);
      } else {
            rc = 0;
      }
out:
      RSA_free(rsa);
      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 *decrypted_key_size,
                            char *from, unsigned char *blob)
{
      RSA *rsa = NULL;
      int rc;

      rc = read_key(&rsa, blob);
      if (rc) {
            rc = -(int)ERR_get_error();
            syslog(LOG_ERR, "Error attempting to read RSA key from file;"
                   " rc = [%d]\n", rc);
            goto out;
      }
      rc = RSA_private_decrypt(RSA_size(rsa), from, to,
                         rsa, RSA_PKCS1_OAEP_PADDING);
      if (rc == -1) {
            rc = -(int)ERR_get_error();
            syslog(LOG_ERR, "Error attempting to perform RSA public key "
                   "decryption; rc = [%d]\n", rc);
      } else {
            *decrypted_key_size = rc;
            rc = 0;
      }
out:
      RSA_free(rsa);
      return 0;
}

/**
 * ecryptfs_openssl_deserialize_length
 * @pair:
 *
 * Returns the amount of space necessary to store the arbitrary data
 * blob specific to this key module, given the name/value pairs in 
 * @pair_list.
 */
static int
ecryptfs_openssl_deserialize_length(struct ecryptfs_name_val_pair *pair_list)
{
      size_t length;
      char *password;
      char *path;

      while (pair_list) {
            if (!pair_list->name)
                  ;
            else if (!strcmp(pair_list->name, "passphrase"))
                  password = pair_list->value;
            else if (!strcmp(pair_list->name, "path"))
                  path = pair_list->value;
            pair_list = pair_list->next;
      }
      if (path) 
            length = (strlen(path) + 3);
      else
            return -1;
      if (password)
            length += (strlen(password) + 3);
      else
            return -1;
      length += (2 + (ECRYPTFS_SIG_SIZE_HEX + 1));
      return length;
}

/**
 * Key modules may have parameters that help evaluate the decision
 * graph. The pki_nvp_map[] array provides a list of such parameters
 * that may be filled in by something managing this key module.
 */
struct pki_nvp_map_elem {
      char *name;
      uint32_t flags;
};

static struct pki_nvp_map_elem pki_nvp_map[] = {
      {"path", ECRYPTFS_ECHO | ECRYPTFS_DEFAULT_VALUE_SET},
      {"passphrase", ECRYPTFS_MLOCK},
      {NULL, 0}
};

/**
 * ecryptfs_openssl_initialize_key_module_state
 * @blob: The key module-specific state blob
 * @pair: A linked list of name/value pairs containing parameters that
 *        are used to generate the state blob (TODO: convert the
 *        name/value pair list into a struct pki_openssl sooner)
 *
 * Transform the name/value pair list into an arbitrary blob of data
 * managed by the key module. This data is usually what is written to
 * the authentication key payload in the user session keyring. It
 * should be persistent state information that this key module uses to
 * figure out what it should do when it receives an encrypt or decrypt
 * request during a live filesystem operation.
 *
 * If @data is NULL, return the required amount of space that needs to
 * be allocated for @data. Otherwise, return zero for success,
 * non-zero for error.
 */
static int ecryptfs_openssl_initialize_key_module_state(
      unsigned char *blob, struct ecryptfs_name_val_pair *pair)
{
      size_t password_length;
      size_t path_length;
      char *password;
      char *path;
      size_t i = 0;

      if (blob == NULL)
            return ecryptfs_openssl_deserialize_length(pair);
      while (pair) {
            if (!pair->name)
                  ;
            else if (!strcmp(pair->name, "passphrase"))
                  password = pair->value;
            else if (!strcmp(pair->name, "path"))
                  path = pair->value;
            pair = pair->next;
      }
      if (path) {
            path_length = strlen(path) + 1;
            blob[i++] = path_length % 256;
            blob[i++] = path_length >> 8;
            memcpy(&blob[i], path, path_length);
            i += path_length;
      } else {
            return -1;
      }
      if (password) {
            password_length = strlen(password) + 1;
            blob[i++] = password_length % 256;
            blob[i++] = password_length >> 8;
            memcpy(&blob[i], password, password_length);
            i += password_length;
      } else {
            return -1;
      }
      return 0;
}

/**
 * ssl_sig
 * @pki: Key module handle
 * @head: List of mount parameters
 *
 * Add the ecryptfs_sig= mount parameter to the linked list of mount
 * parameters that is generated as the decision graph for this key
 * module is traversed.
 */
static int ssl_sig(struct ecryptfs_pki_elem *pki, struct val_node **head)
{
      struct ecryptfs_name_val_pair *openssl_nvp;
      char *sig;
      char *param;
      int rc;

      pki->nvp_head.next = malloc(sizeof(struct ecryptfs_name_val_pair));
      if (!pki->nvp_head.next) {
            rc = -ENOMEM;
            goto out;
      }
      openssl_nvp = pki->nvp_head.next;
      openssl_nvp->name = "passphrase";
      stack_pop_val(head, (void *)&(openssl_nvp->value));
      openssl_nvp->next = malloc(sizeof(struct ecryptfs_name_val_pair));
      if (!openssl_nvp->next) {
            rc = -ENOMEM;
            goto out;
      }
      openssl_nvp = openssl_nvp->next;
      openssl_nvp->name = "path";
      stack_pop_val(head, (void *)&(openssl_nvp->value));
      openssl_nvp->next = NULL;
      sig = malloc(ECRYPTFS_SIG_SIZE_HEX + 1);
      if (!sig) {
            rc = -ENOMEM;
            goto out;
      }
      rc = ecryptfs_add_key_module_key_to_keyring(sig, pki);
      if (rc < 0)
            goto out;
      else
            rc = 0;
      asprintf(&param, "ecryptfs_sig=%s", sig);
      free(sig);
      stack_push(head, param);
out:
      if (rc)
            return MOUNT_ERROR;
      return DEFAULT_TOK;
}

static int tf_ssl_file(struct ecryptfs_ctx *ctx, struct param_node *node,
                   struct val_node **head, void **foo)
{
      stack_push(head, node->val);
      node->val = NULL;
      return DEFAULT_TOK;
}

static int tf_ssl_passwd(struct ecryptfs_ctx *ctx, struct param_node *node,
                   struct val_node **head, void **foo)
{
      stack_push(head, node->val);
      node->val = NULL;
      return ssl_sig((struct ecryptfs_pki_elem *)*foo, head);
}

static int tf_ssl_passfile(struct ecryptfs_ctx *ctx, struct param_node *node,
                     struct val_node **head, void **foo)
{
      int rc = 0;
      char *tmp_val = NULL;
      int fd;
      struct ecryptfs_name_val_pair *file_head = NULL;
      struct ecryptfs_name_val_pair *walker = NULL;

      file_head = malloc(sizeof(struct ecryptfs_name_val_pair));
      if (!file_head) {
            rc = -ENOMEM;
            goto out;
      }
      memset(file_head, 0, sizeof(struct ecryptfs_name_val_pair));
      if (strcmp(node->mnt_opt_names[0], "passfile") == 0)
            fd = open(node->val, O_RDONLY);
      else if (strcmp(node->mnt_opt_names[0], "passfd") == 0)
            fd = strtol(node->val, NULL, 0);
      else {
            rc = MOUNT_ERROR;
            goto out;
      }
      rc = parse_options_file(fd, file_head);
      if (rc) {
            rc = MOUNT_ERROR;
            goto out;
      }
      close(fd);
      walker = file_head->next;
      while (walker) {
            if (strcmp(walker->name, "passwd") == 0) {
                  asprintf(&tmp_val, "%s", walker->value);
                  stack_push(head, tmp_val);
                  break;
            }
            walker = walker->next;
      }
      if (!walker) {
            rc = MOUNT_ERROR;
            goto out;
      }
      free_name_val_pairs(file_head);
      file_head = NULL;
      walker = NULL;
      rc = ssl_sig((struct ecryptfs_pki_elem *)*foo, head);
out:
      free(node->val);
      node->val = NULL;
      return rc;
}

#define OPENSSL_TOK 0
#define SSL_FILE_TOK 1
#define SSL_PASSWD_TOK 2
#define SSL_PASS_FILE_TOK 3
#define SSL_PASS_ENV_TOK 4
#define SSL_PASS_FD_TOK 5
#define SSL_PASS_STDIN_TOK 6
#define SSL_DEFAULT_PASS_TOK 7
static struct param_node ssl_param_nodes[] = {
      {.num_mnt_opt_names = 1,
       .mnt_opt_names = {"keyformat"},
       .prompt = "Key format",
       .val_type = VAL_STR,
       .val = NULL,
       .display_opts = NULL,
       .default_val = "keyfile",
       .flags = NO_VALUE,
       .num_transitions = 1,
       .tl = {{.val = "default",
             .pretty_val = "OpenSSL Key File",
             .next_token = &ssl_param_nodes[SSL_FILE_TOK],
             .trans_func = NULL}}},

      {.num_mnt_opt_names = 1,
       .mnt_opt_names = {"keyfile"},
       .prompt = "SSL key file",
       .val_type = VAL_STR,
       .val = NULL,
       .display_opts = NULL,
       .default_val = NULL,
       .suggested_val = NULL,
       .flags = ECHO_INPUT,
       .num_transitions = 6,
       .tl = {{.val = "passwd",
             .pretty_val = "",
             .next_token = &ssl_param_nodes[SSL_PASSWD_TOK],
             .trans_func = tf_ssl_file},
            {.val = "passfile",
             .pretty_val = "Passphrase File",
             .next_token = &ssl_param_nodes[SSL_PASS_FILE_TOK],
             .trans_func = tf_ssl_file},
            {.val = "passenv",
             .pretty_val = "Passphrase ENV",
             .next_token = &ssl_param_nodes[SSL_PASS_ENV_TOK],
             .trans_func = tf_ssl_file},
            {.val = "passfd",
             .pretty_val = "Passphrase File Descriptor",
             .next_token = &ssl_param_nodes[SSL_PASS_FD_TOK],
             .trans_func = tf_ssl_file},
            {.val = "passstdin",
             .pretty_val = "Passphrase STDIN",
             .next_token = &ssl_param_nodes[SSL_PASS_STDIN_TOK],
             .trans_func = tf_ssl_file},
            {.val = "default",
             .pretty_val = "Passphrase",
             .next_token = &ssl_param_nodes[SSL_DEFAULT_PASS_TOK],
             .trans_func = tf_ssl_file}}},

      {.num_mnt_opt_names = 1,
       .mnt_opt_names = {"passwd"},
       .prompt = "Passphrase",
       .val_type = VAL_STR,
       .val = NULL,
       .display_opts = NULL,
       .default_val = NULL,
       .flags = MASK_OUTPUT,
       .num_transitions = 1,
       .tl = {{.val = NULL,
             .pretty_val = NULL,
             .next_token = NULL,
             .trans_func = tf_ssl_passwd}}},

      {.num_mnt_opt_names = 1,
       .mnt_opt_names = {"passfile"},
       .prompt = "Passphrase",
       .val_type = VAL_STR,
       .val = NULL,
       .display_opts = NULL,
       .default_val = NULL,
       .flags = MASK_OUTPUT,
       .num_transitions = 1,
       .tl = {{.val = NULL,
             .pretty_val = NULL,
             .next_token = NULL,
             .trans_func = tf_ssl_passfile}}},

      {.num_mnt_opt_names = 1,
       .mnt_opt_names = {"passenv"},
       .prompt = "Passphrase",
       .val_type = VAL_STR,
       .val = NULL,
       .display_opts = NULL,
       .default_val = NULL,
       .flags = MASK_OUTPUT,
       .num_transitions = 1,
       .tl = {{.val = NULL,
             .pretty_val = NULL,
             .next_token = NULL,
             .trans_func = tf_ssl_passwd}}},

      {.num_mnt_opt_names = 1,
       .mnt_opt_names = {"passfd"},
       .prompt = "Passphrase",
       .val_type = VAL_STR,
       .val = NULL,
       .display_opts = NULL,
       .default_val = NULL,
       .flags = MASK_OUTPUT,
       .num_transitions = 1,
       .tl = {{.val = NULL,
             .pretty_val = NULL,
             .next_token = NULL,
             .trans_func = tf_ssl_passfile}}},

      {.num_mnt_opt_names = 1,
       .mnt_opt_names = {"passstdin"},
       .prompt = "Passphrase",
       .val_type = VAL_STR,
       .val = NULL,
       .display_opts = NULL,
       .default_val = NULL,
       .flags = VERIFY_VALUE | STDIN_REQUIRED,
       .num_transitions = 1,
       .tl = {{.val = NULL,
             .pretty_val = NULL,
             .next_token = NULL,
             .trans_func = tf_ssl_passwd}}},

      {.num_mnt_opt_names = 1,
       .mnt_opt_names = {"defaultpass"},
       .prompt = "Passphrase",
       .val_type = VAL_STR,
       .val = NULL,
       .display_opts = NULL,
       .default_val = NULL,
       .flags = STDIN_REQUIRED,
       .num_transitions = 1,
       .tl = {{.val = NULL,
             .pretty_val = NULL,
             .next_token = NULL,
             .trans_func = tf_ssl_passwd}}},
};

/**
 * generate_name_val_list
 * @head: Head of list onto which to append name/value pairs for
 *        parameters for this key module
 *
 * For parameters that the module requires, this function generates a
 * list of name/value pair structs and assigns the names. This
 * constitutes a set of names that require values in order to progress
 * through the decision subgraph.
 */
static int generate_name_val_list(struct ecryptfs_name_val_pair *head)
{
      struct stat buf;
      int i = 0;
      uid_t id = getuid();
      struct passwd *pw = getpwuid(id);
      int rc = 0;

      while (pki_nvp_map[i].name) {
            head->next = malloc(sizeof(struct ecryptfs_name_val_pair));
            if (!head->next) {
                  rc = -ENOMEM;
                  goto out;
            }
            head = head->next;
            head->name = pki_nvp_map[i].name;
            head->flags = pki_nvp_map[i].flags;
            if (!strcmp(head->name, "path")) {
                  asprintf(&head->value,
                         "%s/.ecryptfs/pki/openssl/key.pem",
                         pw->pw_dir);
                  if (stat(head->value, &buf))
                        head->flags &= ~ECRYPTFS_DEFAULT_VALUE_SET;
                  asprintf(&ssl_param_nodes[SSL_FILE_TOK].suggested_val,
                         "%s/.ecryptfs/pki/openssl/key.pem",
                         pw->pw_dir);
            }
            i++;
      }
      head->next = NULL;
out:
      return rc;
}

/**
 * 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: Arbitary 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 *node,
                      struct val_node **head, void **foo)
{
      int rc;

      rc = ecryptfs_find_pki(ctx, node->val,
                         (struct ecryptfs_pki_elem **)foo);
      return rc;
}

struct transition_node openssl_transition = {
      .val = "openssl",
      .pretty_val = "OpenSSL module",
      .next_token = &(ssl_param_nodes[0]),
      .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;
}

int destruct_pki(void)
{
      if (ssl_param_nodes[SSL_FILE_TOK].suggested_val)
            free(ssl_param_nodes[SSL_FILE_TOK].suggested_val);
}

/**
 * init_pki
 * @pki_name: Set to the name of this key module
 * @pki: Key module handle
 *
 * This function is the first thing called by libecryptfs when
 * registering a new pluggable key module.
 */
int init_pki(char **pki_name, struct ecryptfs_pki_elem *pki)
{
      struct ecryptfs_pki_ops openssl_ops = {
            &ecryptfs_openssl_get_key_metadata,
            &ecryptfs_openssl_generate_key,
            &ecryptfs_openssl_encrypt,
            &ecryptfs_openssl_decrypt,
            &ecryptfs_openssl_initialize_key_module_state,
            &ecryptfs_openssl_get_param_subgraph_trans_node
      };
      int rc;

      rc = generate_name_val_list(&pki->nvp_head);
      if (rc) {
            syslog(LOG_ERR, "Error attempting to generate name/val list; "
                   "rc = [%d]\n", rc);
            goto out;
      }
      if (asprintf(pki_name, "openssl") == -1) {
            rc = -ENOMEM;
            ecryptfs_syslog(LOG_ERR, "Out of memory\n");
            goto out;
      }
      memcpy(&pki->ops, &openssl_ops, sizeof(struct ecryptfs_pki_ops));
out:
      return rc;
}

/**
 * Builtin handle
 */
int openssl_init_pki(char **pki_name, struct ecryptfs_pki_elem *pki)
{
      return init_pki(pki_name, pki);
}

Generated by  Doxygen 1.6.0   Back to index