Support Keymaster4

This CL changes vold from using a KM3 device directly to using the KM4
support wrapper from the KM4 support library, which supports both KM3
and KM4 devices (KM0, 1 and 2 devices are still supported as well,
because the default KM3 device is a wrapper that uses them).

In addition, I found myself getting confused about which "Keymaster"
types were locally-defined vold keymaster types and which were from
the KM4 HAL and support library, so I changd the approach to
referencing the latter, so all of them are qualified with the "km::"
namespace reference.

Test: Build & boot
Change-Id: I08ed5425641e7496f8597d5716cb3cd0cbd33a7f
This commit is contained in:
Shawn Willden 2018-01-22 09:08:32 -07:00
parent 785365b2f7
commit 353518194e
8 changed files with 148 additions and 1367 deletions

View file

@ -38,6 +38,7 @@ cc_defaults {
], ],
shared_libs: [ shared_libs: [
"android.hardware.keymaster@3.0", "android.hardware.keymaster@3.0",
"android.hardware.keymaster@4.0",
"libbase", "libbase",
"libbinder", "libbinder",
"libcrypto", "libcrypto",
@ -50,6 +51,7 @@ cc_defaults {
"libhardware_legacy", "libhardware_legacy",
"libhidlbase", "libhidlbase",
"libhwbinder", "libhwbinder",
"libkeymaster4support",
"libkeyutils", "libkeyutils",
"liblog", "liblog",
"liblogwrap", "liblogwrap",
@ -113,7 +115,6 @@ cc_library_static {
"VoldNativeService.cpp", "VoldNativeService.cpp",
"VoldUtil.cpp", "VoldUtil.cpp",
"VolumeManager.cpp", "VolumeManager.cpp",
"authorization_set.cpp",
"cryptfs.cpp", "cryptfs.cpp",
"fs/Exfat.cpp", "fs/Exfat.cpp",
"fs/Ext4.cpp", "fs/Ext4.cpp",

View file

@ -40,18 +40,16 @@
#include <cutils/properties.h> #include <cutils/properties.h>
#include <hardware/hw_auth_token.h> #include <hardware/hw_auth_token.h>
#include <keymasterV4_0/authorization_set.h>
#include <keymasterV4_0/keymaster_utils.h>
extern "C" { extern "C" {
#include "crypto_scrypt.h" #include "crypto_scrypt.h"
} }
#include "authorization_set.h"
#include "keystore_hidl_support.h"
namespace android { namespace android {
namespace vold { namespace vold {
using namespace keystore;
const KeyAuthentication kEmptyAuthentication{"", ""}; const KeyAuthentication kEmptyAuthentication{"", ""};
@ -106,15 +104,13 @@ static void hashWithPrefix(char const* prefix, const std::string& tohash, std::s
static bool generateKeymasterKey(Keymaster& keymaster, const KeyAuthentication& auth, static bool generateKeymasterKey(Keymaster& keymaster, const KeyAuthentication& auth,
const std::string& appId, std::string* key) { const std::string& appId, std::string* key) {
auto paramBuilder = AuthorizationSetBuilder() auto paramBuilder = km::AuthorizationSetBuilder()
.AesEncryptionKey(AES_KEY_BYTES * 8) .AesEncryptionKey(AES_KEY_BYTES * 8)
.Authorization(TAG_BLOCK_MODE, BlockMode::GCM) .GcmModeMinMacLen(GCM_MAC_BYTES * 8)
.Authorization(TAG_MIN_MAC_LENGTH, GCM_MAC_BYTES * 8) .Authorization(km::TAG_APPLICATION_ID, km::support::blob2hidlVec(appId));
.Authorization(TAG_PADDING, PaddingMode::NONE)
.Authorization(TAG_APPLICATION_ID, blob2hidlVec(appId));
if (auth.token.empty()) { if (auth.token.empty()) {
LOG(DEBUG) << "Creating key that doesn't need auth token"; LOG(DEBUG) << "Creating key that doesn't need auth token";
paramBuilder.Authorization(TAG_NO_AUTH_REQUIRED); paramBuilder.Authorization(km::TAG_NO_AUTH_REQUIRED);
} else { } else {
LOG(DEBUG) << "Auth token required for key"; LOG(DEBUG) << "Auth token required for key";
if (auth.token.size() != sizeof(hw_auth_token_t)) { if (auth.token.size() != sizeof(hw_auth_token_t)) {
@ -123,24 +119,24 @@ static bool generateKeymasterKey(Keymaster& keymaster, const KeyAuthentication&
return false; return false;
} }
const hw_auth_token_t* at = reinterpret_cast<const hw_auth_token_t*>(auth.token.data()); const hw_auth_token_t* at = reinterpret_cast<const hw_auth_token_t*>(auth.token.data());
paramBuilder.Authorization(TAG_USER_SECURE_ID, at->user_id); paramBuilder.Authorization(km::TAG_USER_SECURE_ID, at->user_id);
paramBuilder.Authorization(TAG_USER_AUTH_TYPE, HardwareAuthenticatorType::PASSWORD); paramBuilder.Authorization(km::TAG_USER_AUTH_TYPE, km::HardwareAuthenticatorType::PASSWORD);
paramBuilder.Authorization(TAG_AUTH_TIMEOUT, AUTH_TIMEOUT); paramBuilder.Authorization(km::TAG_AUTH_TIMEOUT, AUTH_TIMEOUT);
} }
return keymaster.generateKey(paramBuilder, key); return keymaster.generateKey(paramBuilder, key);
} }
static AuthorizationSet beginParams(const KeyAuthentication& auth, const std::string& appId) { static std::pair<km::AuthorizationSet, km::HardwareAuthToken> beginParams(
auto paramBuilder = AuthorizationSetBuilder() const KeyAuthentication& auth, const std::string& appId) {
.Authorization(TAG_BLOCK_MODE, BlockMode::GCM) auto paramBuilder = km::AuthorizationSetBuilder()
.Authorization(TAG_MAC_LENGTH, GCM_MAC_BYTES * 8) .GcmModeMacLen(GCM_MAC_BYTES * 8)
.Authorization(TAG_PADDING, PaddingMode::NONE) .Authorization(km::TAG_APPLICATION_ID, km::support::blob2hidlVec(appId));
.Authorization(TAG_APPLICATION_ID, blob2hidlVec(appId)); km::HardwareAuthToken authToken;
if (!auth.token.empty()) { if (!auth.token.empty()) {
LOG(DEBUG) << "Supplying auth token to Keymaster"; LOG(DEBUG) << "Supplying auth token to Keymaster";
paramBuilder.Authorization(TAG_AUTH_TOKEN, blob2hidlVec(auth.token)); authToken = km::support::hidlVec2AuthToken(km::support::blob2hidlVec(auth.token));
} }
return paramBuilder; return {paramBuilder, authToken};
} }
static bool readFileToString(const std::string& filename, std::string* result) { static bool readFileToString(const std::string& filename, std::string* result) {
@ -202,20 +198,22 @@ bool readSecdiscardable(const std::string& filename, std::string* hash) {
return true; return true;
} }
static KeymasterOperation begin(Keymaster& keymaster, const std::string& dir, KeyPurpose purpose, static KeymasterOperation begin(Keymaster& keymaster, const std::string& dir,
const AuthorizationSet& keyParams, const AuthorizationSet& opParams, km::KeyPurpose purpose, const km::AuthorizationSet& keyParams,
AuthorizationSet* outParams) { const km::AuthorizationSet& opParams,
const km::HardwareAuthToken& authToken,
km::AuthorizationSet* outParams) {
auto kmKeyPath = dir + "/" + kFn_keymaster_key_blob; auto kmKeyPath = dir + "/" + kFn_keymaster_key_blob;
std::string kmKey; std::string kmKey;
if (!readFileToString(kmKeyPath, &kmKey)) return KeymasterOperation(); if (!readFileToString(kmKeyPath, &kmKey)) return KeymasterOperation();
AuthorizationSet inParams(keyParams); km::AuthorizationSet inParams(keyParams);
inParams.append(opParams.begin(), opParams.end()); inParams.append(opParams.begin(), opParams.end());
for (;;) { for (;;) {
auto opHandle = keymaster.begin(purpose, kmKey, inParams, outParams); auto opHandle = keymaster.begin(purpose, kmKey, inParams, authToken, outParams);
if (opHandle) { if (opHandle) {
return opHandle; return opHandle;
} }
if (opHandle.errorCode() != ErrorCode::KEY_REQUIRES_UPGRADE) return opHandle; if (opHandle.errorCode() != km::ErrorCode::KEY_REQUIRES_UPGRADE) return opHandle;
LOG(DEBUG) << "Upgrading key: " << dir; LOG(DEBUG) << "Upgrading key: " << dir;
std::string newKey; std::string newKey;
if (!keymaster.upgradeKey(kmKey, keyParams, &newKey)) return KeymasterOperation(); if (!keymaster.upgradeKey(kmKey, keyParams, &newKey)) return KeymasterOperation();
@ -234,13 +232,15 @@ static KeymasterOperation begin(Keymaster& keymaster, const std::string& dir, Ke
} }
static bool encryptWithKeymasterKey(Keymaster& keymaster, const std::string& dir, static bool encryptWithKeymasterKey(Keymaster& keymaster, const std::string& dir,
const AuthorizationSet& keyParams, const KeyBuffer& message, const km::AuthorizationSet& keyParams,
std::string* ciphertext) { const km::HardwareAuthToken& authToken,
AuthorizationSet opParams; const KeyBuffer& message, std::string* ciphertext) {
AuthorizationSet outParams; km::AuthorizationSet opParams;
auto opHandle = begin(keymaster, dir, KeyPurpose::ENCRYPT, keyParams, opParams, &outParams); km::AuthorizationSet outParams;
auto opHandle =
begin(keymaster, dir, km::KeyPurpose::ENCRYPT, keyParams, opParams, authToken, &outParams);
if (!opHandle) return false; if (!opHandle) return false;
auto nonceBlob = outParams.GetTagValue(TAG_NONCE); auto nonceBlob = outParams.GetTagValue(km::TAG_NONCE);
if (!nonceBlob.isOk()) { if (!nonceBlob.isOk()) {
LOG(ERROR) << "GCM encryption but no nonce generated"; LOG(ERROR) << "GCM encryption but no nonce generated";
return false; return false;
@ -260,12 +260,15 @@ static bool encryptWithKeymasterKey(Keymaster& keymaster, const std::string& dir
} }
static bool decryptWithKeymasterKey(Keymaster& keymaster, const std::string& dir, static bool decryptWithKeymasterKey(Keymaster& keymaster, const std::string& dir,
const AuthorizationSet& keyParams, const km::AuthorizationSet& keyParams,
const km::HardwareAuthToken& authToken,
const std::string& ciphertext, KeyBuffer* message) { const std::string& ciphertext, KeyBuffer* message) {
auto nonce = ciphertext.substr(0, GCM_NONCE_BYTES); auto nonce = ciphertext.substr(0, GCM_NONCE_BYTES);
auto bodyAndMac = ciphertext.substr(GCM_NONCE_BYTES); auto bodyAndMac = ciphertext.substr(GCM_NONCE_BYTES);
auto opParams = AuthorizationSetBuilder().Authorization(TAG_NONCE, blob2hidlVec(nonce)); auto opParams = km::AuthorizationSetBuilder().Authorization(km::TAG_NONCE,
auto opHandle = begin(keymaster, dir, KeyPurpose::DECRYPT, keyParams, opParams, nullptr); km::support::blob2hidlVec(nonce));
auto opHandle =
begin(keymaster, dir, km::KeyPurpose::DECRYPT, keyParams, opParams, authToken, nullptr);
if (!opHandle) return false; if (!opHandle) return false;
if (!opHandle.updateCompletely(bodyAndMac, message)) return false; if (!opHandle.updateCompletely(bodyAndMac, message)) return false;
if (!opHandle.finish(nullptr)) return false; if (!opHandle.finish(nullptr)) return false;
@ -468,8 +471,11 @@ bool storeKey(const std::string& dir, const KeyAuthentication& auth, const KeyBu
std::string kmKey; std::string kmKey;
if (!generateKeymasterKey(keymaster, auth, appId, &kmKey)) return false; if (!generateKeymasterKey(keymaster, auth, appId, &kmKey)) return false;
if (!writeStringToFile(kmKey, dir + "/" + kFn_keymaster_key_blob)) return false; if (!writeStringToFile(kmKey, dir + "/" + kFn_keymaster_key_blob)) return false;
auto keyParams = beginParams(auth, appId); km::AuthorizationSet keyParams;
if (!encryptWithKeymasterKey(keymaster, dir, keyParams, key, &encryptedKey)) return false; km::HardwareAuthToken authToken;
std::tie(keyParams, authToken) = beginParams(auth, appId);
if (!encryptWithKeymasterKey(keymaster, dir, keyParams, authToken, key, &encryptedKey))
return false;
} else { } else {
if (!encryptWithoutKeymaster(appId, key, &encryptedKey)) return false; if (!encryptWithoutKeymaster(appId, key, &encryptedKey)) return false;
} }
@ -518,8 +524,10 @@ bool retrieveKey(const std::string& dir, const KeyAuthentication& auth, KeyBuffe
if (auth.usesKeymaster()) { if (auth.usesKeymaster()) {
Keymaster keymaster; Keymaster keymaster;
if (!keymaster) return false; if (!keymaster) return false;
auto keyParams = beginParams(auth, appId); km::AuthorizationSet keyParams;
if (!decryptWithKeymasterKey(keymaster, dir, keyParams, encryptedMessage, key)) km::HardwareAuthToken authToken;
std::tie(keyParams, authToken) = beginParams(auth, appId);
if (!decryptWithKeymasterKey(keymaster, dir, keyParams, authToken, encryptedMessage, key))
return false; return false;
} else { } else {
if (!decryptWithoutKeymaster(appId, encryptedMessage, key)) return false; if (!decryptWithoutKeymaster(appId, encryptedMessage, key)) return false;

View file

@ -17,45 +17,48 @@
#include "Keymaster.h" #include "Keymaster.h"
#include <android-base/logging.h> #include <android-base/logging.h>
#include <keymasterV4_0/authorization_set.h>
#include "authorization_set.h" #include <keymasterV4_0/keymaster_utils.h>
#include "keymaster_tags.h"
#include "keystore_hidl_support.h"
using namespace ::keystore;
using android::hardware::hidl_string;
namespace android { namespace android {
namespace vold { namespace vold {
using ::android::hardware::hidl_string;
using ::android::hardware::hidl_vec;
KeymasterOperation::~KeymasterOperation() { KeymasterOperation::~KeymasterOperation() {
if (mDevice.get()) mDevice->abort(mOpHandle); if (mDevice) mDevice->abort(mOpHandle);
} }
bool KeymasterOperation::updateCompletely(const char* input, size_t inputLen, bool KeymasterOperation::updateCompletely(const char* input, size_t inputLen,
const std::function<void(const char*, size_t)> consumer) { const std::function<void(const char*, size_t)> consumer) {
uint32_t inputConsumed = 0; uint32_t inputConsumed = 0;
ErrorCode km_error; km::ErrorCode km_error;
auto hidlCB = [&](ErrorCode ret, uint32_t inputConsumedDelta, auto hidlCB = [&](km::ErrorCode ret, uint32_t inputConsumedDelta,
const hidl_vec<KeyParameter>& /*ignored*/, const hidl_vec<uint8_t>& _output) { const hidl_vec<km::KeyParameter>& /*ignored*/,
const hidl_vec<uint8_t>& _output) {
km_error = ret; km_error = ret;
if (km_error != ErrorCode::OK) return; if (km_error != km::ErrorCode::OK) return;
inputConsumed += inputConsumedDelta; inputConsumed += inputConsumedDelta;
consumer(reinterpret_cast<const char*>(&_output[0]), _output.size()); consumer(reinterpret_cast<const char*>(&_output[0]), _output.size());
}; };
while (inputConsumed != inputLen) { while (inputConsumed != inputLen) {
size_t toRead = static_cast<size_t>(inputLen - inputConsumed); size_t toRead = static_cast<size_t>(inputLen - inputConsumed);
auto inputBlob = auto inputBlob = km::support::blob2hidlVec(
blob2hidlVec(reinterpret_cast<const uint8_t*>(&input[inputConsumed]), toRead); reinterpret_cast<const uint8_t*>(&input[inputConsumed]), toRead);
auto error = mDevice->update(mOpHandle, hidl_vec<KeyParameter>(), inputBlob, hidlCB); // TODO(swillden): Need to handle getting a VerificationToken from the TEE if mDevice is
// StrongBox, so we can provide it here. The VerificationToken will need to be
// requested/retrieved during Keymaster::begin().
auto error = mDevice->update(mOpHandle, hidl_vec<km::KeyParameter>(), inputBlob,
km::HardwareAuthToken(), km::VerificationToken(), hidlCB);
if (!error.isOk()) { if (!error.isOk()) {
LOG(ERROR) << "update failed: " << error.description(); LOG(ERROR) << "update failed: " << error.description();
mDevice = nullptr; mDevice = nullptr;
return false; return false;
} }
if (km_error != ErrorCode::OK) { if (km_error != km::ErrorCode::OK) {
LOG(ERROR) << "update failed, code " << int32_t(km_error); LOG(ERROR) << "update failed, code " << int32_t(km_error);
mDevice = nullptr; mDevice = nullptr;
return false; return false;
@ -70,21 +73,22 @@ bool KeymasterOperation::updateCompletely(const char* input, size_t inputLen,
} }
bool KeymasterOperation::finish(std::string* output) { bool KeymasterOperation::finish(std::string* output) {
ErrorCode km_error; km::ErrorCode km_error;
auto hidlCb = [&](ErrorCode ret, const hidl_vec<KeyParameter>& /*ignored*/, auto hidlCb = [&](km::ErrorCode ret, const hidl_vec<km::KeyParameter>& /*ignored*/,
const hidl_vec<uint8_t>& _output) { const hidl_vec<uint8_t>& _output) {
km_error = ret; km_error = ret;
if (km_error != ErrorCode::OK) return; if (km_error != km::ErrorCode::OK) return;
if (output) output->assign(reinterpret_cast<const char*>(&_output[0]), _output.size()); if (output) output->assign(reinterpret_cast<const char*>(&_output[0]), _output.size());
}; };
auto error = mDevice->finish(mOpHandle, hidl_vec<KeyParameter>(), hidl_vec<uint8_t>(), auto error = mDevice->finish(mOpHandle, hidl_vec<km::KeyParameter>(), hidl_vec<uint8_t>(),
hidl_vec<uint8_t>(), hidlCb); hidl_vec<uint8_t>(), km::HardwareAuthToken(),
km::VerificationToken(), hidlCb);
mDevice = nullptr; mDevice = nullptr;
if (!error.isOk()) { if (!error.isOk()) {
LOG(ERROR) << "finish failed: " << error.description(); LOG(ERROR) << "finish failed: " << error.description();
return false; return false;
} }
if (km_error != ErrorCode::OK) { if (km_error != km::ErrorCode::OK) {
LOG(ERROR) << "finish failed, code " << int32_t(km_error); LOG(ERROR) << "finish failed, code " << int32_t(km_error);
return false; return false;
} }
@ -92,15 +96,21 @@ bool KeymasterOperation::finish(std::string* output) {
} }
Keymaster::Keymaster() { Keymaster::Keymaster() {
mDevice = ::android::hardware::keymaster::V3_0::IKeymasterDevice::getService(); auto devices = KmDevice::enumerateAvailableDevices();
if (devices.empty()) return;
mDevice = std::move(devices[0]);
auto& version = mDevice->halVersion();
LOG(INFO) << "Using " << version.keymasterName << " from " << version.authorName
<< " for encryption. Security level: " << toString(version.securityLevel)
<< ", HAL: " << mDevice->descriptor() << "/" << mDevice->instanceName();
} }
bool Keymaster::generateKey(const AuthorizationSet& inParams, std::string* key) { bool Keymaster::generateKey(const km::AuthorizationSet& inParams, std::string* key) {
ErrorCode km_error; km::ErrorCode km_error;
auto hidlCb = [&](ErrorCode ret, const hidl_vec<uint8_t>& keyBlob, auto hidlCb = [&](km::ErrorCode ret, const hidl_vec<uint8_t>& keyBlob,
const KeyCharacteristics& /*ignored*/) { const km::KeyCharacteristics& /*ignored*/) {
km_error = ret; km_error = ret;
if (km_error != ErrorCode::OK) return; if (km_error != km::ErrorCode::OK) return;
if (key) key->assign(reinterpret_cast<const char*>(&keyBlob[0]), keyBlob.size()); if (key) key->assign(reinterpret_cast<const char*>(&keyBlob[0]), keyBlob.size());
}; };
@ -109,7 +119,7 @@ bool Keymaster::generateKey(const AuthorizationSet& inParams, std::string* key)
LOG(ERROR) << "generate_key failed: " << error.description(); LOG(ERROR) << "generate_key failed: " << error.description();
return false; return false;
} }
if (km_error != ErrorCode::OK) { if (km_error != km::ErrorCode::OK) {
LOG(ERROR) << "generate_key failed, code " << int32_t(km_error); LOG(ERROR) << "generate_key failed, code " << int32_t(km_error);
return false; return false;
} }
@ -117,26 +127,26 @@ bool Keymaster::generateKey(const AuthorizationSet& inParams, std::string* key)
} }
bool Keymaster::deleteKey(const std::string& key) { bool Keymaster::deleteKey(const std::string& key) {
auto keyBlob = blob2hidlVec(key); auto keyBlob = km::support::blob2hidlVec(key);
auto error = mDevice->deleteKey(keyBlob); auto error = mDevice->deleteKey(keyBlob);
if (!error.isOk()) { if (!error.isOk()) {
LOG(ERROR) << "delete_key failed: " << error.description(); LOG(ERROR) << "delete_key failed: " << error.description();
return false; return false;
} }
if (ErrorCode(error) != ErrorCode::OK) { if (error != km::ErrorCode::OK) {
LOG(ERROR) << "delete_key failed, code " << uint32_t(ErrorCode(error)); LOG(ERROR) << "delete_key failed, code " << int32_t(km::ErrorCode(error));
return false; return false;
} }
return true; return true;
} }
bool Keymaster::upgradeKey(const std::string& oldKey, const AuthorizationSet& inParams, bool Keymaster::upgradeKey(const std::string& oldKey, const km::AuthorizationSet& inParams,
std::string* newKey) { std::string* newKey) {
auto oldKeyBlob = blob2hidlVec(oldKey); auto oldKeyBlob = km::support::blob2hidlVec(oldKey);
ErrorCode km_error; km::ErrorCode km_error;
auto hidlCb = [&](ErrorCode ret, const hidl_vec<uint8_t>& upgradedKeyBlob) { auto hidlCb = [&](km::ErrorCode ret, const hidl_vec<uint8_t>& upgradedKeyBlob) {
km_error = ret; km_error = ret;
if (km_error != ErrorCode::OK) return; if (km_error != km::ErrorCode::OK) return;
if (newKey) if (newKey)
newKey->assign(reinterpret_cast<const char*>(&upgradedKeyBlob[0]), newKey->assign(reinterpret_cast<const char*>(&upgradedKeyBlob[0]),
upgradedKeyBlob.size()); upgradedKeyBlob.size());
@ -146,44 +156,43 @@ bool Keymaster::upgradeKey(const std::string& oldKey, const AuthorizationSet& in
LOG(ERROR) << "upgrade_key failed: " << error.description(); LOG(ERROR) << "upgrade_key failed: " << error.description();
return false; return false;
} }
if (km_error != ErrorCode::OK) { if (km_error != km::ErrorCode::OK) {
LOG(ERROR) << "upgrade_key failed, code " << int32_t(km_error); LOG(ERROR) << "upgrade_key failed, code " << int32_t(km_error);
return false; return false;
} }
return true; return true;
} }
KeymasterOperation Keymaster::begin(KeyPurpose purpose, const std::string& key, KeymasterOperation Keymaster::begin(km::KeyPurpose purpose, const std::string& key,
const AuthorizationSet& inParams, AuthorizationSet* outParams) { const km::AuthorizationSet& inParams,
auto keyBlob = blob2hidlVec(key); const km::HardwareAuthToken& authToken,
km::AuthorizationSet* outParams) {
auto keyBlob = km::support::blob2hidlVec(key);
uint64_t mOpHandle; uint64_t mOpHandle;
ErrorCode km_error; km::ErrorCode km_error;
auto hidlCb = [&](ErrorCode ret, const hidl_vec<KeyParameter>& _outParams, auto hidlCb = [&](km::ErrorCode ret, const hidl_vec<km::KeyParameter>& _outParams,
uint64_t operationHandle) { uint64_t operationHandle) {
km_error = ret; km_error = ret;
if (km_error != ErrorCode::OK) return; if (km_error != km::ErrorCode::OK) return;
if (outParams) *outParams = _outParams; if (outParams) *outParams = _outParams;
mOpHandle = operationHandle; mOpHandle = operationHandle;
}; };
auto error = mDevice->begin(purpose, keyBlob, inParams.hidl_data(), hidlCb); auto error = mDevice->begin(purpose, keyBlob, inParams.hidl_data(), authToken, hidlCb);
if (!error.isOk()) { if (!error.isOk()) {
LOG(ERROR) << "begin failed: " << error.description(); LOG(ERROR) << "begin failed: " << error.description();
return KeymasterOperation(ErrorCode::UNKNOWN_ERROR); return KeymasterOperation(km::ErrorCode::UNKNOWN_ERROR);
} }
if (km_error != ErrorCode::OK) { if (km_error != km::ErrorCode::OK) {
LOG(ERROR) << "begin failed, code " << int32_t(km_error); LOG(ERROR) << "begin failed, code " << int32_t(km_error);
return KeymasterOperation(km_error); return KeymasterOperation(km_error);
} }
return KeymasterOperation(mDevice, mOpHandle); return KeymasterOperation(mDevice.get(), mOpHandle);
} }
bool Keymaster::isSecure() { bool Keymaster::isSecure() {
bool _isSecure = false; return mDevice->halVersion().securityLevel != km::SecurityLevel::SOFTWARE;
auto rc =
mDevice->getHardwareFeatures([&](bool isSecure, bool, bool, bool, bool, const hidl_string&,
const hidl_string&) { _isSecure = isSecure; });
return rc.isOk() && _isSecure;
} }
} // namespace vold } // namespace vold
@ -216,17 +225,14 @@ static bool write_string_to_buf(const std::string& towrite, uint8_t* buffer, uin
return true; return true;
} }
static AuthorizationSet keyParams(uint32_t rsa_key_size, uint64_t rsa_exponent, uint32_t ratelimit) { static km::AuthorizationSet keyParams(uint32_t rsa_key_size, uint64_t rsa_exponent,
return AuthorizationSetBuilder() uint32_t ratelimit) {
.Authorization(TAG_ALGORITHM, Algorithm::RSA) return km::AuthorizationSetBuilder()
.Authorization(TAG_KEY_SIZE, rsa_key_size) .RsaSigningKey(rsa_key_size, rsa_exponent)
.Authorization(TAG_RSA_PUBLIC_EXPONENT, rsa_exponent) .NoDigestOrPadding()
.Authorization(TAG_PURPOSE, KeyPurpose::SIGN) .Authorization(km::TAG_BLOB_USAGE_REQUIREMENTS, km::KeyBlobUsageRequirements::STANDALONE)
.Authorization(TAG_PADDING, PaddingMode::NONE) .Authorization(km::TAG_NO_AUTH_REQUIRED)
.Authorization(TAG_DIGEST, Digest::NONE) .Authorization(km::TAG_MIN_SECONDS_BETWEEN_OPS, ratelimit);
.Authorization(TAG_BLOB_USAGE_REQUIREMENTS, KeyBlobUsageRequirements::STANDALONE)
.Authorization(TAG_NO_AUTH_REQUIRED)
.Authorization(TAG_MIN_SECONDS_BETWEEN_OPS, ratelimit);
} }
int keymaster_create_key_for_cryptfs_scrypt(uint32_t rsa_key_size, uint64_t rsa_exponent, int keymaster_create_key_for_cryptfs_scrypt(uint32_t rsa_key_size, uint64_t rsa_exponent,
@ -279,31 +285,28 @@ KeymasterSignResult keymaster_sign_object_for_cryptfs_scrypt(
return KeymasterSignResult::error; return KeymasterSignResult::error;
} }
AuthorizationSet outParams; km::AuthorizationSet outParams;
std::string key(reinterpret_cast<const char*>(key_blob), key_blob_size); std::string key(reinterpret_cast<const char*>(key_blob), key_blob_size);
std::string input(reinterpret_cast<const char*>(object), object_size); std::string input(reinterpret_cast<const char*>(object), object_size);
std::string output; std::string output;
KeymasterOperation op; KeymasterOperation op;
auto paramBuilder = AuthorizationSetBuilder() auto paramBuilder = km::AuthorizationSetBuilder().NoDigestOrPadding();
.Authorization(TAG_PADDING, PaddingMode::NONE)
.Authorization(TAG_DIGEST, Digest::NONE);
while (true) { while (true) {
op = dev.begin(KeyPurpose::SIGN, key, paramBuilder, &outParams); op = dev.begin(km::KeyPurpose::SIGN, key, paramBuilder, km::HardwareAuthToken(), &outParams);
if (op.errorCode() == ErrorCode::KEY_RATE_LIMIT_EXCEEDED) { if (op.errorCode() == km::ErrorCode::KEY_RATE_LIMIT_EXCEEDED) {
sleep(ratelimit); sleep(ratelimit);
continue; continue;
} else } else
break; break;
} }
if (op.errorCode() == ErrorCode::KEY_REQUIRES_UPGRADE) { if (op.errorCode() == km::ErrorCode::KEY_REQUIRES_UPGRADE) {
LOG(ERROR) << "Keymaster key requires upgrade"; LOG(ERROR) << "Keymaster key requires upgrade";
return KeymasterSignResult::upgrade; return KeymasterSignResult::upgrade;
} }
if (op.errorCode() != ErrorCode::OK) { if (op.errorCode() != km::ErrorCode::OK) {
LOG(ERROR) << "Error starting keymaster signature transaction: " << int32_t(op.errorCode()); LOG(ERROR) << "Error starting keymaster signature transaction: " << int32_t(op.errorCode());
return KeymasterSignResult::error; return KeymasterSignResult::error;
} }

View file

@ -24,16 +24,14 @@
#include <utility> #include <utility>
#include <android-base/macros.h> #include <android-base/macros.h>
#include <android/hardware/keymaster/3.0/IKeymasterDevice.h> #include <keymasterV4_0/Keymaster.h>
#include <keymasterV4_0/authorization_set.h>
#include "authorization_set.h"
namespace android { namespace android {
namespace vold { namespace vold {
using ::android::hardware::keymaster::V3_0::IKeymasterDevice;
using ::keystore::ErrorCode; namespace km = ::android::hardware::keymaster::V4_0;
using ::keystore::KeyPurpose; using KmDevice = km::support::Keymaster;
using ::keystore::AuthorizationSet;
// C++ wrappers to the Keymaster hidl interface. // C++ wrappers to the Keymaster hidl interface.
// This is tailored to the needs of KeyStorage, but could be extended to be // This is tailored to the needs of KeyStorage, but could be extended to be
@ -48,8 +46,8 @@ class KeymasterOperation {
~KeymasterOperation(); ~KeymasterOperation();
// Is this instance valid? This is false if creation fails, and becomes // Is this instance valid? This is false if creation fails, and becomes
// false on finish or if an update fails. // false on finish or if an update fails.
explicit operator bool() { return mError == ErrorCode::OK; } explicit operator bool() { return mError == km::ErrorCode::OK; }
ErrorCode errorCode() { return mError; } km::ErrorCode errorCode() { return mError; }
// Call "update" repeatedly until all of the input is consumed, and // Call "update" repeatedly until all of the input is consumed, and
// concatenate the output. Return true on success. // concatenate the output. Return true on success.
template <class TI, class TO> template <class TI, class TO>
@ -63,34 +61,30 @@ class KeymasterOperation {
// Finish and write the output to this string, unless pointer is null. // Finish and write the output to this string, unless pointer is null.
bool finish(std::string* output); bool finish(std::string* output);
// Move constructor // Move constructor
KeymasterOperation(KeymasterOperation&& rhs) { KeymasterOperation(KeymasterOperation&& rhs) { *this = std::move(rhs); }
mDevice = std::move(rhs.mDevice);
mOpHandle = std::move(rhs.mOpHandle);
mError = std::move(rhs.mError);
}
// Construct an object in an error state for error returns // Construct an object in an error state for error returns
KeymasterOperation() : mDevice{nullptr}, mOpHandle{0}, mError{ErrorCode::UNKNOWN_ERROR} {} KeymasterOperation() : mDevice{nullptr}, mOpHandle{0}, mError{km::ErrorCode::UNKNOWN_ERROR} {}
// Move Assignment // Move Assignment
KeymasterOperation& operator=(KeymasterOperation&& rhs) { KeymasterOperation& operator=(KeymasterOperation&& rhs) {
mDevice = std::move(rhs.mDevice); mDevice = std::move(rhs.mDevice);
mOpHandle = std::move(rhs.mOpHandle); mOpHandle = std::move(rhs.mOpHandle);
mError = std::move(rhs.mError); mError = std::move(rhs.mError);
rhs.mError = ErrorCode::UNKNOWN_ERROR; rhs.mError = km::ErrorCode::UNKNOWN_ERROR;
rhs.mOpHandle = 0; rhs.mOpHandle = 0;
return *this; return *this;
} }
private: private:
KeymasterOperation(const sp<IKeymasterDevice>& d, uint64_t h) KeymasterOperation(KmDevice* d, uint64_t h)
: mDevice{d}, mOpHandle{h}, mError{ErrorCode::OK} {} : mDevice{d}, mOpHandle{h}, mError{km::ErrorCode::OK} {}
KeymasterOperation(ErrorCode error) : mDevice{nullptr}, mOpHandle{0}, mError{error} {} KeymasterOperation(km::ErrorCode error) : mDevice{nullptr}, mOpHandle{0}, mError{error} {}
bool updateCompletely(const char* input, size_t inputLen, bool updateCompletely(const char* input, size_t inputLen,
const std::function<void(const char*, size_t)> consumer); const std::function<void(const char*, size_t)> consumer);
sp<IKeymasterDevice> mDevice; KmDevice* mDevice;
uint64_t mOpHandle; uint64_t mOpHandle;
ErrorCode mError; km::ErrorCode mError;
DISALLOW_COPY_AND_ASSIGN(KeymasterOperation); DISALLOW_COPY_AND_ASSIGN(KeymasterOperation);
friend class Keymaster; friend class Keymaster;
}; };
@ -103,19 +97,21 @@ class Keymaster {
// false if we failed to open the keymaster device. // false if we failed to open the keymaster device.
explicit operator bool() { return mDevice.get() != nullptr; } explicit operator bool() { return mDevice.get() != nullptr; }
// Generate a key in the keymaster from the given params. // Generate a key in the keymaster from the given params.
bool generateKey(const AuthorizationSet& inParams, std::string* key); bool generateKey(const km::AuthorizationSet& inParams, std::string* key);
// If the keymaster supports it, permanently delete a key. // If the keymaster supports it, permanently delete a key.
bool deleteKey(const std::string& key); bool deleteKey(const std::string& key);
// Replace stored key blob in response to KM_ERROR_KEY_REQUIRES_UPGRADE. // Replace stored key blob in response to KM_ERROR_KEY_REQUIRES_UPGRADE.
bool upgradeKey(const std::string& oldKey, const AuthorizationSet& inParams, bool upgradeKey(const std::string& oldKey, const km::AuthorizationSet& inParams,
std::string* newKey); std::string* newKey);
// Begin a new cryptographic operation, collecting output parameters if pointer is non-null // Begin a new cryptographic operation, collecting output parameters if pointer is non-null
KeymasterOperation begin(KeyPurpose purpose, const std::string& key, KeymasterOperation begin(km::KeyPurpose purpose, const std::string& key,
const AuthorizationSet& inParams, AuthorizationSet* outParams); const km::AuthorizationSet& inParams,
const km::HardwareAuthToken& authToken,
km::AuthorizationSet* outParams);
bool isSecure(); bool isSecure();
private: private:
sp<hardware::keymaster::V3_0::IKeymasterDevice> mDevice; std::unique_ptr<KmDevice> mDevice;
DISALLOW_COPY_AND_ASSIGN(Keymaster); DISALLOW_COPY_AND_ASSIGN(Keymaster);
}; };

View file

@ -1,420 +0,0 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* 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 "authorization_set.h"
#include <assert.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <istream>
#include <limits>
#include <ostream>
#include <new>
namespace keystore {
inline bool keyParamLess(const KeyParameter& a, const KeyParameter& b) {
if (a.tag != b.tag) return a.tag < b.tag;
int retval;
switch (typeFromTag(a.tag)) {
case TagType::INVALID:
case TagType::BOOL:
return false;
case TagType::ENUM:
case TagType::ENUM_REP:
case TagType::UINT:
case TagType::UINT_REP:
return a.f.integer < b.f.integer;
case TagType::ULONG:
case TagType::ULONG_REP:
return a.f.longInteger < b.f.longInteger;
case TagType::DATE:
return a.f.dateTime < b.f.dateTime;
case TagType::BIGNUM:
case TagType::BYTES:
// Handle the empty cases.
if (a.blob.size() == 0) return b.blob.size() != 0;
if (b.blob.size() == 0) return false;
retval = memcmp(&a.blob[0], &b.blob[0], std::min(a.blob.size(), b.blob.size()));
// if one is the prefix of the other the longer wins
if (retval == 0) return a.blob.size() < b.blob.size();
// Otherwise a is less if a is less.
else
return retval < 0;
}
return false;
}
inline bool keyParamEqual(const KeyParameter& a, const KeyParameter& b) {
if (a.tag != b.tag) return false;
switch (typeFromTag(a.tag)) {
case TagType::INVALID:
case TagType::BOOL:
return true;
case TagType::ENUM:
case TagType::ENUM_REP:
case TagType::UINT:
case TagType::UINT_REP:
return a.f.integer == b.f.integer;
case TagType::ULONG:
case TagType::ULONG_REP:
return a.f.longInteger == b.f.longInteger;
case TagType::DATE:
return a.f.dateTime == b.f.dateTime;
case TagType::BIGNUM:
case TagType::BYTES:
if (a.blob.size() != b.blob.size()) return false;
return a.blob.size() == 0 || memcmp(&a.blob[0], &b.blob[0], a.blob.size()) == 0;
}
return false;
}
void AuthorizationSet::Sort() {
std::sort(data_.begin(), data_.end(), keyParamLess);
}
void AuthorizationSet::Deduplicate() {
if (data_.empty()) return;
Sort();
std::vector<KeyParameter> result;
auto curr = data_.begin();
auto prev = curr++;
for (; curr != data_.end(); ++prev, ++curr) {
if (prev->tag == Tag::INVALID) continue;
if (!keyParamEqual(*prev, *curr)) {
result.emplace_back(std::move(*prev));
}
}
result.emplace_back(std::move(*prev));
std::swap(data_, result);
}
void AuthorizationSet::Union(const AuthorizationSet& other) {
data_.insert(data_.end(), other.data_.begin(), other.data_.end());
Deduplicate();
}
void AuthorizationSet::Subtract(const AuthorizationSet& other) {
Deduplicate();
auto i = other.begin();
while (i != other.end()) {
int pos = -1;
do {
pos = find(i->tag, pos);
if (pos != -1 && keyParamEqual(*i, data_[pos])) {
data_.erase(data_.begin() + pos);
break;
}
} while (pos != -1);
++i;
}
}
int AuthorizationSet::find(Tag tag, int begin) const {
auto iter = data_.begin() + (1 + begin);
while (iter != data_.end() && iter->tag != tag) ++iter;
if (iter != data_.end()) return iter - data_.begin();
return -1;
}
bool AuthorizationSet::erase(int index) {
auto pos = data_.begin() + index;
if (pos != data_.end()) {
data_.erase(pos);
return true;
}
return false;
}
KeyParameter& AuthorizationSet::operator[](int at) {
return data_[at];
}
const KeyParameter& AuthorizationSet::operator[](int at) const {
return data_[at];
}
void AuthorizationSet::Clear() {
data_.clear();
}
size_t AuthorizationSet::GetTagCount(Tag tag) const {
size_t count = 0;
for (int pos = -1; (pos = find(tag, pos)) != -1;) ++count;
return count;
}
NullOr<const KeyParameter&> AuthorizationSet::GetEntry(Tag tag) const {
int pos = find(tag);
if (pos == -1) return {};
return data_[pos];
}
/**
* Persistent format is:
* | 32 bit indirect_size |
* --------------------------------
* | indirect_size bytes of data | this is where the blob data is stored
* --------------------------------
* | 32 bit element_count | number of entries
* | 32 bit elements_size | total bytes used by entries (entries have variable length)
* --------------------------------
* | elementes_size bytes of data | where the elements are stored
*/
/**
* Persistent format of blobs and bignums:
* | 32 bit tag |
* | 32 bit blob_length |
* | 32 bit indirect_offset |
*/
struct OutStreams {
std::ostream& indirect;
std::ostream& elements;
};
OutStreams& serializeParamValue(OutStreams& out, const hidl_vec<uint8_t>& blob) {
uint32_t buffer;
// write blob_length
auto blob_length = blob.size();
if (blob_length > std::numeric_limits<uint32_t>::max()) {
out.elements.setstate(std::ios_base::badbit);
return out;
}
buffer = blob_length;
out.elements.write(reinterpret_cast<const char*>(&buffer), sizeof(uint32_t));
// write indirect_offset
auto offset = out.indirect.tellp();
if (offset < 0 || offset > std::numeric_limits<uint32_t>::max() ||
uint32_t(offset) + uint32_t(blob_length) < uint32_t(offset)) { // overflow check
out.elements.setstate(std::ios_base::badbit);
return out;
}
buffer = offset;
out.elements.write(reinterpret_cast<const char*>(&buffer), sizeof(uint32_t));
// write blob to indirect stream
if (blob_length) out.indirect.write(reinterpret_cast<const char*>(&blob[0]), blob_length);
return out;
}
template <typename T>
OutStreams& serializeParamValue(OutStreams& out, const T& value) {
out.elements.write(reinterpret_cast<const char*>(&value), sizeof(T));
return out;
}
OutStreams& serialize(TAG_INVALID_t&&, OutStreams& out, const KeyParameter&) {
// skip invalid entries.
return out;
}
template <typename T>
OutStreams& serialize(T ttag, OutStreams& out, const KeyParameter& param) {
out.elements.write(reinterpret_cast<const char*>(&param.tag), sizeof(int32_t));
return serializeParamValue(out, accessTagValue(ttag, param));
}
template <typename... T>
struct choose_serializer;
template <typename... Tags>
struct choose_serializer<MetaList<Tags...>> {
static OutStreams& serialize(OutStreams& out, const KeyParameter& param) {
return choose_serializer<Tags...>::serialize(out, param);
}
};
template <>
struct choose_serializer<> {
static OutStreams& serialize(OutStreams& out, const KeyParameter&) { return out; }
};
template <TagType tag_type, Tag tag, typename... Tail>
struct choose_serializer<TypedTag<tag_type, tag>, Tail...> {
static OutStreams& serialize(OutStreams& out, const KeyParameter& param) {
if (param.tag == tag) {
return keystore::serialize(TypedTag<tag_type, tag>(), out, param);
} else {
return choose_serializer<Tail...>::serialize(out, param);
}
}
};
OutStreams& serialize(OutStreams& out, const KeyParameter& param) {
return choose_serializer<all_tags_t>::serialize(out, param);
}
std::ostream& serialize(std::ostream& out, const std::vector<KeyParameter>& params) {
std::stringstream indirect;
std::stringstream elements;
OutStreams streams = {indirect, elements};
for (const auto& param : params) {
serialize(streams, param);
}
if (indirect.bad() || elements.bad()) {
out.setstate(std::ios_base::badbit);
return out;
}
auto pos = indirect.tellp();
if (pos < 0 || pos > std::numeric_limits<uint32_t>::max()) {
out.setstate(std::ios_base::badbit);
return out;
}
uint32_t indirect_size = pos;
pos = elements.tellp();
if (pos < 0 || pos > std::numeric_limits<uint32_t>::max()) {
out.setstate(std::ios_base::badbit);
return out;
}
uint32_t elements_size = pos;
uint32_t element_count = params.size();
out.write(reinterpret_cast<const char*>(&indirect_size), sizeof(uint32_t));
pos = out.tellp();
if (indirect_size) out << indirect.rdbuf();
assert(out.tellp() - pos == indirect_size);
out.write(reinterpret_cast<const char*>(&element_count), sizeof(uint32_t));
out.write(reinterpret_cast<const char*>(&elements_size), sizeof(uint32_t));
pos = out.tellp();
if (elements_size) out << elements.rdbuf();
assert(out.tellp() - pos == elements_size);
return out;
}
struct InStreams {
std::istream& indirect;
std::istream& elements;
};
InStreams& deserializeParamValue(InStreams& in, hidl_vec<uint8_t>* blob) {
uint32_t blob_length = 0;
uint32_t offset = 0;
in.elements.read(reinterpret_cast<char*>(&blob_length), sizeof(uint32_t));
blob->resize(blob_length);
in.elements.read(reinterpret_cast<char*>(&offset), sizeof(uint32_t));
in.indirect.seekg(offset);
in.indirect.read(reinterpret_cast<char*>(&(*blob)[0]), blob->size());
return in;
}
template <typename T>
InStreams& deserializeParamValue(InStreams& in, T* value) {
in.elements.read(reinterpret_cast<char*>(value), sizeof(T));
return in;
}
InStreams& deserialize(TAG_INVALID_t&&, InStreams& in, KeyParameter*) {
// there should be no invalid KeyParamaters but if handle them as zero sized.
return in;
}
template <typename T>
InStreams& deserialize(T&& ttag, InStreams& in, KeyParameter* param) {
return deserializeParamValue(in, &accessTagValue(ttag, *param));
}
template <typename... T>
struct choose_deserializer;
template <typename... Tags>
struct choose_deserializer<MetaList<Tags...>> {
static InStreams& deserialize(InStreams& in, KeyParameter* param) {
return choose_deserializer<Tags...>::deserialize(in, param);
}
};
template <>
struct choose_deserializer<> {
static InStreams& deserialize(InStreams& in, KeyParameter*) {
// encountered an unknown tag -> fail parsing
in.elements.setstate(std::ios_base::badbit);
return in;
}
};
template <TagType tag_type, Tag tag, typename... Tail>
struct choose_deserializer<TypedTag<tag_type, tag>, Tail...> {
static InStreams& deserialize(InStreams& in, KeyParameter* param) {
if (param->tag == tag) {
return keystore::deserialize(TypedTag<tag_type, tag>(), in, param);
} else {
return choose_deserializer<Tail...>::deserialize(in, param);
}
}
};
InStreams& deserialize(InStreams& in, KeyParameter* param) {
in.elements.read(reinterpret_cast<char*>(&param->tag), sizeof(Tag));
return choose_deserializer<all_tags_t>::deserialize(in, param);
}
std::istream& deserialize(std::istream& in, std::vector<KeyParameter>* params) {
uint32_t indirect_size = 0;
in.read(reinterpret_cast<char*>(&indirect_size), sizeof(uint32_t));
std::string indirect_buffer(indirect_size, '\0');
if (indirect_buffer.size() != indirect_size) {
in.setstate(std::ios_base::badbit);
return in;
}
in.read(&indirect_buffer[0], indirect_buffer.size());
uint32_t element_count = 0;
in.read(reinterpret_cast<char*>(&element_count), sizeof(uint32_t));
uint32_t elements_size = 0;
in.read(reinterpret_cast<char*>(&elements_size), sizeof(uint32_t));
std::string elements_buffer(elements_size, '\0');
if (elements_buffer.size() != elements_size) {
in.setstate(std::ios_base::badbit);
return in;
}
in.read(&elements_buffer[0], elements_buffer.size());
if (in.bad()) return in;
// TODO write one-shot stream buffer to avoid copying here
std::stringstream indirect(indirect_buffer);
std::stringstream elements(elements_buffer);
InStreams streams = {indirect, elements};
params->resize(element_count);
for (uint32_t i = 0; i < element_count; ++i) {
deserialize(streams, &(*params)[i]);
}
return in;
}
void AuthorizationSet::Serialize(std::ostream* out) const {
serialize(*out, data_);
}
void AuthorizationSet::Deserialize(std::istream* in) {
deserialize(*in, &data_);
}
} // namespace keystore

View file

@ -1,327 +0,0 @@
/*
* Copyright 2014 The Android Open Source Project
*
* 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.
*/
#ifndef SYSTEM_VOLD_AUTHORIZATION_SET_H_
#define SYSTEM_VOLD_AUTHORIZATION_SET_H_
#include <vector>
#include "keymaster_tags.h"
namespace keystore {
class AuthorizationSetBuilder;
/**
* An ordered collection of KeyParameters. It provides memory ownership and some convenient
* functionality for sorting, deduplicating, joining, and subtracting sets of KeyParameters.
* For serialization, wrap the backing store of this structure in a hidl_vec<KeyParameter>.
*/
class AuthorizationSet {
public:
/**
* Construct an empty, dynamically-allocated, growable AuthorizationSet.
*/
AuthorizationSet(){};
// Copy constructor.
AuthorizationSet(const AuthorizationSet& other) : data_(other.data_) {}
// Move constructor.
AuthorizationSet(AuthorizationSet&& other) : data_(std::move(other.data_)) {}
// Constructor from hidl_vec<KeyParameter>
AuthorizationSet(const hidl_vec<KeyParameter>& other) { *this = other; }
// Copy assignment.
AuthorizationSet& operator=(const AuthorizationSet& other) {
data_ = other.data_;
return *this;
}
// Move assignment.
AuthorizationSet& operator=(AuthorizationSet&& other) {
data_ = std::move(other.data_);
return *this;
}
AuthorizationSet& operator=(const hidl_vec<KeyParameter>& other) {
if (other.size() > 0) {
data_.resize(other.size());
for (size_t i = 0; i < data_.size(); ++i) {
/* This makes a deep copy even of embedded blobs.
* See assignment operator/copy constructor of hidl_vec.*/
data_[i] = other[i];
}
}
return *this;
}
/**
* Clear existing authorization set data
*/
void Clear();
~AuthorizationSet() = default;
/**
* Returns the size of the set.
*/
size_t size() const { return data_.size(); }
/**
* Returns true if the set is empty.
*/
bool empty() const { return size() == 0; }
/**
* Returns the data in the set, directly. Be careful with this.
*/
const KeyParameter* data() const { return data_.data(); }
/**
* Sorts the set
*/
void Sort();
/**
* Sorts the set and removes duplicates (inadvertently duplicating tags is easy to do with the
* AuthorizationSetBuilder).
*/
void Deduplicate();
/**
* Adds all elements from \p set that are not already present in this AuthorizationSet. As a
* side-effect, if \p set is not null this AuthorizationSet will end up sorted.
*/
void Union(const AuthorizationSet& set);
/**
* Removes all elements in \p set from this AuthorizationSet.
*/
void Subtract(const AuthorizationSet& set);
/**
* Returns the offset of the next entry that matches \p tag, starting from the element after \p
* begin. If not found, returns -1.
*/
int find(Tag tag, int begin = -1) const;
/**
* Removes the entry at the specified index. Returns true if successful, false if the index was
* out of bounds.
*/
bool erase(int index);
/**
* Returns iterator (pointer) to beginning of elems array, to enable STL-style iteration
*/
std::vector<KeyParameter>::const_iterator begin() const { return data_.begin(); }
/**
* Returns iterator (pointer) one past end of elems array, to enable STL-style iteration
*/
std::vector<KeyParameter>::const_iterator end() const { return data_.end(); }
/**
* Returns the nth element of the set.
* Like for std::vector::operator[] there is no range check performed. Use of out of range
* indices is undefined.
*/
KeyParameter& operator[](int n);
/**
* Returns the nth element of the set.
* Like for std::vector::operator[] there is no range check performed. Use of out of range
* indices is undefined.
*/
const KeyParameter& operator[](int n) const;
/**
* Returns true if the set contains at least one instance of \p tag
*/
bool Contains(Tag tag) const { return find(tag) != -1; }
template <TagType tag_type, Tag tag, typename ValueT>
bool Contains(TypedTag<tag_type, tag> ttag, const ValueT& value) const {
for (const auto& param : data_) {
auto entry = authorizationValue(ttag, param);
if (entry.isOk() && entry.value() == value) return true;
}
return false;
}
/**
* Returns the number of \p tag entries.
*/
size_t GetTagCount(Tag tag) const;
template <typename T>
inline NullOr<const typename TypedTag2ValueType<T>::type&> GetTagValue(T tag) const {
auto entry = GetEntry(tag);
if (entry.isOk()) return authorizationValue(tag, entry.value());
return {};
}
void push_back(const KeyParameter& param) { data_.push_back(param); }
void push_back(KeyParameter&& param) { data_.push_back(std::move(param)); }
/**
* Append the tag and enumerated value to the set.
* "val" may be exactly one parameter unless a boolean parameter is added.
* In this case "val" is omitted. This condition is checked at compile time by Authorization()
*/
template <typename TypedTagT, typename... Value>
void push_back(TypedTagT tag, Value&&... val) {
push_back(Authorization(tag, std::forward<Value>(val)...));
}
template <typename Iterator>
void append(Iterator begin, Iterator end) {
while (begin != end) {
push_back(*begin);
++begin;
}
}
hidl_vec<KeyParameter> hidl_data() const {
hidl_vec<KeyParameter> result;
result.setToExternal(const_cast<KeyParameter*>(data()), size());
return result;
}
void Serialize(std::ostream* out) const;
void Deserialize(std::istream* in);
private:
NullOr<const KeyParameter&> GetEntry(Tag tag) const;
std::vector<KeyParameter> data_;
};
class AuthorizationSetBuilder : public AuthorizationSet {
public:
template <typename TagType, typename... ValueType>
AuthorizationSetBuilder& Authorization(TagType ttag, ValueType&&... value) {
push_back(ttag, std::forward<ValueType>(value)...);
return *this;
}
template <Tag tag>
AuthorizationSetBuilder& Authorization(TypedTag<TagType::BYTES, tag> ttag, const uint8_t* data,
size_t data_length) {
hidl_vec<uint8_t> new_blob;
new_blob.setToExternal(const_cast<uint8_t*>(data), data_length);
push_back(ttag, std::move(new_blob));
return *this;
}
template <Tag tag>
AuthorizationSetBuilder& Authorization(TypedTag<TagType::BYTES, tag> ttag, const char* data,
size_t data_length) {
return Authorization(ttag, reinterpret_cast<const uint8_t*>(data), data_length);
}
AuthorizationSetBuilder& RsaKey(uint32_t key_size, uint64_t public_exponent);
AuthorizationSetBuilder& EcdsaKey(uint32_t key_size);
AuthorizationSetBuilder& AesKey(uint32_t key_size);
AuthorizationSetBuilder& HmacKey(uint32_t key_size);
AuthorizationSetBuilder& RsaSigningKey(uint32_t key_size, uint64_t public_exponent);
AuthorizationSetBuilder& RsaEncryptionKey(uint32_t key_size, uint64_t public_exponent);
AuthorizationSetBuilder& EcdsaSigningKey(uint32_t key_size);
AuthorizationSetBuilder& AesEncryptionKey(uint32_t key_size);
AuthorizationSetBuilder& SigningKey();
AuthorizationSetBuilder& EncryptionKey();
AuthorizationSetBuilder& NoDigestOrPadding();
AuthorizationSetBuilder& EcbMode();
AuthorizationSetBuilder& Digest(Digest digest) { return Authorization(TAG_DIGEST, digest); }
AuthorizationSetBuilder& Padding(PaddingMode padding) {
return Authorization(TAG_PADDING, padding);
}
};
inline AuthorizationSetBuilder& AuthorizationSetBuilder::RsaKey(uint32_t key_size,
uint64_t public_exponent) {
Authorization(TAG_ALGORITHM, Algorithm::RSA);
Authorization(TAG_KEY_SIZE, key_size);
Authorization(TAG_RSA_PUBLIC_EXPONENT, public_exponent);
return *this;
}
inline AuthorizationSetBuilder& AuthorizationSetBuilder::EcdsaKey(uint32_t key_size) {
Authorization(TAG_ALGORITHM, Algorithm::EC);
Authorization(TAG_KEY_SIZE, key_size);
return *this;
}
inline AuthorizationSetBuilder& AuthorizationSetBuilder::AesKey(uint32_t key_size) {
Authorization(TAG_ALGORITHM, Algorithm::AES);
return Authorization(TAG_KEY_SIZE, key_size);
}
inline AuthorizationSetBuilder& AuthorizationSetBuilder::HmacKey(uint32_t key_size) {
Authorization(TAG_ALGORITHM, Algorithm::HMAC);
Authorization(TAG_KEY_SIZE, key_size);
return SigningKey();
}
inline AuthorizationSetBuilder& AuthorizationSetBuilder::RsaSigningKey(uint32_t key_size,
uint64_t public_exponent) {
RsaKey(key_size, public_exponent);
return SigningKey();
}
inline AuthorizationSetBuilder& AuthorizationSetBuilder::RsaEncryptionKey(uint32_t key_size,
uint64_t public_exponent) {
RsaKey(key_size, public_exponent);
return EncryptionKey();
}
inline AuthorizationSetBuilder& AuthorizationSetBuilder::EcdsaSigningKey(uint32_t key_size) {
EcdsaKey(key_size);
return SigningKey();
}
inline AuthorizationSetBuilder& AuthorizationSetBuilder::AesEncryptionKey(uint32_t key_size) {
AesKey(key_size);
return EncryptionKey();
}
inline AuthorizationSetBuilder& AuthorizationSetBuilder::SigningKey() {
Authorization(TAG_PURPOSE, KeyPurpose::SIGN);
return Authorization(TAG_PURPOSE, KeyPurpose::VERIFY);
}
inline AuthorizationSetBuilder& AuthorizationSetBuilder::EncryptionKey() {
Authorization(TAG_PURPOSE, KeyPurpose::ENCRYPT);
return Authorization(TAG_PURPOSE, KeyPurpose::DECRYPT);
}
inline AuthorizationSetBuilder& AuthorizationSetBuilder::NoDigestOrPadding() {
Authorization(TAG_DIGEST, Digest::NONE);
return Authorization(TAG_PADDING, PaddingMode::NONE);
}
inline AuthorizationSetBuilder& AuthorizationSetBuilder::EcbMode() {
return Authorization(TAG_BLOCK_MODE, BlockMode::ECB);
}
} // namespace keystore
#endif // SYSTEM_VOLD_AUTHORIZATION_SET_H_

View file

@ -1,372 +0,0 @@
/*
* Copyright 2014 The Android Open Source Project
*
* 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.
*/
#ifndef SYSTEM_VOLD_KEYMASTER_TAGS_H_
#define SYSTEM_VOLD_KEYMASTER_TAGS_H_
/**
* This header contains various definitions that make working with keymaster tags safer and easier.
*
* It makes use of a fair amount of template metaprogramming. The metaprogramming serves the purpose
* of making it impossible to make certain classes of mistakes when operating on keymaster
* authorizations. For example, it's an error to create a KeyParameter with tag == Tag::PURPOSE
* and then to assign Algorithm::RSA to algorithm element of its union. But because the user
* must choose the union field, there could be a mismatch which the compiler has now way to
* diagnose.
*
* The machinery in this header solves these problems by describing which union field corresponds
* to which Tag. Central to this mechanism is the template TypedTag. It has zero size and binds a
* numeric Tag to a type that the compiler understands. By means of the macro DECLARE_TYPED_TAG,
* we declare types for each of the tags defined in hardware/interfaces/keymaster/2.0/types.hal.
*
* The macro DECLARE_TYPED_TAG(name) generates a typename TAG_name_t and a zero sized instance
* TAG_name. Once these typed tags have been declared we define metafunctions mapping the each tag
* to its value c++ type and the correct union element of KeyParameter. This is done by means of
* the macros MAKE_TAG_*VALUE_ACCESSOR, which generates TypedTag2ValueType, a metafunction mapping
* a typed tag to the corresponding c++ type, and access function, accessTagValue returning a
* reference to the correct element of KeyParameter.
* E.g.:
* given "KeyParameter param;" then "accessTagValue(TAG_PURPOSE, param)"
* yields a reference to param.f.purpose
* If used in an assignment the compiler can now check the compatibility of the assigned value.
*
* For convenience we also provide the constructor like function Authorization().
* Authorization takes a typed tag and a value and checks at compile time whether the value given
* is suitable for the given tag. At runtime it creates a new KeyParameter initialized with the
* given tag and value and returns it by value.
*
* The second convenience function, authorizationValue, allows access to the KeyParameter value in
* a safe way. It takes a typed tag and a KeyParameter and returns a reference to the value wrapped
* by NullOr. NullOr has out-of-band information about whether it is save to access the wrapped
* reference.
* E.g.:
* auto param = Authorization(TAG_ALGORITM, Algorithm::RSA);
* auto value1 = authorizationValue(TAG_PURPOSE, param);
* auto value2 = authorizationValue(TAG_ALGORITM, param);
* value1.isOk() yields false, but value2.isOk() yields true, thus value2.value() is save to access.
*/
#include <android/hardware/keymaster/3.0/IHwKeymasterDevice.h>
#include <hardware/hw_auth_token.h>
#include <type_traits>
namespace keystore {
using ::android::hardware::keymaster::V3_0::Algorithm;
using ::android::hardware::keymaster::V3_0::BlockMode;
using ::android::hardware::keymaster::V3_0::Digest;
using ::android::hardware::keymaster::V3_0::EcCurve;
using ::android::hardware::keymaster::V3_0::ErrorCode;
using ::android::hardware::keymaster::V3_0::HardwareAuthToken;
using ::android::hardware::keymaster::V3_0::HardwareAuthenticatorType;
using ::android::hardware::keymaster::V3_0::IKeymasterDevice;
using ::android::hardware::keymaster::V3_0::KeyBlobUsageRequirements;
using ::android::hardware::keymaster::V3_0::KeyCharacteristics;
using ::android::hardware::keymaster::V3_0::KeyDerivationFunction;
using ::android::hardware::keymaster::V3_0::KeyFormat;
using ::android::hardware::keymaster::V3_0::KeyOrigin;
using ::android::hardware::keymaster::V3_0::KeyParameter;
using ::android::hardware::keymaster::V3_0::KeyPurpose;
using ::android::hardware::keymaster::V3_0::PaddingMode;
using ::android::hardware::keymaster::V3_0::Tag;
using ::android::hardware::keymaster::V3_0::TagType;
using ::android::hardware::hidl_vec;
using ::android::hardware::Return;
// The following create the numeric values that KM_TAG_PADDING and KM_TAG_DIGEST used to have. We
// need these old values to be able to support old keys that use them.
static const int32_t KM_TAG_DIGEST_OLD = static_cast<int32_t>(TagType::ENUM) | 5;
static const int32_t KM_TAG_PADDING_OLD = static_cast<int32_t>(TagType::ENUM) | 7;
constexpr TagType typeFromTag(Tag tag) {
return static_cast<TagType>(static_cast<uint32_t>(tag) & static_cast<uint32_t>(0xf0000000));
}
/**
* TypedTag is a templatized version of Tag, which provides compile-time checking of
* keymaster tag types. Instances are convertible to Tag, so they can be used wherever
* Tag is expected, and because they encode the tag type it's possible to create
* function overloads that only operate on tags with a particular type.
*/
template <TagType tag_type, Tag tag>
struct TypedTag {
inline TypedTag() {
// Ensure that it's impossible to create a TypedTag instance whose 'tag' doesn't have type
// 'tag_type'. Attempting to instantiate a tag with the wrong type will result in a compile
// error (no match for template specialization StaticAssert<false>), with no run-time cost.
static_assert(typeFromTag(tag) == tag_type, "mismatch between tag and tag_type");
}
operator Tag() const { return tag; }
};
template <Tag tag>
struct Tag2TypedTag {
typedef TypedTag<typeFromTag(tag), tag> type;
};
template <Tag tag>
struct Tag2String;
#define _TAGS_STRINGIFY(x) #x
#define TAGS_STRINGIFY(x) _TAGS_STRINGIFY(x)
#define DECLARE_TYPED_TAG(name) \
typedef typename Tag2TypedTag<Tag::name>::type TAG_##name##_t; \
extern TAG_##name##_t TAG_##name; \
template <> \
struct Tag2String<Tag::name> { \
static const char* value() { return "Tag::" TAGS_STRINGIFY(name); } \
}
DECLARE_TYPED_TAG(INVALID);
DECLARE_TYPED_TAG(KEY_SIZE);
DECLARE_TYPED_TAG(MAC_LENGTH);
DECLARE_TYPED_TAG(CALLER_NONCE);
DECLARE_TYPED_TAG(MIN_MAC_LENGTH);
DECLARE_TYPED_TAG(RSA_PUBLIC_EXPONENT);
DECLARE_TYPED_TAG(ECIES_SINGLE_HASH_MODE);
DECLARE_TYPED_TAG(INCLUDE_UNIQUE_ID);
DECLARE_TYPED_TAG(ACTIVE_DATETIME);
DECLARE_TYPED_TAG(ORIGINATION_EXPIRE_DATETIME);
DECLARE_TYPED_TAG(USAGE_EXPIRE_DATETIME);
DECLARE_TYPED_TAG(MIN_SECONDS_BETWEEN_OPS);
DECLARE_TYPED_TAG(MAX_USES_PER_BOOT);
DECLARE_TYPED_TAG(ALL_USERS);
DECLARE_TYPED_TAG(USER_ID);
DECLARE_TYPED_TAG(USER_SECURE_ID);
DECLARE_TYPED_TAG(NO_AUTH_REQUIRED);
DECLARE_TYPED_TAG(AUTH_TIMEOUT);
DECLARE_TYPED_TAG(ALLOW_WHILE_ON_BODY);
DECLARE_TYPED_TAG(ALL_APPLICATIONS);
DECLARE_TYPED_TAG(APPLICATION_ID);
DECLARE_TYPED_TAG(APPLICATION_DATA);
DECLARE_TYPED_TAG(CREATION_DATETIME);
DECLARE_TYPED_TAG(ROLLBACK_RESISTANT);
DECLARE_TYPED_TAG(ROOT_OF_TRUST);
DECLARE_TYPED_TAG(ASSOCIATED_DATA);
DECLARE_TYPED_TAG(NONCE);
DECLARE_TYPED_TAG(AUTH_TOKEN);
DECLARE_TYPED_TAG(BOOTLOADER_ONLY);
DECLARE_TYPED_TAG(OS_VERSION);
DECLARE_TYPED_TAG(OS_PATCHLEVEL);
DECLARE_TYPED_TAG(UNIQUE_ID);
DECLARE_TYPED_TAG(ATTESTATION_CHALLENGE);
DECLARE_TYPED_TAG(ATTESTATION_APPLICATION_ID);
DECLARE_TYPED_TAG(RESET_SINCE_ID_ROTATION);
DECLARE_TYPED_TAG(PURPOSE);
DECLARE_TYPED_TAG(ALGORITHM);
DECLARE_TYPED_TAG(BLOCK_MODE);
DECLARE_TYPED_TAG(DIGEST);
DECLARE_TYPED_TAG(PADDING);
DECLARE_TYPED_TAG(BLOB_USAGE_REQUIREMENTS);
DECLARE_TYPED_TAG(ORIGIN);
DECLARE_TYPED_TAG(USER_AUTH_TYPE);
DECLARE_TYPED_TAG(KDF);
DECLARE_TYPED_TAG(EC_CURVE);
template <typename... Elems>
struct MetaList {};
using all_tags_t = MetaList<
TAG_INVALID_t, TAG_KEY_SIZE_t, TAG_MAC_LENGTH_t, TAG_CALLER_NONCE_t, TAG_MIN_MAC_LENGTH_t,
TAG_RSA_PUBLIC_EXPONENT_t, TAG_ECIES_SINGLE_HASH_MODE_t, TAG_INCLUDE_UNIQUE_ID_t,
TAG_ACTIVE_DATETIME_t, TAG_ORIGINATION_EXPIRE_DATETIME_t, TAG_USAGE_EXPIRE_DATETIME_t,
TAG_MIN_SECONDS_BETWEEN_OPS_t, TAG_MAX_USES_PER_BOOT_t, TAG_ALL_USERS_t, TAG_USER_ID_t,
TAG_USER_SECURE_ID_t, TAG_NO_AUTH_REQUIRED_t, TAG_AUTH_TIMEOUT_t, TAG_ALLOW_WHILE_ON_BODY_t,
TAG_ALL_APPLICATIONS_t, TAG_APPLICATION_ID_t, TAG_APPLICATION_DATA_t, TAG_CREATION_DATETIME_t,
TAG_ROLLBACK_RESISTANT_t, TAG_ROOT_OF_TRUST_t, TAG_ASSOCIATED_DATA_t, TAG_NONCE_t,
TAG_AUTH_TOKEN_t, TAG_BOOTLOADER_ONLY_t, TAG_OS_VERSION_t, TAG_OS_PATCHLEVEL_t, TAG_UNIQUE_ID_t,
TAG_ATTESTATION_CHALLENGE_t, TAG_ATTESTATION_APPLICATION_ID_t, TAG_RESET_SINCE_ID_ROTATION_t,
TAG_PURPOSE_t, TAG_ALGORITHM_t, TAG_BLOCK_MODE_t, TAG_DIGEST_t, TAG_PADDING_t,
TAG_BLOB_USAGE_REQUIREMENTS_t, TAG_ORIGIN_t, TAG_USER_AUTH_TYPE_t, TAG_KDF_t, TAG_EC_CURVE_t>;
/* implementation in keystore_utils.cpp */
extern const char* stringifyTag(Tag tag);
template <typename TypedTagType>
struct TypedTag2ValueType;
#define MAKE_TAG_VALUE_ACCESSOR(tag_type, field_name) \
template <Tag tag> \
struct TypedTag2ValueType<TypedTag<tag_type, tag>> { \
typedef decltype(static_cast<KeyParameter*>(nullptr)->field_name) type; \
}; \
template <Tag tag> \
inline auto accessTagValue(TypedTag<tag_type, tag>, const KeyParameter& param) \
->const decltype(param.field_name)& { \
return param.field_name; \
} \
template <Tag tag> \
inline auto accessTagValue(TypedTag<tag_type, tag>, KeyParameter& param) \
->decltype(param.field_name)& { \
return param.field_name; \
}
MAKE_TAG_VALUE_ACCESSOR(TagType::ULONG, f.longInteger)
MAKE_TAG_VALUE_ACCESSOR(TagType::ULONG_REP, f.longInteger)
MAKE_TAG_VALUE_ACCESSOR(TagType::DATE, f.dateTime)
MAKE_TAG_VALUE_ACCESSOR(TagType::UINT, f.integer)
MAKE_TAG_VALUE_ACCESSOR(TagType::UINT_REP, f.integer)
MAKE_TAG_VALUE_ACCESSOR(TagType::BOOL, f.boolValue)
MAKE_TAG_VALUE_ACCESSOR(TagType::BYTES, blob)
MAKE_TAG_VALUE_ACCESSOR(TagType::BIGNUM, blob)
#define MAKE_TAG_ENUM_VALUE_ACCESSOR(typed_tag, field_name) \
template <> \
struct TypedTag2ValueType<decltype(typed_tag)> { \
typedef decltype(static_cast<KeyParameter*>(nullptr)->field_name) type; \
}; \
inline auto accessTagValue(decltype(typed_tag), const KeyParameter& param) \
->const decltype(param.field_name)& { \
return param.field_name; \
} \
inline auto accessTagValue(decltype(typed_tag), KeyParameter& param) \
->decltype(param.field_name)& { \
return param.field_name; \
}
MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_ALGORITHM, f.algorithm)
MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_BLOB_USAGE_REQUIREMENTS, f.keyBlobUsageRequirements)
MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_BLOCK_MODE, f.blockMode)
MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_DIGEST, f.digest)
MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_EC_CURVE, f.ecCurve)
MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_KDF, f.keyDerivationFunction)
MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_ORIGIN, f.origin)
MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_PADDING, f.paddingMode)
MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_PURPOSE, f.purpose)
MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_USER_AUTH_TYPE, f.hardwareAuthenticatorType)
template <TagType tag_type, Tag tag, typename ValueT>
inline KeyParameter makeKeyParameter(TypedTag<tag_type, tag> ttag, ValueT&& value) {
KeyParameter param;
param.tag = tag;
param.f.longInteger = 0;
accessTagValue(ttag, param) = std::forward<ValueT>(value);
return param;
}
// the boolean case
template <Tag tag>
inline KeyParameter makeKeyParameter(TypedTag<TagType::BOOL, tag>) {
KeyParameter param;
param.tag = tag;
param.f.boolValue = true;
return param;
}
template <typename... Pack>
struct FirstOrNoneHelper;
template <typename First>
struct FirstOrNoneHelper<First> {
typedef First type;
};
template <>
struct FirstOrNoneHelper<> {
struct type {};
};
template <typename... Pack>
using FirstOrNone = typename FirstOrNoneHelper<Pack...>::type;
template <TagType tag_type, Tag tag, typename... Args>
inline KeyParameter Authorization(TypedTag<tag_type, tag> ttag, Args&&... args) {
static_assert(tag_type != TagType::BOOL || (sizeof...(args) == 0),
"TagType::BOOL Authorizations do not take parameters. Presence is truth.");
static_assert(tag_type == TagType::BOOL || (sizeof...(args) == 1),
"Authorization other then TagType::BOOL take exactly one parameter.");
static_assert(
tag_type == TagType::BOOL ||
std::is_convertible<std::remove_cv_t<std::remove_reference_t<FirstOrNone<Args...>>>,
typename TypedTag2ValueType<TypedTag<tag_type, tag>>::type>::value,
"Invalid argument type for given tag.");
return makeKeyParameter(ttag, std::forward<Args>(args)...);
}
/**
* This class wraps a (mostly return) value and stores whether or not the wrapped value is valid out
* of band. Note that if the wrapped value is a reference it is unsafe to access the value if
* !isOk(). If the wrapped type is a pointer or value and !isOk(), it is still safe to access the
* wrapped value. In this case the pointer will be NULL though, and the value will be default
* constructed.
*/
template <typename ValueT>
class NullOr {
template <typename T>
struct reference_initializer {
static T&& init() { return *static_cast<std::remove_reference_t<T>*>(nullptr); }
};
template <typename T>
struct pointer_initializer {
static T init() { return nullptr; }
};
template <typename T>
struct value_initializer {
static T init() { return T(); }
};
template <typename T>
using initializer_t = std::conditional_t<
std::is_lvalue_reference<T>::value, reference_initializer<T>,
std::conditional_t<std::is_pointer<T>::value, pointer_initializer<T>, value_initializer<T>>>;
public:
NullOr() : value_(initializer_t<ValueT>::init()), null_(true) {}
NullOr(ValueT&& value) : value_(std::forward<ValueT>(value)), null_(false) {}
bool isOk() const { return !null_; }
const ValueT& value() const & { return value_; }
ValueT& value() & { return value_; }
ValueT&& value() && { return std::move(value_); }
private:
ValueT value_;
bool null_;
};
template <typename T>
std::remove_reference_t<T> NullOrOr(T&& v) {
if (v.isOk()) return v;
return {};
}
template <typename Head, typename... Tail>
std::remove_reference_t<Head> NullOrOr(Head&& head, Tail&&... tail) {
if (head.isOk()) return head;
return NullOrOr(std::forward<Tail>(tail)...);
}
template <typename Default, typename Wrapped>
std::remove_reference_t<Wrapped> defaultOr(NullOr<Wrapped>&& optional, Default&& def) {
static_assert(
std::is_convertible<std::remove_reference_t<Default>, std::remove_reference_t<Wrapped>>::value,
"Type of default value must match the type wrapped by NullOr");
if (optional.isOk()) return optional.value();
return def;
}
template <TagType tag_type, Tag tag>
inline NullOr<const typename TypedTag2ValueType<TypedTag<tag_type, tag>>::type&> authorizationValue(
TypedTag<tag_type, tag> ttag, const KeyParameter& param) {
if (tag != param.tag) return {};
return accessTagValue(ttag, param);
}
} // namespace keystore
#endif // SYSTEM_SECURITY_KEYSTORE_KEYMASTER_TAGS_H_

View file

@ -1,108 +0,0 @@
/*
**
** Copyright 2016, The Android Open Source Project
**
** 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.
*/
#ifndef SYSTEM_VOLD_KEYSTORE_HIDL_SUPPORT_H_
#define SYSTEM_VOLD_KEYSTORE_HIDL_SUPPORT_H_
#include <ostream>
#include <sstream>
#include <string>
#include <hidl/Status.h>
#include "keymaster_tags.h"
namespace keystore {
inline static std::ostream& formatArgs(std::ostream& out) {
return out;
}
template <typename First, typename... Args>
inline static std::ostream& formatArgs(std::ostream& out, First&& first, Args&&... args) {
out << first;
return formatArgs(out, args...);
}
template <typename... Args>
inline static std::string argsToString(Args&&... args) {
std::stringstream s;
formatArgs(s, args...);
return s.str();
}
template <typename... Msgs>
inline static ErrorCode ksHandleHidlError(const Return<ErrorCode>& error, Msgs&&... msgs) {
if (!error.isOk()) {
ALOGE("HIDL call failed with %s @ %s", error.description().c_str(),
argsToString(msgs...).c_str());
return ErrorCode::UNKNOWN_ERROR;
}
return ErrorCode(error);
}
template <typename... Msgs>
inline static ErrorCode ksHandleHidlError(const Return<void>& error, Msgs&&... msgs) {
if (!error.isOk()) {
ALOGE("HIDL call failed with %s @ %s", error.description().c_str(),
argsToString(msgs...).c_str());
return ErrorCode::UNKNOWN_ERROR;
}
return ErrorCode::OK;
}
#define KS_HANDLE_HIDL_ERROR(rc) \
::keystore::ksHandleHidlError(rc, __FILE__, ":", __LINE__, ":", __PRETTY_FUNCTION__)
inline static hidl_vec<uint8_t> blob2hidlVec(const uint8_t* data, const size_t length,
bool inPlace = true) {
hidl_vec<uint8_t> result;
if (inPlace)
result.setToExternal(const_cast<unsigned char*>(data), length);
else {
result.resize(length);
memcpy(&result[0], data, length);
}
return result;
}
inline static hidl_vec<uint8_t> blob2hidlVec(const std::string& value) {
hidl_vec<uint8_t> result;
result.setToExternal(
reinterpret_cast<uint8_t*>(const_cast<std::string::value_type*>(value.data())),
static_cast<size_t>(value.size()));
return result;
}
inline static hidl_vec<uint8_t> blob2hidlVec(const std::vector<uint8_t>& blob) {
hidl_vec<uint8_t> result;
result.setToExternal(const_cast<uint8_t*>(blob.data()), static_cast<size_t>(blob.size()));
return result;
}
template <typename T, typename OutIter>
inline static OutIter copy_bytes_to_iterator(const T& value, OutIter dest) {
const uint8_t* value_ptr = reinterpret_cast<const uint8_t*>(&value);
return std::copy(value_ptr, value_ptr + sizeof(value), dest);
}
inline std::string hidlVec2String(const hidl_vec<uint8_t>& value) {
return std::string(reinterpret_cast<const std::string::value_type*>(&value[0]), value.size());
}
} // namespace keystore
#endif // SYSTEM_VOLD_KEYSTORE_HIDL_SUPPORT_H_