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

Commit 4f7f7780 authored by Weichin Weng's avatar Weichin Weng Committed by Android (Google) Code Review
Browse files

Merge changes from topic "NIAP_patch" into qt-qpr1-dev

* changes:
  DO NOT MERGE: NIAP: Use AES-GCM 256 bits to encrypt key.
  DO NOT MERGE: NIAP: Use keystore to encrypt KEY
parents 4e5e965c b17e557a
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -105,7 +105,7 @@ bool is_restricted_mode(void);

/*******************************************************************************
 *
 * Function         is_single_user_mode_
 * Function         is_niap_mode
 *
 * Description      Checks if BT was enabled in single user mode. In this
 *                  mode, use of keystore for key attestation of LTK is limitee
@@ -114,7 +114,7 @@ bool is_restricted_mode(void);
 * Returns          bool
 *
 ******************************************************************************/
bool is_single_user_mode(void);
bool is_niap_mode(void);

/*******************************************************************************
 *
+9 −3
Original line number Diff line number Diff line
@@ -59,12 +59,18 @@ class BtifKeystore {
   */
  std::string Decrypt(const std::string& input_filename);

  /**
   * Check for existence of keystore key.
   *
   * This key can be cleared if a user manually wipes bluetooth storage data
   * b/133214365
   */
  bool DoesKeyExist();

 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);
  bool GenerateKey(const std::string& name, int32_t flags);
};

}  // namespace bluetooth
+6 −6
Original line number Diff line number Diff line
@@ -81,7 +81,7 @@ using bluetooth::hearing_aid::HearingAidInterface;

bt_callbacks_t* bt_hal_cbacks = NULL;
bool restricted_mode = false;
bool single_user_mode = false;
bool niap_mode = false;

/*******************************************************************************
 *  Externs
@@ -134,9 +134,9 @@ static bool is_profile(const char* p1, const char* p2) {
 ****************************************************************************/

static int init(bt_callbacks_t* callbacks, bool start_restricted,
                bool is_single_user_mode) {
  LOG_INFO(LOG_TAG, "%s: start restricted = %d ; single user = %d", __func__,
           start_restricted, is_single_user_mode);
                bool is_niap_mode) {
  LOG_INFO(LOG_TAG, "%s: start restricted = %d ; niap = %d", __func__,
           start_restricted, is_niap_mode);

  if (interface_ready()) return BT_STATUS_DONE;

@@ -146,7 +146,7 @@ static int init(bt_callbacks_t* callbacks, bool start_restricted,

  bt_hal_cbacks = callbacks;
  restricted_mode = start_restricted;
  single_user_mode = is_single_user_mode;
  niap_mode = is_niap_mode;
  stack_manager_get_interface()->init_stack();
  btif_debug_init();
  return BT_STATUS_SUCCESS;
@@ -169,7 +169,7 @@ static int disable(void) {
static void cleanup(void) { stack_manager_get_interface()->clean_up_stack(); }

bool is_restricted_mode() { return restricted_mode; }
bool is_single_user_mode() { return single_user_mode; }
bool is_niap_mode() { return niap_mode; }

static int get_adapter_properties(void) {
  /* sanity check */
+121 −10
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@

#include "btif_config.h"

#include <base/base64.h>
#include <base/logging.h>
#include <ctype.h>
#include <openssl/rand.h>
@@ -60,8 +61,8 @@ 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 && is_single_user_mode();
static bool btif_is_niap_mode() {
  return getuid() == AID_BLUETOOTH && is_niap_mode();
}

#define BT_CONFIG_METRICS_SECTION "Metrics"
@@ -93,10 +94,22 @@ static void btif_config_remove_restricted(config_t* config);
static std::unique_ptr<config_t> btif_config_open(const char* filename, const char* checksum_filename);

// Key attestation
static std::string btif_convert_to_encrypt_key(
    const std::string& unencrypt_str);
static std::string btif_convert_to_unencrypt_key(
    const std::string& encrypt_str);
static bool btif_in_encrypt_key_name_list(std::string key);
static bool btif_is_key_encrypted(int key_from_config_size,
                                  std::string key_type_string);
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 const int ENCRYPT_KEY_NAME_LIST_SIZE = 7;
static const std::string encrypt_key_name_list[] = {
    "LinkKey",      "LE_KEY_PENC", "LE_KEY_PID",  "LE_KEY_LID",
    "LE_KEY_PCSRK", "LE_KEY_LENC", "LE_KEY_LCSRK"};

static enum ConfigSource {
  NOT_LOADED,
  ORIGINAL,
@@ -269,7 +282,8 @@ static std::unique_ptr<config_t> btif_config_open(const char* filename, const ch
  std::string stored_hash = read_checksum_file(checksum_filename);
  if (stored_hash.empty()) {
    LOG(ERROR) << __func__ << ": stored_hash=<empty>";
    if (!current_hash.empty()) {
    // Will encrypt once since the bt_config never encrypt.
    if (!btif_keystore.DoesKeyExist() && !current_hash.empty()) {
      write_checksum_file(checksum_filename, current_hash);
      stored_hash = read_checksum_file(checksum_filename);
    }
@@ -406,14 +420,29 @@ bool btif_config_get_bin(const std::string& section, const std::string& key,
  CHECK(length != NULL);

  std::unique_lock<std::recursive_mutex> lock(config_lock);
  const std::string* value_str = config_get_string(*config, section, key, NULL);
  const std::string* value_str;
  const std::string* value_str_from_config =
      config_get_string(*config, section, key, NULL);

  if (!value_str) {
  if (!value_str_from_config) {
    VLOG(1) << __func__ << ": cannot find string for section " << section
            << ", key " << key;
    return false;
  }

  bool in_encrypt_key_name_list = btif_in_encrypt_key_name_list(key);
  bool is_key_encrypted =
      btif_is_key_encrypted(value_str_from_config->size(), key);

  if (in_encrypt_key_name_list && is_key_encrypted) {
    VLOG(2) << __func__ << " decrypt section: " << section << " key:" << key;
    std::string tmp_value_str =
        btif_convert_to_unencrypt_key(*value_str_from_config);
    value_str = &tmp_value_str;
  } else {
    value_str = value_str_from_config;
  }

  size_t value_len = value_str->length();
  if ((value_len % 2) != 0 || *length < (value_len / 2)) {
    LOG(WARNING) << ": value size not divisible by 2, size is " << value_len;
@@ -427,12 +456,72 @@ bool btif_config_get_bin(const std::string& section, const std::string& key,
    }

  const char* ptr = value_str->c_str();
  for (*length = 0; *ptr; ptr += 2, *length += 1)
  for (*length = 0; *ptr; ptr += 2, *length += 1) {
    sscanf(ptr, "%02hhx", &value[*length]);
  }

  if (btif_is_niap_mode()) {
    if (in_encrypt_key_name_list && !is_key_encrypted) {
      VLOG(2) << __func__ << " encrypt section: " << section << " key:" << key;
      std::string encrypt_str =
          btif_convert_to_encrypt_key(*value_str_from_config);
      config_set_string(config.get(), section, key, encrypt_str);
    }
  } else {
    if (in_encrypt_key_name_list && is_key_encrypted) {
      config_set_string(config.get(), section, key, value_str->c_str());
    }
  }

  return true;
}

static bool btif_in_encrypt_key_name_list(std::string key) {
  return std::find(encrypt_key_name_list,
                   encrypt_key_name_list + ENCRYPT_KEY_NAME_LIST_SIZE,
                   key) != (encrypt_key_name_list + ENCRYPT_KEY_NAME_LIST_SIZE);
}

static bool btif_is_key_encrypted(int key_from_config_size,
                                  std::string key_type_string) {
  if (key_type_string.compare("LinkKey") == 0) {
    return sizeof(LinkKey) * 2 != key_from_config_size;
  } else if (key_type_string.compare("LE_KEY_PENC") == 0) {
    return sizeof(tBTM_LE_PENC_KEYS) * 2 != key_from_config_size;
  } else if (key_type_string.compare("LE_KEY_PID") == 0) {
    return sizeof(tBTM_LE_PID_KEYS) * 2 != key_from_config_size;
  } else if (key_type_string.compare("LE_KEY_LID") == 0) {
    return sizeof(tBTM_LE_PID_KEYS) * 2 != key_from_config_size;
  } else if (key_type_string.compare("LE_KEY_PCSRK") == 0) {
    return sizeof(tBTM_LE_PCSRK_KEYS) * 2 != key_from_config_size;
  } else if (key_type_string.compare("LE_KEY_LENC") == 0) {
    return sizeof(tBTM_LE_LENC_KEYS) * 2 != key_from_config_size;
  } else if (key_type_string.compare("LE_KEY_LCSRK") == 0) {
    return sizeof(tBTM_LE_LCSRK_KEYS) * 2 != key_from_config_size;
  } else {
    VLOG(2) << __func__ << ": " << key_type_string
            << " Key type is unknown, return false first";
    return false;
  }
}

static std::string btif_convert_to_unencrypt_key(
    const std::string& encrypt_str) {
  if (!encrypt_str.empty()) {
    std::string tmp_encrypt_str("");
    if (base::Base64Decode(encrypt_str, &tmp_encrypt_str)) {
      std::string unencrypt_str = btif_keystore.Decrypt(tmp_encrypt_str);
      if (!unencrypt_str.empty()) {
        return unencrypt_str;
      }
    } else {
      LOG(WARNING) << __func__
                   << ": base64string decode fail, will return empty string";
    }
  }
  return "";
}

size_t btif_config_get_bin_length(const std::string& section,
                                  const std::string& key) {
  CHECK(config != NULL);
@@ -466,15 +555,37 @@ bool btif_config_set_bin(const std::string& section, const std::string& key,
    str[(i * 2) + 1] = lookup[value[i] & 0x0F];
  }

  std::string value_str;
  if (btif_is_niap_mode() && btif_in_encrypt_key_name_list(key)) {
    VLOG(2) << __func__ << " encrypt section: " << section << " key:" << key;
    value_str = btif_convert_to_encrypt_key(str);
  } else {
    value_str = str;
  }

  {
    std::unique_lock<std::recursive_mutex> lock(config_lock);
    config_set_string(config.get(), section, key, str);
    config_set_string(config.get(), section, key, value_str);
  }

  osi_free(str);
  return true;
}

static std::string btif_convert_to_encrypt_key(
    const std::string& unencrypt_str) {
  if (!unencrypt_str.empty()) {
    std::string encrypt_str = btif_keystore.Encrypt(unencrypt_str, 0);
    if (!encrypt_str.empty()) {
      base::Base64Encode(encrypt_str, &encrypt_str);
      return encrypt_str;
    } else {
      LOG(ERROR) << __func__ << ": Encrypt fail, will return empty str.";
    }
  }
  return "";
}

std::list<section_t>& btif_config_sections() { return config->sections; }

bool btif_config_remove(const std::string& section, const std::string& key) {
@@ -641,7 +752,7 @@ static void delete_config_files(void) {
}

static std::string hash_file(const char* filename) {
  if (!use_key_attestation()) {
  if (!btif_is_niap_mode()) {
    LOG(INFO) << __func__ << ": Disabled for multi-user";
    return DISABLED;
  }
@@ -669,7 +780,7 @@ static std::string hash_file(const char* filename) {
}

static std::string read_checksum_file(const char* checksum_filename) {
  if (!use_key_attestation()) {
  if (!btif_is_niap_mode()) {
    LOG(INFO) << __func__ << ": Disabled for multi-user";
    return DISABLED;
  }
@@ -683,7 +794,7 @@ static std::string read_checksum_file(const char* checksum_filename) {

static void write_checksum_file(const char* checksum_filename,
                                const std::string& hash) {
  if (!use_key_attestation()) {
  if (!btif_is_niap_mode()) {
    LOG(INFO) << __func__
              << ": Disabled for multi-user, since config changed removing "
                 "checksums.";
+83 −36
Original line number Diff line number Diff line
@@ -17,6 +17,8 @@
 ******************************************************************************/

#include "btif_keystore.h"
#include "keystore_client.pb.h"
#include "string.h"

#include <base/files/file_util.h>
#include <base/logging.h>
@@ -29,7 +31,9 @@
using namespace keystore;
using namespace bluetooth;

constexpr char kKeyStore[] = "AndroidKeystore";
const std::string kKeyStore = "bluetooth-key-encrypted";
constexpr uint32_t kAESKeySize = 256;     // bits
constexpr uint32_t kMACOutputSize = 128;  // bits

namespace bluetooth {

@@ -43,19 +47,45 @@ std::string BtifKeystore::Encrypt(const std::string& data, int32_t flags) {
    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;
  if (!GenerateKey(kKeyStore, flags)) {
    return output;
  }

  AuthorizationSetBuilder encrypt_params;
  encrypt_params.Authorization(TAG_BLOCK_MODE, BlockMode::GCM)
      .Authorization(TAG_MAC_LENGTH, kMACOutputSize)
      .Padding(PaddingMode::NONE);
  AuthorizationSet output_params;
  std::string raw_encrypted_data;
  if (!keystore_client_->oneShotOperation(
          KeyPurpose::ENCRYPT, kKeyStore, encrypt_params, data,
          std::string() /* signature_to_verify */, &output_params,
          &raw_encrypted_data)) {
    LOG(ERROR) << __func__ << ": AES operation failed.";
    return output;
  }
  if (!keystore_client_->encryptWithAuthentication(kKeyStore, data, flags,
                                                   &output)) {
    LOG(FATAL) << "EncryptWithAuthentication failed.";
  auto init_vector_blob = output_params.GetTagValue(TAG_NONCE);
  if (!init_vector_blob.isOk()) {
    LOG(ERROR) << __func__ << ": Missing initialization vector.";
    return output;
  }

  const hidl_vec<uint8_t>& value = init_vector_blob.value();
  std::string init_vector =
      std::string(reinterpret_cast<const std::string::value_type*>(&value[0]),
                  value.size());

  if (memcmp(&init_vector_blob, &init_vector, init_vector.length()) == 0) {
    LOG(ERROR) << __func__
               << ": Protobuf nonce data doesn't match the actual nonce.";
  }

  EncryptedData protobuf;
  protobuf.set_init_vector(init_vector);
  protobuf.set_encrypted_data(raw_encrypted_data);
  if (!protobuf.SerializeToString(&output)) {
    LOG(ERROR) << __func__ << ": Failed to serialize EncryptedData protobuf.";
  }
  return output;
}

@@ -66,36 +96,53 @@ std::string BtifKeystore::Decrypt(const std::string& input) {
    return "";
  }
  std::string output;
  if (!keystore_client_->decryptWithAuthentication(kKeyStore, input, &output)) {
    LOG(FATAL) << "DecryptWithAuthentication failed.\n";
  EncryptedData protobuf;
  if (!protobuf.ParseFromString(input)) {
    LOG(ERROR) << __func__ << ": Failed to parse EncryptedData protobuf.";
    return output;
  }
  AuthorizationSetBuilder encrypt_params;
  encrypt_params.Authorization(TAG_BLOCK_MODE, BlockMode::GCM)
      .Authorization(TAG_MAC_LENGTH, kMACOutputSize)
      .Authorization(TAG_NONCE, protobuf.init_vector().data(),
                     protobuf.init_vector().size())
      .Padding(PaddingMode::NONE);
  AuthorizationSet output_params;
  if (!keystore_client_->oneShotOperation(
          KeyPurpose::DECRYPT, kKeyStore, encrypt_params,
          protobuf.encrypted_data(), std::string() /* signature_to_verify */,
          &output_params, &output)) {
    LOG(ERROR) << __func__ << ": AES operation failed.";
  }
  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) {
bool BtifKeystore::GenerateKey(const std::string& name, int32_t flags) {
  if (!DoesKeyExist()) {
    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);
  }
    params.AesEncryptionKey(kAESKeySize)
        .Authorization(TAG_NO_AUTH_REQUIRED)
        .Authorization(TAG_BLOCK_MODE, BlockMode::GCM)
        .Authorization(TAG_PURPOSE, KeyPurpose::ENCRYPT)
        .Authorization(TAG_PURPOSE, KeyPurpose::DECRYPT)
        .Padding(PaddingMode::NONE)
        .Authorization(TAG_MIN_MAC_LENGTH, kMACOutputSize);
    AuthorizationSet hardware_enforced_characteristics;
    AuthorizationSet software_enforced_characteristics;
  return keystore_client_->generateKey(name, params, flags,
                                       &hardware_enforced_characteristics,
    auto result = keystore_client_->generateKey(
        name, params, flags, &hardware_enforced_characteristics,
        &software_enforced_characteristics);
    if (!result.isOk()) {
      LOG(FATAL) << __func__ << "Failed to generate key: name: " << name
                 << ", error code: " << result.getErrorCode();
      return false;
    }
  }
  return true;
}

bool BtifKeystore::DoesKeyExist() {
  return keystore_client_->doesKeyExist(kKeyStore);
}

}  // namespace bluetooth
Loading