| /* |
| * 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 <stdint.h> |
| #include <string.h> |
| #include <time.h> // for time_t. |
| |
| #include <keymaster/UniquePtr.h> |
| |
| #include <hardware/keymaster_defs.h> |
| #include <keymaster/serializable.h> |
| |
| 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 static_cast<int64_t>(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 <typename T, size_t N> inline size_t array_size(const T (&a)[N]) { |
| return sizeof(a); |
| } |
| |
| /** |
| * Return the number of elements in array \p a. |
| */ |
| template <typename T, size_t N> 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 <typename T> 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 <typename T, size_t N> 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 <typename T, size_t N> 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 <typename T, size_t N> 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 <typename T> explicit Eraser(T* t); |
| |
| template <typename T> |
| explicit Eraser(T& t) : buf_(reinterpret_cast<uint8_t*>(&t)), size_(sizeof(t)) {} |
| |
| template <size_t N> explicit Eraser(uint8_t (&arr)[N]) : buf_(arr), size_(N) {} |
| |
| Eraser(void* buf, size_t size) : buf_(static_cast<uint8_t*>(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 <typename T> 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 <typename T> ArrayWrapper<T> array_range(T* begin, size_t length) { |
| return ArrayWrapper<T>(begin, length); |
| } |
| |
| template <typename T, size_t n> ArrayWrapper<T> array_range(T (&a)[n]) { |
| return ArrayWrapper<T>(a, n); |
| } |
| |
| /** |
| * 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 <typename T> T ntoh(T t) { |
| const uint8_t* byte_ptr = reinterpret_cast<const uint8_t*>(&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 <typename T> T hton(T t) { |
| T retval; |
| uint8_t* byte_ptr = reinterpret_cast<uint8_t*>(&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<uint8_t*>(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<uint8_t*>(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<uint8_t[]> 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); } |
| }; |
| |
| struct CertificateChainDelete { |
| void operator()(keymaster_cert_chain_t* p) { |
| if (!p) |
| return; |
| for (size_t i = 0; i < p->entry_count; ++i) |
| delete[] p->entries[i].data; |
| delete[] p->entries; |
| delete p; |
| } |
| }; |
| |
| keymaster_error_t EcKeySizeToCurve(uint32_t key_size_bits, keymaster_ec_curve_t* curve); |
| keymaster_error_t EcCurveToKeySize(keymaster_ec_curve_t curve, uint32_t* key_size_bits); |
| |
| } // namespace keymaster |
| |
| #endif // SYSTEM_KEYMASTER_ANDROID_KEYMASTER_UTILS_H_ |