chromium/chrome/browser/enterprise/connectors/device_trust/key_management/core/persistence/mac_key_persistence_delegate.cc

// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/enterprise/connectors/device_trust/key_management/core/persistence/mac_key_persistence_delegate.h"

#include <Security/Security.h>
#include <utility>

#include "base/check.h"
#include "base/memory/scoped_refptr.h"
#include "chrome/browser/enterprise/connectors/device_trust/key_management/core/mac/secure_enclave_signing_key.h"
#include "chrome/browser/enterprise/connectors/device_trust/key_management/core/shared_command_constants.h"
#include "chrome/browser/enterprise/connectors/device_trust/key_management/core/signing_key_pair.h"
#include "components/policy/proto/device_management_backend.pb.h"

namespace enterprise_connectors {

using BPKUR = enterprise_management::BrowserPublicKeyUploadRequest;

MacKeyPersistenceDelegate::MacKeyPersistenceDelegate()
    : client_(SecureEnclaveClient::Create()) {
  DCHECK(client_);
}

MacKeyPersistenceDelegate::~MacKeyPersistenceDelegate() = default;

bool MacKeyPersistenceDelegate::CheckRotationPermissions() {
  return true;
}

bool MacKeyPersistenceDelegate::StoreKeyPair(KeyTrustLevel trust_level,
                                             std::vector<uint8_t> wrapped) {
  // This method does not actually store a new key pair but instead performs the
  // rollback of moving the previous signing key from temporary key storage back
  // to permanent key storage when failure occurs during the key rotation. This
  // is because key storage is handled by the SecureEnclaveSigningKey upon key
  // creation.
  if (trust_level == BPKUR::KEY_TRUST_LEVEL_UNSPECIFIED) {
    DCHECK_EQ(wrapped.size(), 0u);

    // A previous signing key did not exist so the newly created signing key
    // stored in the permanent key storage is deleted.
    return client_->DeleteKey(SecureEnclaveClient::KeyType::kPermanent);
  }

  auto key_type = SecureEnclaveClient::GetTypeFromWrappedKey(wrapped);

  if (!key_type ||
      key_type.value() == SecureEnclaveClient::KeyType::kTemporary) {
    // Roll the previous signing key back to permanent key storage.
    return client_->UpdateStoredKeyLabel(
        SecureEnclaveClient::KeyType::kTemporary,
        SecureEnclaveClient::KeyType::kPermanent);
  }

  return true;
}

scoped_refptr<SigningKeyPair> MacKeyPersistenceDelegate::LoadKeyPair(
    KeyStorageType type,
    LoadPersistedKeyResult* result) {
  SecureEnclaveSigningKeyProvider provider;
  OSStatus error;
  auto signing_key = provider.LoadStoredSigningKeySlowly(
      SecureEnclaveClient::KeyType::kPermanent, &error);
  if (!signing_key) {
    LoadPersistedKeyResult error_result =
        error == errSecItemNotFound ? LoadPersistedKeyResult::kNotFound
                                    : LoadPersistedKeyResult::kUnknown;
    return ReturnLoadKeyError(error_result, result);
  }

  if (result) {
    *result = LoadPersistedKeyResult::kSuccess;
  }
  return base::MakeRefCounted<SigningKeyPair>(std::move(signing_key),
                                              BPKUR::CHROME_BROWSER_HW_KEY);
}

scoped_refptr<SigningKeyPair> MacKeyPersistenceDelegate::CreateKeyPair() {
  // Moving a previous signing key to temporary key storage if a key exists.
  client_->UpdateStoredKeyLabel(SecureEnclaveClient::KeyType::kPermanent,
                                SecureEnclaveClient::KeyType::kTemporary);

  // The permanent key provider creates a new signing key pair in the permanent
  // key storage.
  SecureEnclaveSigningKeyProvider provider;
  auto signing_key = provider.GenerateSigningKeySlowly();
  if (!signing_key) {
    return nullptr;
  }

  return base::MakeRefCounted<SigningKeyPair>(std::move(signing_key),
                                              BPKUR::CHROME_BROWSER_HW_KEY);
}

bool MacKeyPersistenceDelegate::PromoteTemporaryKeyPair() {
  // TODO(b/290068552): Implement this method.
  return true;
}

bool MacKeyPersistenceDelegate::DeleteKeyPair(KeyStorageType type) {
  // TODO(b/290068552): Implement this method.
  return true;
}

void MacKeyPersistenceDelegate::CleanupTemporaryKeyData() {
  client_->DeleteKey(SecureEnclaveClient::KeyType::kTemporary);
}

}  // namespace enterprise_connectors