/* * 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_KEYMASTER_ANDROID_KEYMASTER_UTILS_H_ #define SYSTEM_KEYMASTER_ANDROID_KEYMASTER_UTILS_H_ #include #include #include // for time_t. #include #include #include namespace keymaster { /** * Convert the specified time value into "Java time", which is a signed 64-bit integer representing * elapsed milliseconds since Jan 1, 1970. */ inline int64_t java_time(time_t time) { // The exact meaning of a time_t value is implementation-dependent. If this code is ported to a // platform that doesn't define it as "seconds since Jan 1, 1970 UTC", this function will have // to be revised. return time * 1000; } /* * Array Manipulation functions. This set of templated inline functions provides some nice tools * for operating on c-style arrays. C-style arrays actually do have a defined size associated with * them, as long as they are not allowed to decay to a pointer. These template methods exploit this * to allow size-based array operations without explicitly specifying the size. If passed a pointer * rather than an array, they'll fail to compile. */ /** * Return the size in bytes of the array \p a. */ template inline size_t array_size(const T (&a)[N]) { return sizeof(a); } /** * Return the number of elements in array \p a. */ template inline size_t array_length(const T (&)[N]) { return N; } /** * Duplicate the array \p a. The memory for the new array is allocated and the caller takes * responsibility. */ template inline T* dup_array(const T* a, size_t n) { T* dup = new (std::nothrow) T[n]; if (dup) for (size_t i = 0; i < n; ++i) dup[i] = a[i]; return dup; } /** * Duplicate the array \p a. The memory for the new array is allocated and the caller takes * responsibility. Note that the dup is necessarily returned as a pointer, so size is lost. Call * array_length() on the original array to discover the size. */ template inline T* dup_array(const T (&a)[N]) { return dup_array(a, N); } /** * Duplicate the buffer \p buf. The memory for the new buffer is allocated and the caller takes * responsibility. */ uint8_t* dup_buffer(const void* buf, size_t size); /** * Copy the contents of array \p arr to \p dest. */ template inline void copy_array(const T (&arr)[N], T* dest) { for (size_t i = 0; i < N; ++i) dest[i] = arr[i]; } /** * Search array \p a for value \p val, returning true if found. Note that this function is * early-exit, meaning that it should not be used in contexts where timing analysis attacks could be * a concern. */ template inline bool array_contains(const T (&a)[N], T val) { for (size_t i = 0; i < N; ++i) { if (a[i] == val) { return true; } } return false; } /** * Variant of memset() that uses GCC-specific pragmas to disable optimizations, so effect is not * optimized away. This is important because we often need to wipe blocks of sensitive data from * memory. As an additional convenience, this implementation avoids writing to NULL pointers. */ #ifdef __clang__ #define OPTNONE __attribute__((optnone)) #else // not __clang__ #define OPTNONE __attribute__((optimize("O0"))) #endif // not __clang__ inline OPTNONE void* memset_s(void* s, int c, size_t n) { if (!s) return s; return memset(s, c, n); } #undef OPTNONE /** * Variant of memcmp that has the same runtime regardless of whether the data matches (i.e. doesn't * short-circuit). Not an exact equivalent to memcmp because it doesn't return <0 if p1 < p2, just * 0 for match and non-zero for non-match. */ int memcmp_s(const void* p1, const void* p2, size_t length); /** * Eraser clears buffers. Construct it with a buffer or object and the destructor will ensure that * it is zeroed. */ class Eraser { public: /* Not implemented. If this gets used, we want a link error. */ template explicit Eraser(T* t); template explicit Eraser(T& t) : buf_(reinterpret_cast(&t)), size_(sizeof(t)) {} template explicit Eraser(uint8_t (&arr)[N]) : buf_(arr), size_(N) {} Eraser(void* buf, size_t size) : buf_(static_cast(buf)), size_(size) {} ~Eraser() { memset_s(buf_, 0, size_); } private: Eraser(const Eraser&); void operator=(const Eraser&); uint8_t* buf_; size_t size_; }; /** * ArrayWrapper is a trivial wrapper around a C-style array that provides begin() and end() * methods. This is primarily to facilitate range-based iteration on arrays. It does not copy, nor * does it take ownership; it just holds pointers. */ template class ArrayWrapper { public: ArrayWrapper(T* array, size_t size) : begin_(array), end_(array + size) {} T* begin() { return begin_; } T* end() { return end_; } private: T* begin_; T* end_; }; template ArrayWrapper array_range(T* begin, size_t length) { return ArrayWrapper(begin, length); } /** * Convert any unsigned integer from network to host order. We implement this here rather than * using the functions from arpa/inet.h because the TEE doesn't have inet.h. This isn't the most * efficient implementation, but the compiler should unroll the loop and tighten it up. */ template T ntoh(T t) { const uint8_t* byte_ptr = reinterpret_cast(&t); T retval = 0; for (size_t i = 0; i < sizeof(t); ++i) { retval <<= 8; retval |= byte_ptr[i]; } return retval; } /** * Convert any unsigned integer from host to network order. We implement this here rather than * using the functions from arpa/inet.h because the TEE doesn't have inet.h. This isn't the most * efficient implementation, but the compiler should unroll the loop and tighten it up. */ template T hton(T t) { T retval; uint8_t* byte_ptr = reinterpret_cast(&retval); for (size_t i = sizeof(t); i > 0; --i) { byte_ptr[i - 1] = t & 0xFF; t >>= 8; } return retval; } /** * KeymasterKeyBlob is a very simple extension of the C struct keymaster_key_blob_t. It manages its * own memory, which makes avoiding memory leaks much easier. */ struct KeymasterKeyBlob : public keymaster_key_blob_t { KeymasterKeyBlob() { key_material = nullptr; key_material_size = 0; } KeymasterKeyBlob(const uint8_t* data, size_t size) { key_material_size = 0; key_material = dup_buffer(data, size); if (key_material) key_material_size = size; } explicit KeymasterKeyBlob(size_t size) { key_material_size = 0; key_material = new (std::nothrow) uint8_t[size]; if (key_material) key_material_size = size; } explicit KeymasterKeyBlob(const keymaster_key_blob_t& blob) { key_material_size = 0; key_material = dup_buffer(blob.key_material, blob.key_material_size); if (key_material) key_material_size = blob.key_material_size; } KeymasterKeyBlob(const KeymasterKeyBlob& blob) { key_material_size = 0; key_material = dup_buffer(blob.key_material, blob.key_material_size); if (key_material) key_material_size = blob.key_material_size; } void operator=(const KeymasterKeyBlob& blob) { Clear(); key_material = dup_buffer(blob.key_material, blob.key_material_size); key_material_size = blob.key_material_size; } ~KeymasterKeyBlob() { Clear(); } const uint8_t* begin() const { return key_material; } const uint8_t* end() const { return key_material + key_material_size; } void Clear() { memset_s(const_cast(key_material), 0, key_material_size); delete[] key_material; key_material = nullptr; key_material_size = 0; } const uint8_t* Reset(size_t new_size) { Clear(); key_material = new (std::nothrow) uint8_t[new_size]; if (key_material) key_material_size = new_size; return key_material; } // The key_material in keymaster_key_blob_t is const, which is the right thing in most // circumstances, but occasionally we do need to write into it. This method exposes a non-const // version of the pointer. Use sparingly. uint8_t* writable_data() { return const_cast(key_material); } keymaster_key_blob_t release() { keymaster_key_blob_t tmp = {key_material, key_material_size}; key_material = nullptr; key_material_size = 0; return tmp; } size_t SerializedSize() const { return sizeof(uint32_t) + key_material_size; } uint8_t* Serialize(uint8_t* buf, const uint8_t* end) const { return append_size_and_data_to_buf(buf, end, key_material, key_material_size); } bool Deserialize(const uint8_t** buf_ptr, const uint8_t* end) { Clear(); UniquePtr tmp; if (!copy_size_and_data_from_buf(buf_ptr, end, &key_material_size, &tmp)) { key_material = nullptr; key_material_size = 0; return false; } key_material = tmp.release(); return true; } }; struct Characteristics_Delete { void operator()(keymaster_key_characteristics_t* p) { keymaster_free_characteristics(p); free(p); } }; struct Malloc_Delete { void operator()(void* p) { free(p); } }; } // namespace keymaster #endif // SYSTEM_KEYMASTER_ANDROID_KEYMASTER_UTILS_H_