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

// Contains the implementation of class Pkcs11Init.

#include "cryptohome/pkcs11_init.h"

#include <string.h>

#include <base/logging.h>
#include <base/strings/string_util.h>
#include <base/strings/stringprintf.h>
#include <chaps/isolate.h>
#include <chaps/token_manager_client.h>
#include <chromeos/cryptohome.h>
#include <errno.h>
#include <glib.h>

using base::FilePath;

namespace cryptohome {

// static
const char Pkcs11Init::kDefaultPin[] = "111111";
const char Pkcs11Init::kDefaultSystemLabel[] = "System TPM Token";
const char Pkcs11Init::kDefaultUserLabelPrefix[] = "User TPM Token ";

extern const char* kTpmOwnedFile;

Pkcs11Init::Pkcs11Init() : default_platform_(new Platform),
                           platform_(default_platform_.get()) {
}

Pkcs11Init::~Pkcs11Init() {
}

void Pkcs11Init::GetTpmTokenInfo(gchar **OUT_label,
                                 gchar **OUT_user_pin) {
  *OUT_label = g_strdup(reinterpret_cast<const gchar*>(kDefaultSystemLabel));
  *OUT_user_pin = g_strdup(reinterpret_cast<const gchar*>(kDefaultPin));
}

void Pkcs11Init::GetTpmTokenInfoForUser(gchar *username,
                                        gchar **OUT_label,
                                        gchar **OUT_user_pin) {
  std::string label = GetTpmTokenLabelForUser(
      reinterpret_cast<const char*>(username));
  *OUT_label = g_strdup(reinterpret_cast<const gchar*>(label.c_str()));
  *OUT_user_pin = g_strdup(reinterpret_cast<const gchar*>(kDefaultPin));
}

std::string Pkcs11Init::GetTpmTokenLabelForUser(const std::string& username) {
  // Use a truncated sanitized username in the token label so a label collision
  // is extremely unlikely.
  return std::string(kDefaultUserLabelPrefix) +
         chromeos::cryptohome::home::SanitizeUserName(username).substr(0, 16);
}

bool Pkcs11Init::GetTpmTokenSlotForPath(const base::FilePath& path,
                                        CK_SLOT_ID_PTR slot) {
  CK_RV rv;
  rv = C_Initialize(NULL);
  if (rv != CKR_OK && rv != CKR_CRYPTOKI_ALREADY_INITIALIZED) {
    LOG(WARNING) << __func__ << ": C_Initialize failed.";
    return false;
  }
  CK_ULONG num_slots = 0;
  rv = C_GetSlotList(CK_TRUE, NULL, &num_slots);
  if (rv != CKR_OK) {
    LOG(WARNING) << __func__ << ": C_GetSlotList(NULL) failed.";
    return false;
  }
  scoped_ptr<CK_SLOT_ID[]> slot_list(new CK_SLOT_ID[num_slots]);
  rv = C_GetSlotList(CK_TRUE, slot_list.get(), &num_slots);
  if (rv != CKR_OK) {
    LOG(WARNING) << __func__ << ": C_GetSlotList failed.";
    return false;
  }
  chaps::TokenManagerClient token_manager;
  for (CK_ULONG i = 0; i < num_slots; ++i) {
    FilePath slot_path;
    if (token_manager.GetTokenPath(
        chaps::IsolateCredentialManager::GetDefaultIsolateCredential(),
        slot_list[i],
        &slot_path) && (path == slot_path)) {
      *slot = slot_list[i];
      return true;
    }
  }
  LOG(WARNING) << __func__ << ": Path not found.";
  return false;
}

bool Pkcs11Init::IsUserTokenOK() {
  if (!platform_->FileExists(kTpmOwnedFile)) {
    LOG(WARNING) << "TPM is not owned, token can not be valid.";
    return false;
  }

  CK_RV rv;
  rv = C_Initialize(NULL);
  if (rv != CKR_OK && rv != CKR_CRYPTOKI_ALREADY_INITIALIZED) {
    LOG(WARNING) << __func__ << ": C_Initialize failed.";
    return false;
  }
  CK_ULONG num_slots = 0;
  rv = C_GetSlotList(CK_TRUE, NULL, &num_slots);
  if (rv != CKR_OK) {
    LOG(WARNING) << __func__ << ": C_GetSlotList(NULL) failed.";
    return false;
  }
  scoped_ptr<CK_SLOT_ID[]> slot_list(new CK_SLOT_ID[num_slots]);
  rv = C_GetSlotList(CK_TRUE, slot_list.get(), &num_slots);
  if (rv != CKR_OK) {
    LOG(WARNING) << __func__ << ": C_GetSlotList failed.";
    return false;
  }

  // Check if at least one sane user token exists.
  for (CK_ULONG i = 0; i < num_slots; ++i) {
    if (CheckTokenInSlot(slot_list[i], kDefaultUserLabelPrefix)) {
      LOG(INFO) << "User PKCS #11 token looks ok.";
      return true;
    }
  }

  LOG(WARNING) << "Cannot find sane user token.";
  return false;
}

bool Pkcs11Init::IsSystemTokenOK() {
  return CheckTokenInSlot(0, kDefaultSystemLabel);
}

bool Pkcs11Init::CheckTokenInSlot(CK_SLOT_ID slot_id,
                                  const std::string& expected_label_prefix) {
  CK_RV rv;
  CK_SESSION_HANDLE session_handle = 0;
  CK_SESSION_INFO session_info;
  CK_TOKEN_INFO token_info;

  rv = C_Initialize(NULL);
  if (rv != CKR_OK && rv != CKR_CRYPTOKI_ALREADY_INITIALIZED) {
    LOG(WARNING) << "C_Initialize failed while checking token: "
                 << std::hex << rv;
    return false;
  }

  rv = C_OpenSession(slot_id, CKF_RW_SESSION | CKF_SERIAL_SESSION,
                     NULL, NULL,
                     &session_handle);
  if (rv != CKR_OK) {
    LOG(WARNING) << "Could not open session on slot " << slot_id
                 << " while checking token." << std::hex << rv;
    C_CloseAllSessions(slot_id);
    return false;
  }

  memset(&session_info, 0, sizeof(session_info));
  rv = C_GetSessionInfo(session_handle, &session_info);
  if (rv != CKR_OK || session_info.slotID != slot_id) {
    LOG(WARNING) << "Could not get session info on " << slot_id
                 << " while checking token: " << std::hex << rv;
    C_CloseAllSessions(slot_id);
    return false;
  }

  rv = C_GetTokenInfo(slot_id, &token_info);
  if (rv != CKR_OK || !(token_info.flags & CKF_TOKEN_INITIALIZED)) {
    LOG(WARNING) << "Could not get token info on " << slot_id
                 << " while checking token: " << std::hex << rv;
    C_CloseAllSessions(slot_id);
    return false;
  }

  std::string label(reinterpret_cast<const char*>(token_info.label),
                    arraysize(token_info.label));
  if (!base::StartsWithASCII(label, expected_label_prefix, true)) {
    LOG(WARNING) << "Token Label (" << label << ") does not match expected "
                 << "label prefix (" << expected_label_prefix << ")";
    return false;
  }

  C_CloseAllSessions(slot_id);
  return true;
}

}  // namespace cryptohome
