Break vold dependency on keystore utilities.

This is temporary.  Keystore is in the process of being upgraded to use
the new Keymaster 4.0 HAL, and I want to leave vold alone, using
Keymaster 3.0 for the moment.  This CL just copies relevant bits of
keystore support utilities into vold, so it can stop depending on the
copies from keystore.

After the keystore update is complete, vold will be changed either to
use Keymaster 4.0 or -- more likely -- to use keystore rather than
talking to Keymaster directly.  At that point the files added by this CL
will be deleted.

Test: Device boots and successfully decrypts /data
Change-Id: I73f6d4cc4c5e20d89d7ac37d29d025bf279f9e12
This commit is contained in:
Shawn Willden 2017-11-09 15:59:39 -07:00
parent b64933a502
commit f452774030
8 changed files with 1237 additions and 7 deletions

View file

@ -50,7 +50,6 @@ cc_defaults {
"libhardware_legacy",
"libhidlbase",
"libhwbinder",
"libkeystore_binder",
"libkeyutils",
"liblog",
"liblogwrap",
@ -111,6 +110,7 @@ cc_library_static {
"VoldNativeService.cpp",
"VoldUtil.cpp",
"VolumeManager.cpp",
"authorization_set.cpp",
"cryptfs.cpp",
"fs/Ext4.cpp",
"fs/F2fs.cpp",

View file

@ -40,14 +40,15 @@
#include <hardware/hw_auth_token.h>
#include <keystore/authorization_set.h>
#include <keystore/keystore_hidl_support.h>
extern "C" {
#include "crypto_scrypt.h"
}
#include "authorization_set.h"
#include "keystore_hidl_support.h"
namespace android {
namespace vold {
using namespace keystore;

View file

@ -17,9 +17,10 @@
#include "Keymaster.h"
#include <android-base/logging.h>
#include <keystore/keymaster_tags.h>
#include <keystore/authorization_set.h>
#include <keystore/keystore_hidl_support.h>
#include "authorization_set.h"
#include "keymaster_tags.h"
#include "keystore_hidl_support.h"
using namespace ::keystore;
using android::hardware::hidl_string;

View file

@ -25,7 +25,8 @@
#include <android/hardware/keymaster/3.0/IKeymasterDevice.h>
#include <android-base/macros.h>
#include <keystore/authorization_set.h>
#include "authorization_set.h"
namespace android {
namespace vold {

420
authorization_set.cpp Normal file
View file

@ -0,0 +1,420 @@
/*
* 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

327
authorization_set.h Normal file
View file

@ -0,0 +1,327 @@
/*
* 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_

372
keymaster_tags.h Normal file
View file

@ -0,0 +1,372 @@
/*
* 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_

108
keystore_hidl_support.h Normal file
View file

@ -0,0 +1,108 @@
/*
**
** 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_