/* Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 *
 * Host functions for keys.
 */

/* TODO: change all 'return 0', 'return 1' into meaningful return codes */

#define OPENSSL_NO_SHA
#include <openssl/engine.h>
#include <openssl/pem.h>
#include <openssl/rsa.h>
#include <openssl/x509.h>

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#include "cryptolib.h"
#include "host_common.h"
#include "host_key.h"
#include "host_misc.h"
#include "vboot_common.h"


VbPrivateKey* PrivateKeyReadPem(const char* filename, uint64_t algorithm) {

  VbPrivateKey* key;
  RSA* rsa_key;
  FILE* f;

  if (algorithm >= kNumAlgorithms) {
    VBDEBUG(("%s() called with invalid algorithm!\n", __FUNCTION__));
    return NULL;
  }

  /* Read private key */
  f = fopen(filename, "r");
  if (!f) {
    VBDEBUG(("%s(): Couldn't open key file: %s\n", __FUNCTION__, filename));
    return NULL;
  }
  rsa_key = PEM_read_RSAPrivateKey(f, NULL, NULL, NULL);
  fclose(f);
  if (!rsa_key) {
    VBDEBUG(("%s(): Couldn't read private key from file: %s\n", __FUNCTION__,
             filename));
    return NULL;
  }

  /* Store key and algorithm in our struct */
  key = (VbPrivateKey*)malloc(sizeof(VbPrivateKey));
  if (!key) {
    RSA_free(rsa_key);
    return NULL;
  }
  key->rsa_private_key = rsa_key;
  key->algorithm = algorithm;

  /* Return the key */
  return key;
}


void PrivateKeyFree(VbPrivateKey* key) {
  if (!key)
    return;
  if (key->rsa_private_key)
    RSA_free(key->rsa_private_key);
  free(key);
}


/* Write a private key to a file in .vbprivk format. */
int PrivateKeyWrite(const char* filename, const VbPrivateKey* key) {
  uint8_t *outbuf = 0;
  int buflen;
  FILE *f;

  buflen = i2d_RSAPrivateKey(key->rsa_private_key, &outbuf);
  if (buflen <= 0) {
    VbExError("Unable to write private key buffer\n");
    return 1;
  }

  f = fopen(filename, "wb");
  if (!f) {
    VbExError("Unable to open file %s\n", filename);
    free(outbuf);
    return 1;
  }

  if (1 != fwrite(&key->algorithm, sizeof(key->algorithm), 1, f)) {
    VbExError("Unable to write to file %s\n", filename);
    fclose(f);
    free(outbuf);
    unlink(filename);  /* Delete any partial file */
  }

  if (1 != fwrite(outbuf, buflen, 1, f)) {
    VbExError("Unable to write to file %s\n", filename);
    fclose(f);
    unlink(filename);  /* Delete any partial file */
    free(outbuf);
  }

  fclose(f);
  free(outbuf);
  return 0;
}

VbPrivateKey* PrivateKeyRead(const char* filename) {
  VbPrivateKey *key;
  uint64_t filelen = 0;
  uint8_t *buffer;
  const unsigned char *start;

  buffer = ReadFile(filename, &filelen);
  if (!buffer) {
    VbExError("unable to read from file %s\n", filename);
    return 0;
  }

  key = (VbPrivateKey*)malloc(sizeof(VbPrivateKey));
  if (!key) {
    VbExError("Unable to allocate VbPrivateKey\n");
    free(buffer);
    return 0;
  }

  key->algorithm = *(typeof(key->algorithm) *)buffer;
  start = buffer + sizeof(key->algorithm);

  key->rsa_private_key = d2i_RSAPrivateKey(0, &start,
                                           filelen - sizeof(key->algorithm));

  if (!key->rsa_private_key) {
    VbExError("Unable to parse RSA private key\n");
    free(buffer);
    free(key);
    return 0;
  }

  free(buffer);
  return key;
}


/* Allocate a new public key with space for a [key_size] byte key. */
VbPublicKey* PublicKeyAlloc(uint64_t key_size, uint64_t algorithm,
                            uint64_t version) {
  VbPublicKey* key = (VbPublicKey*)malloc(sizeof(VbPublicKey) + key_size);
  if (!key)
    return NULL;

  key->algorithm = algorithm;
  key->key_version = version;
  key->key_size = key_size;
  key->key_offset = sizeof(VbPublicKey);
  return key;
}

VbPublicKey* PublicKeyReadKeyb(const char* filename, uint64_t algorithm,
                               uint64_t version) {
  VbPublicKey* key;
  uint8_t* key_data;
  uint64_t key_size;
  uint64_t expected_key_size;

  if (algorithm >= kNumAlgorithms) {
    VBDEBUG(("PublicKeyReadKeyb() called with invalid algorithm!\n"));
    return NULL;
  }
  if (version > 0xFFFF) {
    /* Currently, TPM only supports 16-bit version */
    VBDEBUG(("PublicKeyReadKeyb() called with invalid version!\n"));
    return NULL;
  }

  key_data = ReadFile(filename, &key_size);
  if (!key_data)
    return NULL;

  if (!RSAProcessedKeySize(algorithm, &expected_key_size) ||
      expected_key_size != key_size) {
    VBDEBUG(("PublicKeyReadKeyb() wrong key size for algorithm\n"));
    free(key_data);
    return NULL;
  }

  key = PublicKeyAlloc(key_size, algorithm, version);
  if (!key) {
    free(key_data);
    return NULL;
  }
  Memcpy(GetPublicKeyData(key), key_data, key_size);

  free(key_data);
  return key;
}


VbPublicKey* PublicKeyRead(const char* filename) {
  VbPublicKey* key;
  uint64_t file_size;
  uint64_t key_size;

  key = (VbPublicKey*)ReadFile(filename, &file_size);
  if (!key)
    return NULL;

  do {
    /* Sanity-check key data */
    if (0 != VerifyPublicKeyInside(key, file_size, key)) {
      VBDEBUG(("PublicKeyRead() not a VbPublicKey\n"));
      break;
    }
    if (key->algorithm >= kNumAlgorithms) {
      VBDEBUG(("PublicKeyRead() invalid algorithm\n"));
      break;
    }
    if (key->key_version > 0xFFFF) {
      VBDEBUG(("PublicKeyRead() invalid version\n"));
      break;  /* Currently, TPM only supports 16-bit version */
    }
    if (!RSAProcessedKeySize(key->algorithm, &key_size) ||
        key_size != key->key_size) {
      VBDEBUG(("PublicKeyRead() wrong key size for algorithm\n"));
      break;
    }

    /* Success */
    return key;

  } while(0);

  /* Error */
  free(key);
  return NULL;
}

int PublicKeyWrite(const char* filename, const VbPublicKey* key) {
  VbPublicKey* kcopy;
  int rv;

  /* Copy the key, so its data is contiguous with the header */
  kcopy = PublicKeyAlloc(key->key_size, 0, 0);
  if (!kcopy)
    return 1;
  if (0 != PublicKeyCopy(kcopy, key)) {
    free(kcopy);
    return 1;
  }

  /* Write the copy, then free it */
  rv = WriteFile(filename, kcopy, kcopy->key_offset + kcopy->key_size);
  free(kcopy);
  return rv;
}
