// Copyright 2020 The Fuchsia 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 "platform_auth_delegate.h"

#include <fuchsia/weave/cpp/fidl.h>
#include <lib/fit/defer.h>

#include <Weave/Profiles/security/WeaveSig.h>
#include <sdk/lib/syslog/cpp/macros.h>

#include "src/connectivity/weave/adaptation/weave_device_platform_error.h"
#include "utils.h"

namespace nl::Weave::DeviceLayer::Internal {
namespace {
namespace Profiles = ::nl::Weave::Profiles;
namespace Security = ::nl::Weave::Profiles::Security;
namespace ServiceProvisioning = ::nl::Weave::Profiles::ServiceProvisioning;

using Profiles::Security::CertificateKeyId;
using Profiles::Security::kDecodeFlag_IsTrusted;
using Profiles::Security::PackedCertDateToTime;
using Profiles::Security::WeaveDN;
using Security::WeaveCertificateData;

// TODO(https://fxbug.dev/42128288): Allow build-time configuration of these values.
constexpr size_t kMaxCerts = 10;
constexpr size_t kMaxServiceConfigSize = 10000;
constexpr size_t kCertDecodeBufferSize = 5000;

WEAVE_ERROR GetEffectiveTime(uint32_t& effective_time) {
  // Set the effective time for certificate validation. Use the current time if
  // the system's real time clock is synchronized, but otherwise use the
  // firmware build time and arrange to ignore the 'not before' date in the
  // peer's certificate.
  uint64_t now_ms;
  WEAVE_ERROR err = System::Layer::GetClock_RealTimeMS(now_ms);
  if (err == WEAVE_NO_ERROR) {
    // TODO(https://fxbug.dev/42129131): The default implementation of GetClock_RealTimeMS only returns
    // not-synced if the value is before Jan 1, 2000. Use the UTC fidl instead
    // to confirm whether the clock source is from some external source.
    effective_time =
        Security::SecondsSinceEpochToPackedCertTime(static_cast<uint32_t>(now_ms / 1000));
  } else if (err == WEAVE_SYSTEM_ERROR_REAL_TIME_NOT_SYNCED) {
    // TODO(https://fxbug.dev/42129131): Acquire the firmware build time, for now we set it to May 26, 2023
    // as reasonable default time.
    effective_time = Security::SecondsSinceEpochToPackedCertTime(1685059200U);
    FX_LOGS(WARNING) << "Real time clock not synchronized, using default time for cert validation.";
  }
  return err;
}

}  // namespace

static PlatformAuthDelegate gPlatformCASEAuthDelegate;
static PlatformAuthDelegate gPlatformKeyExportDelegate;

// Implementation of Internal::InitCASEAuthDelegate as defined in the
// openweave-core adaptation layer.
WEAVE_ERROR InitCASEAuthDelegate() {
  new (&gPlatformCASEAuthDelegate) PlatformAuthDelegate();
  SecurityMgr.SetCASEAuthDelegate(&gPlatformCASEAuthDelegate);
  return WEAVE_NO_ERROR;
}

// Implementation of Internal::InitKeyExportDelegate.
WEAVE_ERROR InitKeyExportDelegate() {
  new (&gPlatformKeyExportDelegate) PlatformAuthDelegate();
  SecurityMgr.SetKeyExportDelegate(&gPlatformKeyExportDelegate);
  return WEAVE_NO_ERROR;
}

/// ==========================================================
/// nl::Weave::Profiles::Security::CASE::WeaveCASEAuthDelegate
/// ==========================================================

WEAVE_ERROR PlatformAuthDelegate::EncodeNodePayload(const BeginSessionContext& msg_ctx,
                                                    uint8_t* payload_buf, uint16_t payload_buf_size,
                                                    uint16_t& payload_len) {
  WEAVE_ERROR error = WEAVE_NO_ERROR;
  size_t device_desc_len;

  error = ConfigurationMgr().GetDeviceDescriptorTLV(
      payload_buf, static_cast<size_t>(payload_buf_size), device_desc_len);
  if (error != WEAVE_NO_ERROR) {
    return error;
  }

  payload_len = device_desc_len;
  return WEAVE_NO_ERROR;
}

WEAVE_ERROR PlatformAuthDelegate::EncodeNodeCertInfo(const BeginSessionContext& msg_ctx,
                                                     TLVWriter& writer) {
  WEAVE_ERROR err = WEAVE_NO_ERROR;

  err = GetNodeCertificates(device_cert_, device_intermediate_certs_);
  if (err != WEAVE_NO_ERROR) {
    return err;
  }

  // Encode the certificate information into the provided TLVWriter.
  return Profiles::Security::CASE::EncodeCASECertInfo(
      writer, device_cert_.data(), device_cert_.size(), device_intermediate_certs_.data(),
      device_intermediate_certs_.size());
}

WEAVE_ERROR PlatformAuthDelegate::GenerateNodeSignature(const BeginSessionContext& msg_ctx,
                                                        const uint8_t* msg_hash,
                                                        uint8_t msg_hash_len, TLVWriter& writer,
                                                        uint64_t tag) {
  return GenerateNodeSignature(msg_hash, msg_hash_len, writer, tag);
}

WEAVE_ERROR PlatformAuthDelegate::BeginValidation(const BeginSessionContext& msg_ctx,
                                                  ValidationContext& valid_ctx,
                                                  WeaveCertificateSet& cert_set) {
  return BeginCertValidation(valid_ctx, cert_set, msg_ctx.IsInitiator());
}

WEAVE_ERROR PlatformAuthDelegate::HandleValidationResult(const BeginSessionContext& msg_ctx,
                                                         ValidationContext& valid_ctx,
                                                         WeaveCertificateSet& cert_set,
                                                         WEAVE_ERROR& valid_res) {
  // If an error was already detected in a previous stage, return it as-is.
  if (valid_res != WEAVE_NO_ERROR) {
    return WEAVE_NO_ERROR;
  }

  uint64_t cert_id = valid_ctx.SigningCert->SubjectDN.AttrValue.WeaveId;
  switch (valid_ctx.SigningCert->CertType) {
    // If the peer authenticated with a device certificate:
    case kCertType_Device:
      // Reject the peer if the certificate node ID and peer node ID do not match.
      if (cert_id != msg_ctx.PeerNodeId) {
        valid_res = WEAVE_ERROR_WRONG_CERTIFICATE_SUBJECT;
      }
      break;
    // If the peer authenticated with a service endpoint certificate:
    case kCertType_ServiceEndpoint:
      // Reject the peer if the certificate node ID and peer node ID do not match.
      if (cert_id != msg_ctx.PeerNodeId) {
        valid_res = WEAVE_ERROR_WRONG_CERTIFICATE_SUBJECT;
      }
      // Reject the peer if they are initiating the session. Service endpoint
      // certificates cannot be used to initiate sessions to other nodes, only
      // to respond.
      if (!msg_ctx.IsInitiator()) {
        valid_res = WEAVE_ERROR_CERT_USAGE_NOT_ALLOWED;
      }
      break;
    // If the peer authenticated with an access token certificate:
    case kCertType_AccessToken:
      // Reject the peer if they are the session responder. Access token
      // certificates can only be used to initiate sessions.
      if (msg_ctx.IsInitiator()) {
        valid_res = WEAVE_ERROR_CERT_USAGE_NOT_ALLOWED;
      }
      break;
    default:
      valid_res = WEAVE_ERROR_CERT_USAGE_NOT_ALLOWED;
  }
  return WEAVE_NO_ERROR;
}

void PlatformAuthDelegate::EndValidation(const BeginSessionContext& msg_ctx,
                                         ValidationContext& valid_ctx,
                                         WeaveCertificateSet& cert_set) {
  cert_set.Release();
  service_config_.clear();
}

///=================================================================
/// nl::Weave::Profiles::Security::KeyExport::WeaveKeyExportDelegate
///=================================================================

WEAVE_ERROR PlatformAuthDelegate::GetNodeCertSet(WeaveKeyExport* key_export,
                                                 WeaveCertificateSet& cert_set) {
  WEAVE_ERROR err = WEAVE_NO_ERROR;
  WeaveCertificateData* node_cert = nullptr;

  if (key_export->IsInitiator()) {
    return WEAVE_ERROR_INVALID_ARGUMENT;
  }

  // Acquire the node certificates.
  err = GetNodeCertificates(device_cert_, device_intermediate_certs_);
  if (err != WEAVE_NO_ERROR) {
    return err;
  }

  // Initialize the certificate set to populate it.
  err = cert_set.Init(kMaxCerts, kCertDecodeBufferSize);
  if (err != WEAVE_NO_ERROR) {
    FX_LOGS(ERROR) << "Failed to initialize certificate set: " << ErrorStr(err);
    return err;
  }

  // Auto-release the certificate set on failures.
  auto release_cert_set = fit::defer([&] { cert_set.Release(); });

  // Load node certificate into the certificate set.
  err = cert_set.LoadCert(device_cert_.data(), device_cert_.size(), 0, node_cert);
  if (err != WEAVE_NO_ERROR) {
    FX_LOGS(ERROR) << "Failed to load device certificate data: " << ErrorStr(err);
    return err;
  }

  // If device intermediate certs were available, load into certificate set.
  if (!device_intermediate_certs_.empty()) {
    err =
        cert_set.LoadCerts(device_intermediate_certs_.data(), device_intermediate_certs_.size(), 0);
    if (err != WEAVE_NO_ERROR) {
      FX_LOGS(ERROR) << "Failed to load intermediate certificate data: " << ErrorStr(err);
      return err;
    }
  }

  release_cert_set.cancel();
  return WEAVE_NO_ERROR;
}

WEAVE_ERROR PlatformAuthDelegate::ReleaseNodeCertSet(WeaveKeyExport* key_export,
                                                     WeaveCertificateSet& cert_set) {
  cert_set.Release();
  device_cert_.clear();
  device_intermediate_certs_.clear();

  return WEAVE_NO_ERROR;
}

WEAVE_ERROR PlatformAuthDelegate::GenerateNodeSignature(WeaveKeyExport* key_export,
                                                        const uint8_t* msg_hash,
                                                        uint8_t msg_hash_len, TLVWriter& writer) {
  return GenerateNodeSignature(
      msg_hash, msg_hash_len, writer,
      TLV::ContextTag(Profiles::Security::kTag_WeaveSignature_ECDSASignatureData));
}

WEAVE_ERROR PlatformAuthDelegate::BeginCertValidation(WeaveKeyExport* key_export,
                                                      ValidationContext& valid_ctx,
                                                      WeaveCertificateSet& cert_set) {
  return BeginCertValidation(valid_ctx, cert_set, key_export->IsInitiator());
}

WEAVE_ERROR PlatformAuthDelegate::HandleCertValidationResult(WeaveKeyExport* key_export,
                                                             ValidationContext& valid_ctx,
                                                             WeaveCertificateSet& cert_set,
                                                             uint32_t requested_key_id) {
  WeaveCertificateData* peer_cert;
  WEAVE_ERROR err = WEAVE_NO_ERROR;

  if (key_export->IsInitiator()) {
    FX_LOGS(ERROR) << "Invalid initiator state for key export.";
    return WEAVE_ERROR_INVALID_ARGUMENT;
  }

  // Only permit key export for a trusted, self-signed certificate.
  peer_cert = valid_ctx.SigningCert;
  if ((requested_key_id == WeaveKeyId::kClientRootKey) &&
      (peer_cert->CertFlags & Profiles::Security::kCertFlag_IsTrusted) &&
      peer_cert->IssuerDN.IsEqual(peer_cert->SubjectDN) &&
      (peer_cert->SubjectDN.AttrOID == ASN1::kOID_AttributeType_CommonName)) {
    err = WEAVE_NO_ERROR;
  } else {
    err = WEAVE_ERROR_UNAUTHORIZED_KEY_EXPORT_RESPONSE;
  }

  return err;
}

WEAVE_ERROR PlatformAuthDelegate::EndCertValidation(WeaveKeyExport* key_export,
                                                    ValidationContext& valid_ctx,
                                                    WeaveCertificateSet& cert_set) {
  if (key_export->IsInitiator()) {
    FX_LOGS(ERROR) << "Invalid initiator state for key export.";
    return WEAVE_ERROR_INVALID_ARGUMENT;
  }

  cert_set.Release();
  return WEAVE_NO_ERROR;
}

WEAVE_ERROR PlatformAuthDelegate::ValidateUnsignedKeyExportMessage(WeaveKeyExport* key_export,
                                                                   uint32_t requested_key_id) {
  return WEAVE_ERROR_UNAUTHORIZED_KEY_EXPORT_REQUEST;
}

///====================================
/// Common Authentication Functionality
///====================================

WEAVE_ERROR PlatformAuthDelegate::GetNodeCertificates(
    std::vector<uint8_t>& device_cert, std::vector<uint8_t>& device_intermediate_certs) {
  size_t device_cert_size = 0;
  size_t device_intermediate_certs_size = 0;
  WEAVE_ERROR err = WEAVE_NO_ERROR;

  // Fetch the provided device certificate.
  err = ConfigurationMgr().GetDeviceCertificate(nullptr, 0, device_cert_size);
  if (err != WEAVE_NO_ERROR) {
    return err;
  }

  device_cert.resize(device_cert_size);
  err = ConfigurationMgr().GetDeviceCertificate(device_cert.data(), device_cert.size(),
                                                device_cert_size);
  if (err != WEAVE_NO_ERROR) {
    return err;
  }

  // Fetch any intermediate CA certificates.
  err = ConfigurationMgr().GetDeviceIntermediateCACerts(nullptr, 0, device_intermediate_certs_size);
  if (err == WEAVE_NO_ERROR) {
    device_intermediate_certs.resize(device_intermediate_certs_size);
    err = ConfigurationMgr().GetDeviceIntermediateCACerts(device_intermediate_certs.data(),
                                                          device_intermediate_certs.size(),
                                                          device_intermediate_certs_size);
    if (err != WEAVE_NO_ERROR) {
      return err;
    }
  } else if (err != WEAVE_DEVICE_ERROR_CONFIG_NOT_FOUND) {
    return err;
  } else {
    device_intermediate_certs.resize(0);
  }

  return WEAVE_NO_ERROR;
}

WEAVE_ERROR PlatformAuthDelegate::GenerateNodeSignature(const uint8_t* msg_hash,
                                                        uint8_t msg_hash_len, TLVWriter& writer,
                                                        uint64_t tag) {
  fuchsia::weave::Signer_SignHash_Result result;
  std::vector<uint8_t>* output;
  zx_status_t status;
  std::vector<uint8_t> signing_key;

  // Using a private key directly is intended only for test purposes.
  status = ConfigurationMgrImpl().GetPrivateKeyForSigning(&signing_key);
  if (status == ZX_OK) {
    status = Security::GenerateAndEncodeWeaveECDSASignature(writer, tag, msg_hash, msg_hash_len,
                                                            signing_key.data(), signing_key.size());
    secure_memset(signing_key.data(), 0, signing_key.size());
    signing_key.clear();
    return status;
  }

  // If private key is not present, continue with the signer, else return the error
  // encountered in reading the private key.
  if (status != ZX_ERR_NOT_FOUND) {
    FX_LOGS(ERROR) << "Failed reading private key:  " << zx_status_get_string(status);
    return status;
  }

  fuchsia::weave::SignerSyncPtr signer;
  if ((status = PlatformMgrImpl().GetComponentContextForProcess()->svc()->Connect(
           signer.NewRequest())) != ZX_OK) {
    FX_LOGS(ERROR) << "Failed to connect to signer: " << status;
    return status;
  }

  std::vector<uint8_t> hash(msg_hash, msg_hash + (msg_hash_len * sizeof(uint8_t)));
  if ((status = signer->SignHash(hash, &result)) != ZX_OK || !result.is_response()) {
    FX_LOGS(ERROR) << "Failed to sign hash: " << status;
    return status;
  }

  output = &result.response().signature;
  return Security::ConvertECDSASignature_DERToWeave(output->data(), output->size(), writer, tag);
}

// If the service config contains a dev root cert that has expired, replace it.
WEAVE_ERROR PlatformAuthDelegate::ReplaceExpiredCertInServiceConfig(WeaveCertificateSet& cert_set) {
  WEAVE_ERROR err;
  WeaveCertificateData* candidate = nullptr;
  const CertificateKeyId skid = {
      .Id = nl::NestCerts::Development::Root::SubjectKeyId,
      .Len = static_cast<uint8_t>(nl::NestCerts::Development::Root::SubjectKeyIdLength)};

  const WeaveDN dn = {.AttrValue = {.WeaveId = nl::NestCerts::Development::Root::CAId},
                      .AttrOID = ASN1::kOID_AttributeType_WeaveCAId};
  ValidationContext valid_ctx;
  enum { kLastSecondOfDay = nl::kSecondsPerDay - 1 };

  // Search for dev root cert, return if not found.
  candidate = cert_set.FindCert(skid);
  if (!candidate) {
    return WEAVE_NO_ERROR;
  }

  if (!candidate->SubjectDN.IsEqual(dn)) {
    return WEAVE_NO_ERROR;
  }

  FX_LOGS(INFO) << "Found Dev root CA";

  uint32_t effective_time = 0;
  err = GetEffectiveTime(effective_time);
  valid_ctx.EffectiveTime = effective_time;

  if (candidate->NotAfterDate != 0 &&
      valid_ctx.EffectiveTime > PackedCertDateToTime(candidate->NotAfterDate) + kLastSecondOfDay) {
    FX_LOGS(INFO) << "Dev root CA expired, so replace it.";
    err = cert_set.ReplaceCert(nl::NestCerts::Development::Root::Cert,
                               nl::NestCerts::Development::Root::CertLength, kDecodeFlag_IsTrusted,
                               candidate);
    if (err != WEAVE_NO_ERROR) {
      FX_LOGS(ERROR) << "Failed to replace Dev root CA";
      return err;
    }
  }

  return WEAVE_NO_ERROR;
}

WEAVE_ERROR PlatformAuthDelegate::BeginCertValidation(ValidationContext& valid_ctx,
                                                      WeaveCertificateSet& cert_set,
                                                      bool is_initiator) {
  WEAVE_ERROR err = WEAVE_NO_ERROR;
  size_t service_config_len = 0;

  service_config_.clear();
  service_config_.resize(kMaxServiceConfigSize);

  err = cert_set.Init(kMaxCerts, kCertDecodeBufferSize);
  if (err != WEAVE_NO_ERROR) {
    return err;
  }

  auto release_cert_set = fit::defer([&] { cert_set.Release(); });

  // Read the service config data.
  err = ConfigurationMgr().GetServiceConfig(service_config_.data(), service_config_.size(),
                                            service_config_len);
  if (err != WEAVE_NO_ERROR) {
    return err;
  }

  // Load the list of trusted root certificates from the service config.
  err = LoadCertsFromServiceConfig(service_config_.data(), service_config_len, cert_set);
  if (err != WEAVE_NO_ERROR) {
    return err;
  }

  err = ReplaceExpiredCertInServiceConfig(cert_set);
  if (err != WEAVE_NO_ERROR) {
    return err;
  }

  // Scan the list of trusted certs loaded from the service config. If the list
  // contains a general certificate with a CommonName subject, presume this is
  // the access token certificate.
  for (uint8_t cert_index = 0; cert_index < cert_set.CertCount; cert_index++) {
    WeaveCertificateData* cert = &cert_set.Certs[cert_index];
    if ((cert->CertFlags & Security::kCertFlag_IsTrusted) != 0 &&
        cert->CertType == kCertType_General &&
        cert->SubjectDN.AttrOID == ASN1::kOID_AttributeType_CommonName) {
      cert->CertType = kCertType_AccessToken;
    }
  }

  memset(&valid_ctx, 0, sizeof(valid_ctx));

  uint32_t effective_time = 0;
  err = GetEffectiveTime(effective_time);
  if (err == WEAVE_SYSTEM_ERROR_REAL_TIME_NOT_SYNCED) {
    valid_ctx.ValidateFlags |= Security::kValidateFlag_IgnoreNotBefore;
  }
  valid_ctx.EffectiveTime = effective_time;

  valid_ctx.RequiredKeyUsages = Security::kKeyUsageFlag_DigitalSignature;
  valid_ctx.RequiredKeyPurposes =
      is_initiator ? Security::kKeyPurposeFlag_ServerAuth : Security::kKeyPurposeFlag_ClientAuth;
  release_cert_set.cancel();
  return WEAVE_NO_ERROR;
}

WEAVE_ERROR PlatformAuthDelegate::LoadCertsFromServiceConfig(const uint8_t* service_config,
                                                             uint16_t service_config_len,
                                                             WeaveCertificateSet& cert_set) {
  WEAVE_ERROR err = WEAVE_NO_ERROR;
  TLV::TLVReader reader;
  TLV::TLVType top_level_container;

  reader.Init(service_config, service_config_len);
  reader.ImplicitProfileId = Profiles::kWeaveProfile_ServiceProvisioning;

  err = reader.Next(TLV::kTLVType_Structure,
                    TLV::ProfileTag(Profiles::kWeaveProfile_ServiceProvisioning,
                                    ServiceProvisioning::kTag_ServiceConfig));
  if (err != WEAVE_NO_ERROR) {
    return err;
  }

  err = reader.EnterContainer(top_level_container);
  if (err != WEAVE_NO_ERROR) {
    return err;
  }

  err = reader.Next(TLV::kTLVType_Array,
                    TLV::ContextTag(ServiceProvisioning::kTag_ServiceConfig_CACerts));
  if (err != WEAVE_NO_ERROR) {
    return err;
  }

  err = cert_set.LoadCerts(reader, Security::kDecodeFlag_IsTrusted);
  if (err != WEAVE_NO_ERROR) {
    return err;
  }

  return WEAVE_NO_ERROR;
}

}  // namespace nl::Weave::DeviceLayer::Internal
