1 /* 2 ** 3 ** Copyright 2017, The Android Open Source Project 4 ** 5 ** Licensed under the Apache License, Version 2.0 (the "License"); 6 ** you may not use this file except in compliance with the License. 7 ** You may obtain a copy of the License at 8 ** 9 ** http://www.apache.org/licenses/LICENSE-2.0 10 ** 11 ** Unless required by applicable law or agreed to in writing, software 12 ** distributed under the License is distributed on an "AS IS" BASIS, 13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 ** See the License for the specific language governing permissions and 15 ** limitations under the License. 16 */ 17 18 #include <keymaster/km_openssl/soft_keymaster_enforcement.h> 19 20 #include <assert.h> 21 #include <time.h> 22 23 #include <openssl/cmac.h> 24 #include <openssl/evp.h> 25 #include <openssl/hmac.h> 26 #include <openssl/rand.h> 27 28 #include <keymaster/km_openssl/ckdf.h> 29 #include <keymaster/km_openssl/openssl_err.h> 30 #include <keymaster/km_openssl/openssl_utils.h> 31 32 namespace keymaster { 33 34 namespace { 35 36 constexpr uint8_t kFakeKeyAgreementKey[32] = {}; 37 constexpr const char* kSharedHmacLabel = "KeymasterSharedMac"; 38 constexpr const char* kMacVerificationString = "Keymaster HMAC Verification"; 39 constexpr const char* kAuthVerificationLabel = "Auth Verification"; 40 41 class EvpMdCtx { 42 public: 43 EvpMdCtx() { EVP_MD_CTX_init(&ctx_); } 44 ~EvpMdCtx() { EVP_MD_CTX_cleanup(&ctx_); } 45 46 EVP_MD_CTX* get() { return &ctx_; } 47 48 private: 49 EVP_MD_CTX ctx_; 50 }; 51 52 } // anonymous namespace 53 54 uint64_t SoftKeymasterEnforcement::get_current_time_ms() const { 55 struct timespec tp; 56 int err = clock_gettime(CLOCK_BOOTTIME, &tp); 57 if (err || tp.tv_sec < 0) return 0; 58 59 return static_cast<uint64_t>(tp.tv_sec) * 1000 + static_cast<uint64_t>(tp.tv_nsec) / 1000000; 60 } 61 62 bool SoftKeymasterEnforcement::CreateKeyId(const keymaster_key_blob_t& key_blob, 63 km_id_t* keyid) const { 64 EvpMdCtx ctx; 65 66 uint8_t hash[EVP_MAX_MD_SIZE]; 67 unsigned int hash_len; 68 if (EVP_DigestInit_ex(ctx.get(), EVP_sha256(), nullptr /* ENGINE */) && 69 EVP_DigestUpdate(ctx.get(), key_blob.key_material, key_blob.key_material_size) && 70 EVP_DigestFinal_ex(ctx.get(), hash, &hash_len)) { 71 assert(hash_len >= sizeof(*keyid)); 72 memcpy(keyid, hash, sizeof(*keyid)); 73 return true; 74 } 75 76 return false; 77 } 78 79 keymaster_error_t 80 SoftKeymasterEnforcement::GetHmacSharingParameters(HmacSharingParameters* params) { 81 if (!have_saved_params_) { 82 saved_params_.seed = {}; 83 RAND_bytes(saved_params_.nonce, 32); 84 have_saved_params_ = true; 85 } 86 params->seed = saved_params_.seed; 87 memcpy(params->nonce, saved_params_.nonce, sizeof(params->nonce)); 88 return KM_ERROR_OK; 89 } 90 91 namespace { 92 93 DEFINE_OPENSSL_OBJECT_POINTER(HMAC_CTX); 94 95 keymaster_error_t hmacSha256(const keymaster_key_blob_t& key, const keymaster_blob_t data_chunks[], 96 size_t data_chunk_count, KeymasterBlob* output) { 97 if (!output) return KM_ERROR_UNEXPECTED_NULL_POINTER; 98 99 unsigned digest_len = SHA256_DIGEST_LENGTH; 100 if (!output->Reset(digest_len)) return KM_ERROR_MEMORY_ALLOCATION_FAILED; 101 102 HMAC_CTX_Ptr ctx(HMAC_CTX_new()); 103 if (!HMAC_Init_ex(ctx.get(), key.key_material, key.key_material_size, EVP_sha256(), 104 nullptr /* engine*/)) { 105 return TranslateLastOpenSslError(); 106 } 107 108 for (size_t i = 0; i < data_chunk_count; i++) { 109 auto& chunk = data_chunks[i]; 110 if (!HMAC_Update(ctx.get(), chunk.data, chunk.data_length)) { 111 return TranslateLastOpenSslError(); 112 } 113 } 114 115 if (!HMAC_Final(ctx.get(), output->writable_data(), &digest_len)) { 116 return TranslateLastOpenSslError(); 117 } 118 119 if (digest_len != output->data_length) return KM_ERROR_UNKNOWN_ERROR; 120 121 return KM_ERROR_OK; 122 } 123 124 // Helpers for converting types to keymaster_blob_t, for easy feeding of hmacSha256. 125 template <typename T> inline keymaster_blob_t toBlob(const T& t) { 126 return {reinterpret_cast<const uint8_t*>(&t), sizeof(t)}; 127 } 128 inline keymaster_blob_t toBlob(const char* str) { 129 return {reinterpret_cast<const uint8_t*>(str), strlen(str)}; 130 } 131 132 // Perhaps these shoud be in utils, but the impact of that needs to be considered carefully. For 133 // now, just define it here. 134 inline bool operator==(const keymaster_blob_t& a, const keymaster_blob_t& b) { 135 if (!a.data_length && !b.data_length) return true; 136 if (!(a.data && b.data)) return a.data == b.data; 137 return (a.data_length == b.data_length && !memcmp(a.data, b.data, a.data_length)); 138 } 139 140 bool operator==(const HmacSharingParameters& a, const HmacSharingParameters& b) { 141 return a.seed == b.seed && !memcmp(a.nonce, b.nonce, sizeof(a.nonce)); 142 } 143 144 } // namespace 145 146 keymaster_error_t 147 SoftKeymasterEnforcement::ComputeSharedHmac(const HmacSharingParametersArray& params_array, 148 KeymasterBlob* sharingCheck) { 149 size_t num_chunks = params_array.num_params * 2; 150 UniquePtr<keymaster_blob_t[]> context_chunks(new (std::nothrow) keymaster_blob_t[num_chunks]); 151 if (!context_chunks.get()) return KM_ERROR_MEMORY_ALLOCATION_FAILED; 152 153 bool found_mine = false; 154 auto context_chunks_pos = context_chunks.get(); 155 for (auto& params : array_range(params_array.params_array, params_array.num_params)) { 156 *context_chunks_pos++ = params.seed; 157 *context_chunks_pos++ = {params.nonce, sizeof(params.nonce)}; 158 found_mine = found_mine || params == saved_params_; 159 } 160 assert(context_chunks_pos - num_chunks == context_chunks.get()); 161 162 if (!found_mine) return KM_ERROR_INVALID_ARGUMENT; 163 164 if (!hmac_key_.Reset(SHA256_DIGEST_LENGTH)) return KM_ERROR_MEMORY_ALLOCATION_FAILED; 165 keymaster_error_t error = ckdf( 166 KeymasterKeyBlob(kFakeKeyAgreementKey, sizeof(kFakeKeyAgreementKey)), 167 KeymasterBlob(reinterpret_cast<const uint8_t*>(kSharedHmacLabel), strlen(kSharedHmacLabel)), 168 context_chunks.get(), num_chunks, // 169 &hmac_key_); 170 if (error != KM_ERROR_OK) return error; 171 172 keymaster_blob_t data = {reinterpret_cast<const uint8_t*>(kMacVerificationString), 173 strlen(kMacVerificationString)}; 174 keymaster_blob_t data_chunks[] = {data}; 175 return hmacSha256(hmac_key_, data_chunks, 1, sharingCheck); 176 } 177 178 VerifyAuthorizationResponse 179 SoftKeymasterEnforcement::VerifyAuthorization(const VerifyAuthorizationRequest& request) { 180 // The only thing this implementation provides is timestamp and security level. Note that this 181 // is an acceptable implementation strategy for production use as well. Additional verification 182 // need only be provided by an implementation if it is interoperating with another 183 // implementation that requires more. 184 VerifyAuthorizationResponse response; 185 response.token.challenge = request.challenge; 186 response.token.timestamp = get_current_time_ms(); 187 response.token.security_level = SecurityLevel(); 188 keymaster_blob_t data_chunks[] = { 189 toBlob(kAuthVerificationLabel), 190 toBlob(response.token.challenge), 191 toBlob(response.token.timestamp), 192 toBlob(response.token.security_level), 193 {}, // parametersVerified 194 }; 195 response.error = hmacSha256(hmac_key_, data_chunks, 5, &response.token.mac); 196 197 return response; 198 } 199 200 } // namespace keymaster 201