// Copyright (c) 2010 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 "login_manager/owner_key.h"

#include <base/crypto/rsa_private_key.h>
#include <base/file_path.h>
#include <base/file_util.h>
#include <base/logging.h>
#include <base/scoped_ptr.h>

#include "login_manager/child_job.h"
#include "login_manager/nss_util.h"
#include "login_manager/system_utils.h"

namespace login_manager {

// Note: this structure is an ASN.1 which encodes the algorithm used
// with its parameters. This is defined in PKCS #1 v2.1 (RFC 3447).
// It is encoding: { OID sha1WithRSAEncryption      PARAMETERS NULL }
// static
const uint8 OwnerKey::kAlgorithm[15] = {
  0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
  0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00
};

OwnerKey::OwnerKey(const FilePath& key_file)
    : key_file_(key_file),
      have_checked_disk_(false),
      utils_(new SystemUtils) {
}

OwnerKey::~OwnerKey() {}

bool OwnerKey::HaveCheckedDisk() { return have_checked_disk_; }

bool OwnerKey::IsPopulated() { return !key_.empty(); }

bool OwnerKey::PopulateFromDiskIfPossible() {
  have_checked_disk_ = true;
  if (!file_util::PathExists(key_file_)) {
    LOG(INFO) << "No owner key on disk.";
    return true;
  }

  int32 safe_file_size = 0;
  if (!utils_->EnsureAndReturnSafeFileSize(key_file_, &safe_file_size)) {
    LOG(ERROR) << key_file_.value() << " is too large!";
    return false;
  }

  key_.resize(safe_file_size);
  int data_read = file_util::ReadFile(key_file_,
                                      reinterpret_cast<char*>(&key_[0]),
                                      safe_file_size);
  if (data_read != safe_file_size) {
    PLOG(ERROR) << key_file_.value() << " could not be read in its entirety!";
    key_.resize(0);
    return false;
  }
  return true;
}

bool OwnerKey::PopulateFromBuffer(const std::vector<uint8>& public_key_der) {
  if (!HaveCheckedDisk()) {
    LOG(WARNING) << "Haven't checked disk for owner key yet!";
    return false;
  }
  // Only get here if we've checked disk already.
  if (IsPopulated()) {
    LOG(ERROR) << "Already have an owner key!";
    return false;
  }
  // Only get here if we've checked disk AND we didn't load a key.
  key_ = public_key_der;
  return true;
}

bool OwnerKey::PopulateFromKeypair(base::RSAPrivateKey* pair) {
  std::vector<uint8> public_key_der;
  if (pair && pair->ExportPublicKey(&public_key_der))
    return PopulateFromBuffer(public_key_der);
  LOG(ERROR) << "Failed to export public key from key pair";
  return false;
}

bool OwnerKey::Persist() {
  // It is a programming error to call this before checking for the key on disk.
  CHECK(have_checked_disk_) << "Haven't checked disk for owner key yet!";
  if (file_util::PathExists(key_file_)) {
    LOG(ERROR) << "Tried to overwrite owner key!";
    return false;
  }

  if (!utils_->AtomicFileWrite(key_file_,
                               reinterpret_cast<char*>(&key_[0]),
                               key_.size())) {
    PLOG(ERROR) << "Could not write data to " << key_file_.value();
    return false;
  }
  DLOG(INFO) << "wrote " << key_.size() << " bytes to " << key_file_.value();
  return true;
}

bool OwnerKey::Verify(const char* data,
                      uint32 data_len,
                      const char* signature,
                      uint32 sig_len) {
  scoped_ptr<NssUtil> util(NssUtil::Create());

  if (!util->Verify(kAlgorithm,
                    sizeof(kAlgorithm),
                    reinterpret_cast<const uint8*>(signature),
                    sig_len,
                    reinterpret_cast<const uint8*>(data),
                    data_len,
                    &key_[0],
                    key_.size())) {
    LOG(ERROR) << "Signature verification of " << data << " failed";
    return false;
  }
  return true;
}

bool OwnerKey::Sign(const char* data,
                    uint32 data_len,
                    std::vector<uint8>* OUT_signature) {
  scoped_ptr<NssUtil> util(NssUtil::Create());
  scoped_ptr<base::RSAPrivateKey> private_key(util->GetPrivateKey(key_));
  if (!private_key.get())
    return false;
  if (!util->Sign(reinterpret_cast<const uint8*>(data),
                  data_len,
                  OUT_signature,
                  private_key.get())) {
    LOG(ERROR) << "Signing of " << data << " failed";
    return false;
  }
  return true;
}


int OwnerKey::StartGeneration(ChildJobInterface* generator) {
  int pid = fork();
  if (pid == 0) {
    generator->Run();
    exit(1);  // Run() is not supposed to return.
  }
  return pid;
}

}  // namespace login_manager
