// Copyright (c) 2014 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.

#include "cryptohome/boot_lockbox.h"

#include <string>

#include <base/stl_util.h>
#include <openssl/objects.h>
#include <openssl/rsa.h>

#include "cryptohome/crypto.h"
#include "cryptohome/cryptolib.h"
#include "cryptohome/platform.h"
#include "cryptohome/tpm.h"

namespace {

// The DER encoding of SHA-256 DigestInfo as defined in PKCS #1.
const unsigned char kSha256DigestInfo[] = {
    0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03,
    0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20
};

const int kPCRIndex = 15;

const unsigned char kPCRValue[20] = {0};

// This is an arbitrary value, our only goal is for the PCR to be non-zero.
const char kPCRExtension[] = "CROS_PCR15_845A4A757B94";

const char kKeyFilePath[] = "/var/lib/boot-lockbox/key";

// A helper to safely concatenate SecureBlobs.
chromeos::SecureBlob SecureCat(const chromeos::SecureBlob& blob1,
                               const chromeos::SecureBlob& blob2) {
  chromeos::SecureBlob result(blob1.size() + blob2.size());
  unsigned char* buffer = vector_as_array(&result);
  memcpy(buffer, blob1.const_data(), blob1.size());
  memcpy(buffer + blob1.size(), blob2.const_data(), blob2.size());
  return chromeos::SecureBlob(result.begin(), result.end());
}

chromeos::SecureBlob ConvertStringToBlob(const std::string& s) {
  return chromeos::SecureBlob(s.data(), s.length());
}

std::string ConvertBlobToString(const chromeos::Blob& blob) {
  return std::string(reinterpret_cast<const char*>(vector_as_array(&blob)),
                     blob.size());
}

// So we can use scoped_ptr with openssl types.
struct RSADeleter {
  void operator()(void* ptr) const {
    if (ptr)
      RSA_free(reinterpret_cast<RSA*>(ptr));
  }
};

}  // namespace

namespace cryptohome {

BootLockbox::BootLockbox(Tpm* tpm, Platform* platform, Crypto* crypto)
    : tpm_(tpm), platform_(platform), crypto_(crypto) {
}

BootLockbox::~BootLockbox() {}

bool BootLockbox::Sign(const chromeos::SecureBlob& data,
                       chromeos::SecureBlob* signature) {
  CHECK(signature);
  chromeos::SecureBlob key_blob;
  if (!GetKeyBlob(&key_blob)) {
    return false;
  }
  chromeos::SecureBlob der_header(kSha256DigestInfo,
                                  arraysize(kSha256DigestInfo));
  chromeos::SecureBlob der_encoded_input = SecureCat(der_header,
                                           CryptoLib::Sha256(data));
  return tpm_->Sign(key_blob, der_encoded_input, signature);
}

bool BootLockbox::Verify(const chromeos::SecureBlob& data,
                         const chromeos::SecureBlob& signature) {
  chromeos::SecureBlob public_key;
  if (!GetPublicKey(&public_key)) {
    return false;
  }
  if (!VerifySignature(public_key, data, signature)) {
    return false;
  }
  chromeos::SecureBlob key_blob;
  if (!GetKeyBlob(&key_blob)) {
    return false;
  }
  chromeos::SecureBlob pcr_value(kPCRValue, arraysize(kPCRValue));
  if (!tpm_->VerifyPCRBoundKey(kPCRIndex, pcr_value, key_blob)) {
    return false;
  }
  return true;
}

bool BootLockbox::FinalizeBoot() {
  chromeos::SecureBlob actual_pcr_value;
  if (tpm_->ReadPCR(kPCRIndex, &actual_pcr_value)) {
    if (actual_pcr_value.size() == arraysize(kPCRValue) &&
        memcmp(actual_pcr_value.data(), kPCRValue, arraysize(kPCRValue))) {
      // The PCR is already not at the initial value, no need to extend again.
      return true;
    }
  }
  return tpm_->ExtendPCR(kPCRIndex,
                         chromeos::SecureBlob(kPCRExtension,
                                              arraysize(kPCRExtension)));
}

bool BootLockbox::GetKeyBlob(chromeos::SecureBlob* key_blob) {
  if (!key_.has_key_blob() && !LoadKey(&key_) && !CreateKey(&key_)) {
    return false;
  }
  CHECK(key_.has_key_blob());
  if (key_blob) {
    chromeos::SecureBlob tmp = ConvertStringToBlob(key_.key_blob());
    key_blob->swap(tmp);
  }
  return true;
}

bool BootLockbox::GetPublicKey(chromeos::SecureBlob* public_key) {
  if (!key_.has_public_key_der() && !LoadKey(&key_)) {
    return false;
  }
  CHECK(key_.has_public_key_der());
  if (public_key) {
    chromeos::SecureBlob tmp = ConvertStringToBlob(key_.public_key_der());
    public_key->swap(tmp);
  }
  return true;
}

bool BootLockbox::LoadKey(BootLockboxKey* key) {
  std::string file_contents;
  if (!platform_->ReadFileToString(kKeyFilePath, &file_contents)) {
    return false;
  }
  chromeos::SecureBlob protobuf;
  if (!crypto_->DecryptWithTpm(file_contents, &protobuf)) {
    LOG(WARNING) << "Failed to decrypt boot-lockbox key.";
    return false;
  }
  if (!key->ParseFromArray(protobuf.const_data(), protobuf.size())) {
    LOG(ERROR) << "Invalid boot-lockbox key.";
    return false;
  }
  return true;
}

bool BootLockbox::SaveKey(const BootLockboxKey& key) {
  chromeos::SecureBlob protobuf(key.ByteSize());
  if (!key.SerializeToArray(protobuf.data(), protobuf.size())) {
    LOG(ERROR) << "Failed to serialize boot-lockbox key.";
    return false;
  }
  std::string encrypted_protobuf;
  if (!crypto_->EncryptWithTpm(protobuf, &encrypted_protobuf)) {
    LOG(ERROR) << "Failed to encrypt boot-lockbox key.";
    return false;
  }
  if (!platform_->WriteStringToFile(kKeyFilePath, encrypted_protobuf)) {
    LOG(ERROR) << "Failed to write boot-lockbox key.";
    return false;
  }
  return true;
}

bool BootLockbox::CreateKey(BootLockboxKey* key) {
  LOG(INFO) <<  "Creating new boot-lockbox key.";
  chromeos::SecureBlob key_blob;
  chromeos::SecureBlob public_key;
  chromeos::SecureBlob pcr_value(kPCRValue, arraysize(kPCRValue));
  if (!tpm_->CreatePCRBoundKey(kPCRIndex, pcr_value, &key_blob, &public_key)) {
    LOG(ERROR) << "Failed to create boot-lockbox key.";
    return false;
  }
  key->set_key_blob(ConvertBlobToString(key_blob));
  key->set_public_key_der(ConvertBlobToString(public_key));
  return SaveKey(*key);
}

bool BootLockbox::VerifySignature(const chromeos::SecureBlob& public_key,
                                  const chromeos::SecureBlob& signed_data,
                                  const chromeos::SecureBlob& signature) {
  const unsigned char* asn1_ptr = &public_key.front();
  scoped_ptr<RSA, RSADeleter> rsa(
      d2i_RSAPublicKey(NULL, &asn1_ptr, public_key.size()));
  if (!rsa.get()) {
    LOG(ERROR) << "Failed to decode public key.";
    return false;
  }
  chromeos::SecureBlob digest = CryptoLib::Sha256(signed_data);
  if (!RSA_verify(NID_sha256, &digest.front(), digest.size(),
                  const_cast<unsigned char*>(&signature.front()),
                  signature.size(), rsa.get())) {
    LOG(ERROR) << "Failed to verify signature.";
    return false;
  }
  return true;
}

}  // namespace cryptohome
