Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4b9aca0f authored by android-build-team Robot's avatar android-build-team Robot
Browse files

Snap for 5369966 from e270a05a to pi-qpr3-b-release

Change-Id: Ie69d983ca990b16efc8aa1f57f3c954fecb2115b
parents 3b98d24b e270a05a
Loading
Loading
Loading
Loading
+25 −1
Original line number Diff line number Diff line
@@ -24,6 +24,8 @@ btifCommonIncludes = [
    "packages/modules/Bluetooth/system/utils/include",
    "packages/modules/Bluetooth/system/include",
    "system/libhwbinder/include",
    "system/security/keystore/include",
    "hardware/interfaces/keymaster/4.0/support/include",
]

// libbtif static library for target
@@ -72,6 +74,7 @@ cc_library_static {
        "src/btif_hh.cc",
        "src/btif_hd.cc",
        "src/btif_hl.cc",
        "src/btif_keystore.cc",
        "src/btif_mce.cc",
        "src/btif_pan.cc",
        "src/btif_profile_queue.cc",
@@ -101,6 +104,13 @@ cc_library_static {
        "libhidltransport",
        "libhwbinder",
        "libutils",
        "libcrypto",
        "android.hardware.keymaster@4.0",
        "android.hardware.keymaster@3.0",
        "libkeymaster4support",
        "libkeystore_aidl",
        "libkeystore_binder",
        "libkeystore_parcelables",
    ],
    whole_static_libs: [
        "avrcp-target-service",
@@ -117,7 +127,10 @@ cc_test {
    name: "net_test_btif",
    defaults: ["fluoride_defaults"],
    include_dirs: btifCommonIncludes,
    srcs: ["test/btif_storage_test.cc"],
    srcs: [
        "test/btif_storage_test.cc",
        "test/btif_keystore_test.cc"
    ],
    header_libs: ["libbluetooth_headers"],
    shared_libs: [
        "libaudioclient",
@@ -127,6 +140,14 @@ cc_test {
        "libprotobuf-cpp-lite",
        "libcutils",
        "libutils",
        "libcrypto",
        "android.hardware.keymaster@4.0",
        "android.hardware.keymaster@3.0",
        "libkeymaster4support",
        "libkeystore_aidl",
        "libkeystore_binder",
        "libkeystore_parcelables",
        "libbinder",
    ],
    static_libs: [
        "libbt-bta",
@@ -148,6 +169,9 @@ cc_test {
        "libbluetooth-for-tests",
    ],
    cflags: ["-DBUILDCFG"],
    sanitize: {
        integer_overflow: true,
    },
}

// btif profile queue unit tests for target
+70 −0
Original line number Diff line number Diff line
/******************************************************************************
 *
 *  Copyright 2019 Google, Inc.
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at:
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 ******************************************************************************/

#include <base/logging.h>
#include <keystore/keystore_client_impl.h>
#include <mutex>

#include "osi/include/alarm.h"
#include "osi/include/allocator.h"
#include "osi/include/compat.h"
#include "osi/include/config.h"
#include "osi/include/log.h"
#include "osi/include/osi.h"
#include "osi/include/properties.h"

namespace bluetooth {
/**
 * Client wrapper to access AndroidKeystore.
 *
 * <p>Use to encrypt/decrypt data and store to disk.
 */
class BtifKeystore {
 public:
  /**
   * @param keystore_client injected pre-created client object for keystore
   */
  BtifKeystore(keystore::KeystoreClient* keystore_client);

  /**
   * Encrypts given data
   *
   * <p>Returns a string representation of the encrypted data
   *
   * @param data to be encrypted
   * @param flags for keystore
   */
  std::string Encrypt(const std::string& data, int32_t flags);

  /**
   * Returns a decrypted string representation of the encrypted data or empty
   * string on error.
   *
   * @param input encrypted data
   */
  std::string Decrypt(const std::string& input_filename);

 private:
  std::unique_ptr<keystore::KeystoreClient> keystore_client_;
  std::mutex api_mutex_;
  keystore::KeyStoreNativeReturnCode GenerateKey(const std::string& name,
                                                 int32_t flags,
                                                 bool auth_bound);
};

}  // namespace bluetooth
+119 −6
Original line number Diff line number Diff line
@@ -22,19 +22,23 @@

#include <base/logging.h>
#include <ctype.h>
#include <openssl/rand.h>
#include <openssl/sha.h>
#include <private/android_filesystem_config.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <string>

#include <mutex>
#include <sstream>
#include <string>

#include "bt_types.h"
#include "btcore/include/module.h"
#include "btif_api.h"
#include "btif_common.h"
#include "btif_config_transcode.h"
#include "btif_keystore.h"
#include "btif_util.h"
#include "osi/include/alarm.h"
#include "osi/include/allocator.h"
@@ -50,8 +54,15 @@
#define FILE_TIMESTAMP "TimeCreated"
#define FILE_SOURCE "FileSource"
#define TIME_STRING_LENGTH sizeof("YYYY-MM-DD HH:MM:SS")
#define DISABLED "disabled"
static const char* TIME_STRING_FORMAT = "%Y-%m-%d %H:%M:%S";

constexpr int kBufferSize = 400 * 10;  // initial file is ~400B

static bool use_key_attestation() { return getuid() == AID_BLUETOOTH; }

using bluetooth::BtifKeystore;

// TODO(armansito): Find a better way than searching by a hardcoded path.
#if defined(OS_GENERIC)
static const char* CONFIG_FILE_PATH = "bt_config.conf";
@@ -60,6 +71,8 @@ static const char* CONFIG_LEGACY_FILE_PATH = "bt_config.xml";
#else   // !defined(OS_GENERIC)
static const char* CONFIG_FILE_PATH = "/data/misc/bluedroid/bt_config.conf";
static const char* CONFIG_BACKUP_PATH = "/data/misc/bluedroid/bt_config.bak";
static const char* CONFIG_FILE_CHECKSUM_PATH = "/data/misc/bluedroid/bt_config.conf.encrypted-checksum";
static const char* CONFIG_BACKUP_CHECKSUM_PATH = "/data/misc/bluedroid/bt_config.bak.encrypted-checksum";
static const char* CONFIG_LEGACY_FILE_PATH =
    "/data/misc/bluedroid/bt_config.xml";
#endif  // defined(OS_GENERIC)
@@ -71,7 +84,12 @@ static bool is_factory_reset(void);
static void delete_config_files(void);
static void btif_config_remove_unpaired(config_t* config);
static void btif_config_remove_restricted(config_t* config);
static std::unique_ptr<config_t> btif_config_open(const char* filename);
static std::unique_ptr<config_t> btif_config_open(const char* filename, const char* checksum_filename);

// Key attestation
static std::string hash_file(const char* filename);
static std::string read_checksum_file(const char* filename);
static void write_checksum_file(const char* filename, const std::string& hash);

static enum ConfigSource {
  NOT_LOADED,
@@ -118,6 +136,8 @@ static std::mutex config_lock; // protects operations on |config|.
static std::unique_ptr<config_t> config;
static alarm_t* config_timer;

static BtifKeystore btif_keystore(new keystore::KeystoreClientImpl);

// Module lifecycle functions

static future_t* init(void) {
@@ -127,12 +147,13 @@ static future_t* init(void) {

  std::string file_source;

  config = btif_config_open(CONFIG_FILE_PATH);
  config = btif_config_open(CONFIG_FILE_PATH, CONFIG_FILE_CHECKSUM_PATH);
  btif_config_source = ORIGINAL;
  if (!config) {
    LOG_WARN(LOG_TAG, "%s unable to load config file: %s; using backup.",
             __func__, CONFIG_FILE_PATH);
    config = btif_config_open(CONFIG_BACKUP_PATH);
    remove(CONFIG_FILE_CHECKSUM_PATH);
    config = btif_config_open(CONFIG_BACKUP_PATH, CONFIG_BACKUP_CHECKSUM_PATH);
    btif_config_source = BACKUP;
    file_source = "Backup";
  }
@@ -140,6 +161,7 @@ static future_t* init(void) {
    LOG_WARN(LOG_TAG,
             "%s unable to load backup; attempting to transcode legacy file.",
             __func__);
    remove(CONFIG_BACKUP_CHECKSUM_PATH);
    config = btif_config_transcode(CONFIG_LEGACY_FILE_PATH);
    btif_config_source = LEGACY;
    file_source = "Legacy";
@@ -196,7 +218,25 @@ error:
  return future_new_immediate(FUTURE_FAIL);
}

static std::unique_ptr<config_t> btif_config_open(const char* filename) {
static std::unique_ptr<config_t> btif_config_open(const char* filename, const char* checksum_filename) {
  // START KEY ATTESTATION
  // Get hash of current file
  std::string current_hash = hash_file(filename);
  // Get stored hash
  std::string stored_hash = read_checksum_file(checksum_filename);
  if (stored_hash.empty()) {
    LOG(ERROR) << __func__ << ": stored_hash=<empty>";
    if (!current_hash.empty()) {
      write_checksum_file(checksum_filename, current_hash);
      stored_hash = read_checksum_file(checksum_filename);
    }
  }
  // Compare hashes
  if (current_hash != stored_hash) {
    return nullptr;
  }
  // END KEY ATTESTATION

  std::unique_ptr<config_t> config = config_new(filename);
  if (!config) return nullptr;

@@ -412,6 +452,13 @@ bool btif_config_clear(void) {

  bool ret = config_save(*config, CONFIG_FILE_PATH);
  btif_config_source = RESET;

  // Save encrypted hash
  std::string current_hash = hash_file(CONFIG_FILE_PATH);
  if (!current_hash.empty()) {
    write_checksum_file(CONFIG_FILE_CHECKSUM_PATH, current_hash);
  }

  return ret;
}

@@ -429,9 +476,15 @@ static void btif_config_write(UNUSED_ATTR uint16_t event,

  std::unique_lock<std::mutex> lock(config_lock);
  rename(CONFIG_FILE_PATH, CONFIG_BACKUP_PATH);
  rename(CONFIG_FILE_CHECKSUM_PATH, CONFIG_BACKUP_CHECKSUM_PATH);
  std::unique_ptr<config_t> config_paired = config_new_clone(*config);
  btif_config_remove_unpaired(config_paired.get());
  config_save(*config_paired, CONFIG_FILE_PATH);
  // Save hash
  std::string current_hash = hash_file(CONFIG_FILE_PATH);
  if (!current_hash.empty()) {
    write_checksum_file(CONFIG_FILE_CHECKSUM_PATH, current_hash);
  }
}

static void btif_config_remove_unpaired(config_t* conf) {
@@ -523,5 +576,65 @@ static bool is_factory_reset(void) {
static void delete_config_files(void) {
  remove(CONFIG_FILE_PATH);
  remove(CONFIG_BACKUP_PATH);
  remove(CONFIG_FILE_CHECKSUM_PATH);
  remove(CONFIG_BACKUP_CHECKSUM_PATH);
  osi_property_set("persist.bluetooth.factoryreset", "false");
}

static std::string hash_file(const char* filename) {
  if (!use_key_attestation()) {
    LOG(INFO) << __func__ << ": Disabled for multi-user";
    return DISABLED;
  }
  FILE* fp = fopen(filename, "rb");
  if (!fp) {
    LOG(ERROR) << __func__ << ": unable to open config file: '" << filename
               << "': " << strerror(errno);
    return "";
  }
  uint8_t hash[SHA256_DIGEST_LENGTH];
  SHA256_CTX sha256;
  SHA256_Init(&sha256);
  std::array<unsigned char, kBufferSize> buffer;
  int bytes_read = 0;
  while ((bytes_read = fread(buffer.data(), 1, buffer.size(), fp))) {
    SHA256_Update(&sha256, buffer.data(), bytes_read);
  }
  SHA256_Final(hash, &sha256);
  std::stringstream ss;
  for (int i = 0; i < SHA256_DIGEST_LENGTH; i++) {
    ss << std::hex << std::setw(2) << std::setfill('0') << (int)hash[i];
  }
  fclose(fp);
  return ss.str();
}

static std::string read_checksum_file(const char* checksum_filename) {
  if (!use_key_attestation()) {
    LOG(INFO) << __func__ << ": Disabled for multi-user";
    return DISABLED;
  }
  std::string encrypted_hash = checksum_read(checksum_filename);
  if (encrypted_hash.empty()) {
    LOG(INFO) << __func__ << ": read empty hash.";
    return "";
  }
  return btif_keystore.Decrypt(encrypted_hash);
}

static void write_checksum_file(const char* checksum_filename,
                                const std::string& hash) {
  if (!use_key_attestation()) {
    LOG(INFO) << __func__
              << ": Disabled for multi-user, since config changed removing "
                 "checksums.";
    remove(CONFIG_FILE_CHECKSUM_PATH);
    remove(CONFIG_BACKUP_CHECKSUM_PATH);
    return;
  }
  std::string encrypted_checksum = btif_keystore.Encrypt(hash, 0);
  CHECK(!encrypted_checksum.empty())
      << __func__ << ": Failed encrypting checksum";
  CHECK(checksum_save(encrypted_checksum, checksum_filename))
      << __func__ << ": Failed to save checksum!";
}
+101 −0
Original line number Diff line number Diff line
/******************************************************************************
 *
 *  Copyright 2019 Google, Inc.
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at:
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 ******************************************************************************/

#include "btif_keystore.h"

#include <base/files/file_util.h>
#include <base/logging.h>
#include <base/strings/string_number_conversions.h>
#include <base/strings/string_split.h>
#include <base/strings/string_util.h>
#include <base/strings/utf_string_conversions.h>
#include <sys/stat.h>

using namespace keystore;
using namespace bluetooth;

constexpr char kKeyStore[] = "AndroidKeystore";

namespace bluetooth {

BtifKeystore::BtifKeystore(keystore::KeystoreClient* keystore_client)
    : keystore_client_(keystore_client) {}

std::string BtifKeystore::Encrypt(const std::string& data, int32_t flags) {
  std::lock_guard<std::mutex> lock(api_mutex_);
  std::string output;
  if (data.empty()) {
    LOG(ERROR) << __func__ << ": empty data";
    return output;
  }
  if (!keystore_client_->doesKeyExist(kKeyStore)) {
    auto gen_result = GenerateKey(kKeyStore, 0, false);
    if (!gen_result.isOk()) {
      LOG(FATAL) << "EncryptWithAuthentication Failed: generateKey response="
                 << gen_result;
      return output;
    }
  }
  if (!keystore_client_->encryptWithAuthentication(kKeyStore, data, flags,
                                                   &output)) {
    LOG(FATAL) << "EncryptWithAuthentication failed.";
    return output;
  }
  return output;
}

std::string BtifKeystore::Decrypt(const std::string& input) {
  std::lock_guard<std::mutex> lock(api_mutex_);
  if (input.empty()) {
    LOG(ERROR) << __func__ << ": empty input data";
    return "";
  }
  std::string output;
  if (!keystore_client_->decryptWithAuthentication(kKeyStore, input, &output)) {
    LOG(FATAL) << "DecryptWithAuthentication failed.\n";
  }
  return output;
}

// Note: auth_bound keys created with this tool will not be usable.
KeyStoreNativeReturnCode BtifKeystore::GenerateKey(const std::string& name,
                                                   int32_t flags,
                                                   bool auth_bound) {
  AuthorizationSetBuilder params;
  params.RsaSigningKey(2048, 65537)
      .Digest(Digest::SHA_2_224)
      .Digest(Digest::SHA_2_256)
      .Digest(Digest::SHA_2_384)
      .Digest(Digest::SHA_2_512)
      .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN)
      .Padding(PaddingMode::RSA_PSS);
  if (auth_bound) {
    // Gatekeeper normally generates the secure user id.
    // Using zero allows the key to be created, but it will not be usuable.
    params.Authorization(TAG_USER_SECURE_ID, 0);
  } else {
    params.Authorization(TAG_NO_AUTH_REQUIRED);
  }
  AuthorizationSet hardware_enforced_characteristics;
  AuthorizationSet software_enforced_characteristics;
  return keystore_client_->generateKey(name, params, flags,
                                       &hardware_enforced_characteristics,
                                       &software_enforced_characteristics);
}

}  // namespace bluetooth
+64 −0
Original line number Diff line number Diff line
/******************************************************************************
 *
 *  Copyright 2019 Google, Inc.
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at:
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 ******************************************************************************/

#include <base/logging.h>
#include <binder/ProcessState.h>
#include <gtest/gtest.h>
#include <fstream>

#include "btif/include/btif_keystore.h"

using namespace bluetooth;

class BtifKeystoreTest : public ::testing::Test {
 protected:
  std::unique_ptr<BtifKeystore> btif_keystore_;
  void SetUp() override {
    android::ProcessState::self()->startThreadPool();
    btif_keystore_ =
        std::make_unique<BtifKeystore>(static_cast<keystore::KeystoreClient*>(
            new keystore::KeystoreClientImpl));
  };
  void TearDown() override { btif_keystore_ = nullptr; };
};

TEST_F(BtifKeystoreTest, test_encrypt_decrypt) {
  std::string hash = "test";

  std::string encrypted_hash = btif_keystore_->Encrypt(hash, 0);
  std::string decrypted_hash = btif_keystore_->Decrypt(encrypted_hash);

  EXPECT_FALSE(encrypted_hash.empty());
  EXPECT_EQ(hash, decrypted_hash);
}

TEST_F(BtifKeystoreTest, test_encrypt_empty_hash) {
  std::string hash = "";

  std::string encrypted_hash = btif_keystore_->Encrypt(hash, 0);

  EXPECT_TRUE(encrypted_hash.empty());
}

TEST_F(BtifKeystoreTest, test_decrypt_empty_hash) {
  std::string hash = "";

  std::string decrypted_hash = btif_keystore_->Decrypt(hash);

  EXPECT_TRUE(decrypted_hash.empty());
}
Loading