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

ecryptfs_pki_tspi.c

/**
 * Copyright (C) 2006 International Business Machines Corp.
 * Author(s): Mike Halcrow <mhalcrow@us.ibm.com>
 *            Kent Yoder <kyoder@users.sf.net>
 *
 * 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 <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <trousers/tss.h>
#include "../include/ecryptfs.h"
#include "../include/decision_graph.h"

#undef DEBUG

#ifdef DEBUG
#define LOG()                 fprintf(stderr, "%s\n", __FUNCTION__)
#define DBGSYSLOG(x, ...)     syslog(LOG_DEBUG, x, ##__VA_ARGS__)
#define DBG_print_hex(a,b)    print_hex(a,b)

void
print_hex( BYTE *buf, uint32_t len )
{
      uint32_t i = 0, j;

      while (i < len) {
            for (j=0; (j < 15) && (i < len); j++, i++)
                  printf("%02x ", buf[i] & 0xff);
            printf("\n");
      }
}

#else
#define LOG()
#define DBGSYSLOG(x, ...)
#define DBG_print_hex(a,b)
#endif

TSS_UUID srk_uuid = TSS_UUID_SRK;

struct key_mapper {
      TSS_UUID uuid;
      TSS_HKEY hKey;
      struct key_mapper *next;
} *mapper = NULL;

struct pki_tpm {
      TSS_UUID uuid;
      char *signature;
};

inline void tpm_to_hex(char *dst, char *src, int src_size)
{
      int x;

      for (x = 0; x < src_size; x++)
            sprintf(&dst[x * 2], "%.2x", (unsigned char)src[x]);
}

static void get_pki_data(unsigned char *data, struct pki_tpm *pki_data)
{
      LOG();
      memcpy(&pki_data->uuid, data, sizeof(TSS_UUID));
      pki_data->signature = data + sizeof(TSS_UUID);
}

static int generate_signature(BYTE *n, uint32_t nbytes, char *sig)
{
      int len, i;
      char hash[SHA1_DIGEST_LENGTH];
      char *data = NULL;
      BYTE e[] = { 1, 0, 1 }; /* The e for all TPM RSA keys */
      int rc = 0;

      LOG();
      len = 10 + nbytes + sizeof(e);
      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)((nbytes * 8) >> 8);
      data[i++] = (char)(nbytes * 8);
      memcpy(&data[i], n, nbytes);
      i += nbytes;
      data[i++] = (char)((sizeof(e) * 8) >> 8);
      data[i++] = (char)(sizeof(e) * 8);
      memcpy(&data[i], e, sizeof(e));
      i += sizeof(e);
      SHA1(data, len + 3, hash);
      tpm_to_hex(sig, hash, ECRYPTFS_SIG_SIZE);
      sig[ECRYPTFS_SIG_SIZE_HEX] = '\0';
 out:
      free(data);
      return rc;
}

/* TODO: If sig == NULL, just return *length; the caller can use this
 * information to allocate memory and call again. There should also be
 * a max_length parameter. -Halcrow */
int
ecryptfs_tspi_set_key_data(unsigned char *private_key_data, char *sig,
                     int *length)
{
      struct pki_tpm pki_data;
      BYTE *n;
      uint32_t size_n;
      TSS_RESULT result;
      TSS_HCONTEXT hContext;
      TSS_HKEY hKey;
      int rc = 0;

      LOG();
      get_pki_data(private_key_data, &pki_data);

      result = Tspi_Context_Create(&hContext);
      if (result != TSS_SUCCESS) {
            syslog(LOG_ERR, "Tspi_Context_Create failed: %s",
                   Trspi_Error_String(result));
            rc = -1;
            goto out;
      }

      DBG_print_hex((BYTE *)&pki_data.uuid, sizeof(TSS_UUID));
      result = Tspi_Context_GetKeyByUUID(hContext, TSS_PS_TYPE_USER,
                                 pki_data.uuid, &hKey);
      if (result != TSS_SUCCESS) {
            syslog(LOG_ERR, "Tspi_Context_GetKeyByUUID failed: %s",
                   Trspi_Error_String(result));
            rc = -1;
            goto out;
      }

      result = Tspi_GetAttribData(hKey, TSS_TSPATTRIB_RSAKEY_INFO,
                            TSS_TSPATTRIB_KEYINFO_RSA_MODULUS,
                            &size_n, &n);
      if (result != TSS_SUCCESS) {
            syslog(LOG_ERR, "Tspi_GetAttribUint32 failed: %s",
                   Trspi_Error_String(result));
            rc = -1;
            goto out;
      }

      *length = size_n;
      rc = generate_signature(n, size_n, pki_data.signature);
      memcpy(sig, pki_data.signature, ECRYPTFS_SIG_SIZE_HEX + 1);
 out:
      return rc;
}

int ecryptfs_tspi_encrypt(int size, char *from, char *to,
                 unsigned char *private_key_data)
{
      TSS_RESULT result;
      TSS_HCONTEXT hContext;
      TSS_HKEY hKey;
      TSS_HENCDATA hEncData;
      uint32_t encdata_size;
      BYTE *encdata;
      int rc = 0;
      struct pki_tpm pki_data;

      LOG();
      get_pki_data(private_key_data, &pki_data);

      result = Tspi_Context_Create(&hContext);
      if (result != TSS_SUCCESS) {
            syslog(LOG_ERR, "Tspi_Context_Create failed: %s",
                   Trspi_Error_String(result));
            rc = -1;
            goto out;
      }

      result = Tspi_Context_CreateObject(hContext, TSS_OBJECT_TYPE_ENCDATA,
                                 TSS_ENCDATA_BIND, &hEncData);
      if (result != TSS_SUCCESS) {
            syslog(LOG_ERR, "Tspi_Context_CreateObject failed: %s",
                   Trspi_Error_String(result));
            rc = -1;
            goto out;
      }

      result = Tspi_Context_GetKeyByUUID(hContext, TSS_PS_TYPE_USER,
                                 pki_data.uuid, &hKey);
      if (result != TSS_SUCCESS) {
            syslog(LOG_ERR, "Tspi_Context_GetKeyByUUID failed: %s",
                   Trspi_Error_String(result));
            rc = -1;
            goto out;
      }

      result = Tspi_Data_Bind(hEncData, hKey, size, from);
      if (result != TSS_SUCCESS) {
            syslog(LOG_ERR, "Tspi_Data_Bind failed: %s",
                   Trspi_Error_String(result));
            rc = -1;
            goto out;
      }

      result = Tspi_GetAttribData(hEncData, TSS_TSPATTRIB_ENCDATA_BLOB,
                            TSS_TSPATTRIB_ENCDATABLOB_BLOB,
                            &encdata_size, &encdata);
      if (result != TSS_SUCCESS) {
            syslog(LOG_ERR, "Tspi_GetAttribData failed: %s",
                   Trspi_Error_String(result));
            rc = -1;
            goto out;
      }

      memcpy(to, encdata, encdata_size);
      Tspi_Context_FreeMemory(hContext, encdata);

 out:
      return rc;
}

/* currently assumes that a single block is passed in for decryption */
int ecryptfs_tspi_decrypt(char *from, char *to, size_t *decrypted_key_size,
                    unsigned char *private_key_data)
{
      TSS_RESULT result;
      static TSS_HCONTEXT hDecryptContext = 0;
      static TSS_HPOLICY hSRKPolicy = 0;
      static TSS_HKEY hDecryptKey = 0, hSRK = 0;
      static uint32_t decryptKeySize;
      static TSS_HENCDATA hEncData;
      uint32_t encdata_size;
      BYTE *encdata;
      int rc = 0;
      struct pki_tpm pki_data;
      struct key_mapper *walker, *new_mapper;

      LOG();
      get_pki_data(private_key_data, &pki_data);

      if (!hDecryptContext) {
            result = Tspi_Context_Create(&hDecryptContext);
            if (result != TSS_SUCCESS) {
                  syslog(LOG_ERR, "Tspi_Context_Create failed: %s",
                         Trspi_Error_String(result));
                  rc = -1;
                  goto out_uninit;
            }
            DBGSYSLOG("New TSP context: 0x%x", hDecryptContext);

            result = Tspi_Context_Connect(hDecryptContext, NULL);
            if (result != TSS_SUCCESS) {
                  syslog(LOG_ERR, "Tspi_Context_Connect failed: %s",
                         Trspi_Error_String(result));
                  rc = -1;
                  goto out_uninit;
            }

            result = Tspi_Context_LoadKeyByUUID(hDecryptContext,
                                        TSS_PS_TYPE_SYSTEM,
                                        srk_uuid, &hSRK);
            if (result != TSS_SUCCESS) {
                  syslog(LOG_ERR, "Tspi_Context_LoadKeyByUUID failed: %s",
                         Trspi_Error_String(result));
                  rc = -1;
                  goto out_uninit;
            }

            result = Tspi_GetPolicyObject(hSRK, TSS_POLICY_USAGE,
                                    &hSRKPolicy);
            if (result != TSS_SUCCESS) {
                  syslog(LOG_ERR, "Tspi_GetPolicyObject failed: %s",
                         Trspi_Error_String(result));
                  rc = -1;
                  goto out_uninit;
            }

            result = Tspi_Policy_SetSecret(hSRKPolicy,
                                     TSS_SECRET_MODE_POPUP, 0, NULL);
            if (result != TSS_SUCCESS) {
                  syslog(LOG_ERR, "Tspi_Policy_SetSecret failed: %s",
                         Trspi_Error_String(result));
                  rc = -1;
                  goto out_uninit;
            }

            result = Tspi_Context_CreateObject(hDecryptContext,
                                       TSS_OBJECT_TYPE_ENCDATA,
                                       TSS_ENCDATA_BIND, &hEncData);
            if (result != TSS_SUCCESS) {
                  syslog(LOG_ERR, "Tspi_Context_CreateObject failed: %s",
                         Trspi_Error_String(result));
                  rc = -1;
                  goto out_uninit;
            }
      }

      for (walker = mapper; walker; walker = walker->next) {
            if (!memcmp(&walker->uuid, &pki_data.uuid, sizeof(TSS_UUID)))
                  break;
      }

      if (!walker) {
            new_mapper = calloc(1, sizeof(struct key_mapper));
            if (!new_mapper) {
                  syslog(LOG_ERR, "malloc failed: %s", strerror(errno));
                  rc = -1;
                  goto out;
            }

            result = Tspi_Context_GetKeyByUUID(hDecryptContext,
                                       TSS_PS_TYPE_USER,
                                       pki_data.uuid,
                                       &new_mapper->hKey);
            if (result != TSS_SUCCESS) {
                  syslog(LOG_ERR, "Tspi_Context_LoadKeyByUUID failed: %s",
                         Trspi_Error_String(result));
                  rc = -1;
                  goto out;
            }

            DBGSYSLOG("New key object: 0x%x", new_mapper->hKey);

            result = Tspi_Key_LoadKey(new_mapper->hKey, hSRK);
            if (result != TSS_SUCCESS) {
                  syslog(LOG_ERR, "Tspi_Context_LoadKey failed: %s",
                         Trspi_Error_String(result));
                  rc = -1;
                  goto out;
            }

            memcpy(&new_mapper->uuid, &pki_data.uuid, sizeof(TSS_UUID));
            new_mapper->next = mapper;
            walker = mapper = new_mapper;
      }

      result = Tspi_GetAttribUint32(walker->hKey, TSS_TSPATTRIB_KEY_INFO,
                              TSS_TSPATTRIB_KEYINFO_SIZE,
                              &decryptKeySize);
      if (result != TSS_SUCCESS) {
            syslog(LOG_ERR, "Tspi_GetAttribUint32 failed: %s",
                   Trspi_Error_String(result));
            rc = -1;
            goto out;
      }

      encdata_size = decryptKeySize / 8;
      result = Tspi_SetAttribData(hEncData, TSS_TSPATTRIB_ENCDATA_BLOB,
                            TSS_TSPATTRIB_ENCDATABLOB_BLOB,
                            encdata_size, (BYTE *)from);
      if (result != TSS_SUCCESS) {
            syslog(LOG_ERR, "Tspi_SetAttribData failed: %s",
                   Trspi_Error_String(result));
            rc = -1;
            goto out;
      }

      result = Tspi_Data_Unbind(hEncData, walker->hKey, &encdata_size,
                          &encdata);
      if (result != TSS_SUCCESS) {
            syslog(LOG_ERR, "Tspi_Data_Unbind failed: %s",
                   Trspi_Error_String(result));
            rc = -1;
            goto out;
      }

      memcpy(to, encdata, encdata_size);
      Tspi_Context_FreeMemory(hDecryptContext, encdata);
      *decrypted_key_size = encdata_size;
      return 0;

 out_uninit:
      Tspi_Context_Close(hDecryptContext);
      hDecryptContext = 0;
      hSRKPolicy = 0;
      hDecryptKey = 0;
      hSRK = 0;
 out:
      return rc;
}

static int
ecryptfs_tspi_get_pki_data_length(struct ecryptfs_name_val_pair *pair)
{
      LOG();
      return sizeof(TSS_UUID) + (2 + (ECRYPTFS_SIG_SIZE_HEX + 1));
}

struct pki_nvp_map_elem {
      char *name;
      uint32_t flags;
};

static struct pki_nvp_map_elem pki_nvp_map[] = {
      { "uuid", ECRYPTFS_ECHO },
      { NULL, 0 }
};

int generate_name_val_list(struct ecryptfs_name_val_pair *head)
{
      int i = 0;
      int rc = 0;

      LOG();
      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;
            i++;
      }
      head->next = NULL;
 out:
      return rc;
}

void
string_to_uuid(char *str, TSS_UUID *uuid)
{
      BYTE tmp[sizeof(unsigned long) * 2 + 1];
      unsigned long l;
      uint32_t i;

      LOG();
      tmp[sizeof(unsigned long) * 2] = '\0';

      for (i = 0; i < (sizeof(TSS_UUID) * 2); i += sizeof(unsigned long)*2) {
            memcpy(tmp, &str[i], sizeof(unsigned long) * 2);
            l = strtoul(tmp, NULL, 16);
            l = htonl(l);
            memcpy(&((BYTE *)uuid)[i/2], &l, sizeof(unsigned long));
      }
}

/* TODO: In general, we should be passing the head of the lists
 * around; the head's only job is to provide a pointer to the first
 * real element in the list. Please update this function to reflect
 * that. -Halcrow */
int
ecryptfs_tspi_set_pki_data(struct ecryptfs_name_val_pair *pair,
                     unsigned char *data)
{
      char *uuid_str = NULL;
      TSS_UUID uuid;
      size_t i = 0;

      LOG();
      if (data == NULL)
            return ecryptfs_tspi_get_pki_data_length(pair);
      while (pair) {
            if (!pair->name)
                  ;
            else if (!strcmp(pair->name, "uuid"))
                  uuid_str = pair->value;
            pair = pair->next;
      }
      if (uuid_str) {
            string_to_uuid(uuid_str, &uuid);
            memcpy(data, &uuid, sizeof(TSS_UUID));
      } else {
            return -1;
      }
      return 0;
}

int ecryptfs_tspi_generate_key(char *filename)
{
      return -1;
}

static int
ecryptfs_tspi_get_param_subgraph_trans_node(struct transition_node **trans,
                                  uint32_t version)
{
      return -1;
}

int init_pki(char **pki_name, struct ecryptfs_pki_elem *pki)
{
      struct ecryptfs_pki_ops tspi_ops = {
            &ecryptfs_tspi_set_key_data,
            &ecryptfs_tspi_generate_key,
            &ecryptfs_tspi_encrypt,
            &ecryptfs_tspi_decrypt,
            &ecryptfs_tspi_set_pki_data,
            &ecryptfs_tspi_get_param_subgraph_trans_node
      };
      int rc;

      LOG();
      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, "tspi") == -1) {
            syslog(LOG_ERR, "Out of memory\n");
            goto out;
      }
      memcpy(&pki->ops, &tspi_ops, sizeof(struct ecryptfs_pki_ops));
 out:
      return -EINVAL;
}

Generated by  Doxygen 1.6.0   Back to index