// Copyright 2017 The Chromium 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 "chromeos/cryptohome/cryptohome_util.h"

#include <string>

#include "base/logging.h"
#include "chromeos/cryptohome/cryptohome_parameters.h"
#include "chromeos/dbus/cryptohome/key.pb.h"
#include "chromeos/dbus/cryptohome/rpc.pb.h"
#include "components/device_event_log/device_event_log.h"
#include "third_party/cros_system_api/dbus/service_constants.h"

using chromeos::ChallengeResponseKey;
using google::protobuf::RepeatedPtrField;

namespace cryptohome {

namespace {

bool IsEmpty(const base::Optional<BaseReply>& reply) {
  if (!reply.has_value()) {
    LOGIN_LOG(ERROR) << "Cryptohome call failed with empty reply.";
    return true;
  }
  return false;
}

ChallengeSignatureAlgorithm ChallengeSignatureAlgorithmToProtoEnum(
    ChallengeResponseKey::SignatureAlgorithm algorithm) {
  using Algorithm = ChallengeResponseKey::SignatureAlgorithm;
  switch (algorithm) {
    case Algorithm::kRsassaPkcs1V15Sha1:
      return CHALLENGE_RSASSA_PKCS1_V1_5_SHA1;
    case Algorithm::kRsassaPkcs1V15Sha256:
      return CHALLENGE_RSASSA_PKCS1_V1_5_SHA256;
    case Algorithm::kRsassaPkcs1V15Sha384:
      return CHALLENGE_RSASSA_PKCS1_V1_5_SHA384;
    case Algorithm::kRsassaPkcs1V15Sha512:
      return CHALLENGE_RSASSA_PKCS1_V1_5_SHA512;
  }
  NOTREACHED();
}

void ChallengeResponseKeyToPublicKeyInfo(
    const ChallengeResponseKey& challenge_response_key,
    ChallengePublicKeyInfo* public_key_info) {
  public_key_info->set_public_key_spki_der(
      challenge_response_key.public_key_spki_der());
  for (ChallengeResponseKey::SignatureAlgorithm algorithm :
       challenge_response_key.signature_algorithms()) {
    public_key_info->add_signature_algorithm(
        ChallengeSignatureAlgorithmToProtoEnum(algorithm));
  }
}

void KeyDefPrivilegesToKeyPrivileges(int key_def_privileges,
                                     KeyPrivileges* privileges) {
  privileges->set_mount(key_def_privileges & PRIV_MOUNT);
  privileges->set_add(key_def_privileges & PRIV_ADD);
  privileges->set_remove(key_def_privileges & PRIV_REMOVE);
  privileges->set_update(key_def_privileges & PRIV_MIGRATE);
  privileges->set_authorized_update(key_def_privileges &
                                    PRIV_AUTHORIZED_UPDATE);
}

// TODO(crbug.com/797848): Add tests that cover this logic.
void KeyDefSecretToKeyAuthorizationSecret(
    const KeyDefinition::AuthorizationData::Secret& key_def_secret,
    KeyAuthorizationSecret* secret) {
  secret->mutable_usage()->set_encrypt(key_def_secret.encrypt);
  secret->mutable_usage()->set_sign(key_def_secret.sign);
  secret->set_wrapped(key_def_secret.wrapped);
  if (!key_def_secret.symmetric_key.empty())
    secret->set_symmetric_key(key_def_secret.symmetric_key);

  if (!key_def_secret.public_key.empty())
    secret->set_public_key(key_def_secret.public_key);
}

// TODO(crbug.com/797848): Add tests that cover this logic.
void KeyDefProviderDataToKeyProviderDataEntry(
    const KeyDefinition::ProviderData& provider_data,
    KeyProviderData::Entry* entry) {
  entry->set_name(provider_data.name);
  if (provider_data.number)
    entry->set_number(*provider_data.number);

  if (provider_data.bytes)
    entry->set_bytes(*provider_data.bytes);
}

// TODO(crbug.com/797848): Add tests that cover this logic.
KeyAuthorizationData::KeyAuthorizationType GetKeyAuthDataType(
    KeyDefinition::AuthorizationData::Type key_def_auth_data_type) {
  switch (key_def_auth_data_type) {
    case KeyDefinition::AuthorizationData::TYPE_HMACSHA256:
      return KeyAuthorizationData::KEY_AUTHORIZATION_TYPE_HMACSHA256;
    case KeyDefinition::AuthorizationData::TYPE_AES256CBC_HMACSHA256:
      return KeyAuthorizationData::KEY_AUTHORIZATION_TYPE_AES256CBC_HMACSHA256;
  }
}

}  // namespace

MountError MountExReplyToMountError(const base::Optional<BaseReply>& reply) {
  if (IsEmpty(reply))
    return MOUNT_ERROR_FATAL;

  if (!reply->HasExtension(MountReply::reply)) {
    LOGIN_LOG(ERROR) << "MountEx failed with no MountReply extension in reply.";
    return MOUNT_ERROR_FATAL;
  }
  return CryptohomeErrorToMountError(reply->error());
}

MountError BaseReplyToMountError(const base::Optional<BaseReply>& reply) {
  if (IsEmpty(reply))
    return MOUNT_ERROR_FATAL;

  return CryptohomeErrorToMountError(reply->error());
}

MountError GetKeyDataReplyToMountError(const base::Optional<BaseReply>& reply) {
  if (IsEmpty(reply))
    return MOUNT_ERROR_FATAL;

  if (!reply->HasExtension(GetKeyDataReply::reply)) {
    LOGIN_LOG(ERROR)
        << "GetKeyDataEx failed with no GetKeyDataReply extension in reply.";
    return MOUNT_ERROR_FATAL;
  }
  return CryptohomeErrorToMountError(reply->error());
}

// TODO(crbug.com/797848): Finish testing this method.
std::vector<KeyDefinition> GetKeyDataReplyToKeyDefinitions(
    const base::Optional<BaseReply>& reply) {
  const RepeatedPtrField<KeyData>& key_data =
      reply->GetExtension(GetKeyDataReply::reply).key_data();
  std::vector<KeyDefinition> key_definitions;
  for (RepeatedPtrField<KeyData>::const_iterator it = key_data.begin();
       it != key_data.end(); ++it) {
    // Extract |type|, |label| and |revision|.
    KeyDefinition key_definition;
    CHECK(it->has_type());
    switch (it->type()) {
      case KeyData::KEY_TYPE_PASSWORD:
        key_definition.type = KeyDefinition::TYPE_PASSWORD;
        break;
      case KeyData::KEY_TYPE_CHALLENGE_RESPONSE:
        key_definition.type = KeyDefinition::TYPE_CHALLENGE_RESPONSE;
        break;
    }
    key_definition.label = it->label();
    key_definition.revision = it->revision();

    // Extract |privileges|.
    const KeyPrivileges& privileges = it->privileges();
    if (privileges.mount())
      key_definition.privileges |= PRIV_MOUNT;
    if (privileges.add())
      key_definition.privileges |= PRIV_ADD;
    if (privileges.remove())
      key_definition.privileges |= PRIV_REMOVE;
    if (privileges.update())
      key_definition.privileges |= PRIV_MIGRATE;
    if (privileges.authorized_update())
      key_definition.privileges |= PRIV_AUTHORIZED_UPDATE;

    // Extract |policy|.
    key_definition.policy.low_entropy_credential =
        it->policy().low_entropy_credential();
    key_definition.policy.auth_locked = it->policy().auth_locked();

    // Extract |authorization_data|.
    for (RepeatedPtrField<KeyAuthorizationData>::const_iterator auth_it =
             it->authorization_data().begin();
         auth_it != it->authorization_data().end(); ++auth_it) {
      key_definition.authorization_data.push_back(
          KeyDefinition::AuthorizationData());
      KeyAuthorizationDataToAuthorizationData(
          *auth_it, &key_definition.authorization_data.back());
    }

    // Extract |provider_data|.
    for (RepeatedPtrField<KeyProviderData::Entry>::const_iterator
             provider_data_it = it->provider_data().entry().begin();
         provider_data_it != it->provider_data().entry().end();
         ++provider_data_it) {
      // Extract |name|.
      key_definition.provider_data.push_back(
          KeyDefinition::ProviderData(provider_data_it->name()));
      KeyDefinition::ProviderData& provider_data =
          key_definition.provider_data.back();

      int data_items = 0;

      // Extract |number|.
      if (provider_data_it->has_number()) {
        provider_data.number.reset(new int64_t(provider_data_it->number()));
        ++data_items;
      }

      // Extract |bytes|.
      if (provider_data_it->has_bytes()) {
        provider_data.bytes.reset(new std::string(provider_data_it->bytes()));
        ++data_items;
      }

      DCHECK_EQ(1, data_items);
    }

    key_definitions.push_back(std::move(key_definition));
  }
  return key_definitions;
}

int64_t AccountDiskUsageReplyToUsageSize(
    const base::Optional<BaseReply>& reply) {
  if (IsEmpty(reply))
    return -1;

  if (reply->has_error() && reply->error() != CRYPTOHOME_ERROR_NOT_SET) {
    LOGIN_LOG(ERROR) << "GetAccountDiskUsage failed with error: "
                     << reply->error();
    return -1;
  }
  if (!reply->HasExtension(GetAccountDiskUsageReply::reply)) {
    LOGIN_LOG(ERROR) << "GetAccountDiskUsage failed with no "
                        "GetAccountDiskUsageReply extension in reply.";
    return -1;
  }
  return reply->GetExtension(GetAccountDiskUsageReply::reply).size();
}

const std::string& MountExReplyToMountHash(const BaseReply& reply) {
  return reply.GetExtension(MountReply::reply).sanitized_username();
}

AuthorizationRequest CreateAuthorizationRequest(const std::string& label,
                                                const std::string& secret) {
  cryptohome::AuthorizationRequest auth_request;
  Key* key = auth_request.mutable_key();
  if (!label.empty())
    key->mutable_data()->set_label(label);

  key->set_secret(secret);
  return auth_request;
}

// TODO(crbug.com/797848): Finish testing this method.
void KeyDefinitionToKey(const KeyDefinition& key_def, Key* key) {
  KeyData* data = key->mutable_data();
  data->set_label(key_def.label);

  switch (key_def.type) {
    case KeyDefinition::TYPE_PASSWORD:
      data->set_type(KeyData::KEY_TYPE_PASSWORD);
      key->set_secret(key_def.secret);
      break;

    case KeyDefinition::TYPE_CHALLENGE_RESPONSE:
      data->set_type(KeyData::KEY_TYPE_CHALLENGE_RESPONSE);
      for (const auto& challenge_response_key :
           key_def.challenge_response_keys) {
        ChallengeResponseKeyToPublicKeyInfo(challenge_response_key,
                                            data->add_challenge_response_key());
      }
      break;
  }

  if (key_def.revision > 0)
    data->set_revision(key_def.revision);

  if (key_def.privileges != 0) {
    KeyDefPrivilegesToKeyPrivileges(key_def.privileges,
                                    data->mutable_privileges());
  }

  for (const auto& key_def_auth_data : key_def.authorization_data) {
    KeyAuthorizationData* auth_data = data->add_authorization_data();
    auth_data->set_type(GetKeyAuthDataType(key_def_auth_data.type));
    for (const auto& key_def_secret : key_def_auth_data.secrets) {
      KeyDefSecretToKeyAuthorizationSecret(key_def_secret,
                                           auth_data->add_secrets());
    }
  }

  for (const auto& provider_data : key_def.provider_data) {
    KeyDefProviderDataToKeyProviderDataEntry(
        provider_data, data->mutable_provider_data()->add_entry());
  }
}

// TODO(crbug.com/797848): Finish testing this method.
MountError CryptohomeErrorToMountError(CryptohomeErrorCode code) {
  switch (code) {
    case CRYPTOHOME_ERROR_NOT_SET:
      return MOUNT_ERROR_NONE;
    case CRYPTOHOME_ERROR_ACCOUNT_NOT_FOUND:
      return MOUNT_ERROR_USER_DOES_NOT_EXIST;
    case CRYPTOHOME_ERROR_NOT_IMPLEMENTED:
    case CRYPTOHOME_ERROR_MOUNT_FATAL:
    case CRYPTOHOME_ERROR_KEY_QUOTA_EXCEEDED:
    case CRYPTOHOME_ERROR_BACKING_STORE_FAILURE:
      return MOUNT_ERROR_FATAL;
    case CRYPTOHOME_ERROR_AUTHORIZATION_KEY_NOT_FOUND:
    case CRYPTOHOME_ERROR_KEY_NOT_FOUND:
    case CRYPTOHOME_ERROR_MIGRATE_KEY_FAILED:
    case CRYPTOHOME_ERROR_AUTHORIZATION_KEY_FAILED:
      return MOUNT_ERROR_KEY_FAILURE;
    case CRYPTOHOME_ERROR_TPM_COMM_ERROR:
      return MOUNT_ERROR_TPM_COMM_ERROR;
    case CRYPTOHOME_ERROR_TPM_DEFEND_LOCK:
      return MOUNT_ERROR_TPM_DEFEND_LOCK;
    case CRYPTOHOME_ERROR_MOUNT_MOUNT_POINT_BUSY:
      return MOUNT_ERROR_MOUNT_POINT_BUSY;
    case CRYPTOHOME_ERROR_TPM_NEEDS_REBOOT:
      return MOUNT_ERROR_TPM_NEEDS_REBOOT;
    case CRYPTOHOME_ERROR_AUTHORIZATION_KEY_DENIED:
    case CRYPTOHOME_ERROR_KEY_LABEL_EXISTS:
    case CRYPTOHOME_ERROR_UPDATE_SIGNATURE_INVALID:
      return MOUNT_ERROR_KEY_FAILURE;
    case CRYPTOHOME_ERROR_MOUNT_OLD_ENCRYPTION:
      return MOUNT_ERROR_OLD_ENCRYPTION;
    case CRYPTOHOME_ERROR_MOUNT_PREVIOUS_MIGRATION_INCOMPLETE:
      return MOUNT_ERROR_PREVIOUS_MIGRATION_INCOMPLETE;
    case CRYPTOHOME_ERROR_REMOVE_FAILED:
      return MOUNT_ERROR_REMOVE_FAILED;
    // TODO(crbug.com/797563): Split the error space and/or handle everything.
    case CRYPTOHOME_ERROR_LOCKBOX_SIGNATURE_INVALID:
    case CRYPTOHOME_ERROR_LOCKBOX_CANNOT_SIGN:
    case CRYPTOHOME_ERROR_BOOT_ATTRIBUTE_NOT_FOUND:
    case CRYPTOHOME_ERROR_BOOT_ATTRIBUTES_CANNOT_SIGN:
    case CRYPTOHOME_ERROR_TPM_EK_NOT_AVAILABLE:
    case CRYPTOHOME_ERROR_ATTESTATION_NOT_READY:
    case CRYPTOHOME_ERROR_CANNOT_CONNECT_TO_CA:
    case CRYPTOHOME_ERROR_CA_REFUSED_ENROLLMENT:
    case CRYPTOHOME_ERROR_CA_REFUSED_CERTIFICATE:
    case CRYPTOHOME_ERROR_INTERNAL_ATTESTATION_ERROR:
    case CRYPTOHOME_ERROR_FIRMWARE_MANAGEMENT_PARAMETERS_INVALID:
    case CRYPTOHOME_ERROR_FIRMWARE_MANAGEMENT_PARAMETERS_CANNOT_STORE:
    case CRYPTOHOME_ERROR_FIRMWARE_MANAGEMENT_PARAMETERS_CANNOT_REMOVE:
      NOTREACHED();
      return MOUNT_ERROR_FATAL;
  }
}

void KeyAuthorizationDataToAuthorizationData(
    const KeyAuthorizationData& authorization_data_proto,
    KeyDefinition::AuthorizationData* authorization_data) {
  switch (authorization_data_proto.type()) {
    case KeyAuthorizationData::KEY_AUTHORIZATION_TYPE_HMACSHA256:
      authorization_data->type =
          KeyDefinition::AuthorizationData::TYPE_HMACSHA256;
      break;
    case KeyAuthorizationData::KEY_AUTHORIZATION_TYPE_AES256CBC_HMACSHA256:
      authorization_data->type =
          KeyDefinition::AuthorizationData::TYPE_AES256CBC_HMACSHA256;
      break;
  }

  for (const auto& secret : authorization_data_proto.secrets()) {
    authorization_data->secrets.push_back(
        KeyDefinition::AuthorizationData::Secret(
            secret.usage().encrypt(), secret.usage().sign(),
            secret.symmetric_key(), secret.public_key(), secret.wrapped()));
  }
}

}  // namespace cryptohome
