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 #ifdef _WIN32
33 #include <sysinfoapi.h>
34 #endif
35
36 namespace keymaster {
37
38 namespace {
39
40 constexpr uint8_t kFakeKeyAgreementKey[32] = {};
41 constexpr const char* kSharedHmacLabel = "KeymasterSharedMac";
42 constexpr const char* kMacVerificationString = "Keymaster HMAC Verification";
43 constexpr const char* kAuthVerificationLabel = "Auth Verification";
44
45 class EvpMdCtx {
46 public:
EvpMdCtx()47 EvpMdCtx() { EVP_MD_CTX_init(&ctx_); }
~EvpMdCtx()48 ~EvpMdCtx() { EVP_MD_CTX_cleanup(&ctx_); }
49
get()50 EVP_MD_CTX* get() { return &ctx_; }
51
52 private:
53 EVP_MD_CTX ctx_;
54 };
55
56 } // anonymous namespace
57
get_current_time_ms() const58 uint64_t SoftKeymasterEnforcement::get_current_time_ms() const {
59 #ifdef _WIN32
60 return GetTickCount64();
61 #else
62 struct timespec tp;
63 #ifdef __linux__
64 int err = clock_gettime(CLOCK_BOOTTIME, &tp);
65 #else
66 int err = clock_gettime(CLOCK_MONOTONIC, &tp);
67 #endif
68 if (err || tp.tv_sec < 0) return 0;
69
70 return static_cast<uint64_t>(tp.tv_sec) * 1000 + static_cast<uint64_t>(tp.tv_nsec) / 1000000;
71 #endif
72 }
73
CreateKeyId(const keymaster_key_blob_t & key_blob,km_id_t * keyid) const74 bool SoftKeymasterEnforcement::CreateKeyId(const keymaster_key_blob_t& key_blob,
75 km_id_t* keyid) const {
76 EvpMdCtx ctx;
77
78 uint8_t hash[EVP_MAX_MD_SIZE];
79 unsigned int hash_len;
80 if (EVP_DigestInit_ex(ctx.get(), EVP_sha256(), nullptr /* ENGINE */) &&
81 EVP_DigestUpdate(ctx.get(), key_blob.key_material, key_blob.key_material_size) &&
82 EVP_DigestFinal_ex(ctx.get(), hash, &hash_len)) {
83 assert(hash_len >= sizeof(*keyid));
84 memcpy(keyid, hash, sizeof(*keyid));
85 return true;
86 }
87
88 return false;
89 }
90
91 keymaster_error_t
GetHmacSharingParameters(HmacSharingParameters * params)92 SoftKeymasterEnforcement::GetHmacSharingParameters(HmacSharingParameters* params) {
93 if (!have_saved_params_) {
94 saved_params_.seed = {};
95 RAND_bytes(saved_params_.nonce, 32);
96 have_saved_params_ = true;
97 }
98 params->seed = saved_params_.seed;
99 memcpy(params->nonce, saved_params_.nonce, sizeof(params->nonce));
100 return KM_ERROR_OK;
101 }
102
103 namespace {
104
105 DEFINE_OPENSSL_OBJECT_POINTER(HMAC_CTX);
106
hmacSha256(const keymaster_key_blob_t & key,const keymaster_blob_t data_chunks[],size_t data_chunk_count,KeymasterBlob * output)107 keymaster_error_t hmacSha256(const keymaster_key_blob_t& key, const keymaster_blob_t data_chunks[],
108 size_t data_chunk_count, KeymasterBlob* output) {
109 if (!output) return KM_ERROR_UNEXPECTED_NULL_POINTER;
110
111 unsigned digest_len = SHA256_DIGEST_LENGTH;
112 if (!output->Reset(digest_len)) return KM_ERROR_MEMORY_ALLOCATION_FAILED;
113
114 HMAC_CTX_Ptr ctx(HMAC_CTX_new());
115 if (!HMAC_Init_ex(ctx.get(), key.key_material, key.key_material_size, EVP_sha256(),
116 nullptr /* engine*/)) {
117 return TranslateLastOpenSslError();
118 }
119
120 for (size_t i = 0; i < data_chunk_count; i++) {
121 auto& chunk = data_chunks[i];
122 if (!HMAC_Update(ctx.get(), chunk.data, chunk.data_length)) {
123 return TranslateLastOpenSslError();
124 }
125 }
126
127 if (!HMAC_Final(ctx.get(), output->writable_data(), &digest_len)) {
128 return TranslateLastOpenSslError();
129 }
130
131 if (digest_len != output->data_length) return KM_ERROR_UNKNOWN_ERROR;
132
133 return KM_ERROR_OK;
134 }
135
136 // Helpers for converting types to keymaster_blob_t, for easy feeding of hmacSha256.
toBlob(const T & t)137 template <typename T> inline keymaster_blob_t toBlob(const T& t) {
138 return {reinterpret_cast<const uint8_t*>(&t), sizeof(t)};
139 }
toBlob(const char * str)140 inline keymaster_blob_t toBlob(const char* str) {
141 return {reinterpret_cast<const uint8_t*>(str), strlen(str)};
142 }
143
144 // Perhaps these shoud be in utils, but the impact of that needs to be considered carefully. For
145 // now, just define it here.
operator ==(const keymaster_blob_t & a,const keymaster_blob_t & b)146 inline bool operator==(const keymaster_blob_t& a, const keymaster_blob_t& b) {
147 if (!a.data_length && !b.data_length) return true;
148 if (!(a.data && b.data)) return a.data == b.data;
149 return (a.data_length == b.data_length && !memcmp(a.data, b.data, a.data_length));
150 }
151
operator ==(const HmacSharingParameters & a,const HmacSharingParameters & b)152 bool operator==(const HmacSharingParameters& a, const HmacSharingParameters& b) {
153 return a.seed == b.seed && !memcmp(a.nonce, b.nonce, sizeof(a.nonce));
154 }
155
156 } // namespace
157
158 keymaster_error_t
ComputeSharedHmac(const HmacSharingParametersArray & params_array,KeymasterBlob * sharingCheck)159 SoftKeymasterEnforcement::ComputeSharedHmac(const HmacSharingParametersArray& params_array,
160 KeymasterBlob* sharingCheck) {
161 size_t num_chunks = params_array.num_params * 2;
162 UniquePtr<keymaster_blob_t[]> context_chunks(new (std::nothrow) keymaster_blob_t[num_chunks]);
163 if (!context_chunks.get()) return KM_ERROR_MEMORY_ALLOCATION_FAILED;
164
165 bool found_mine = false;
166 auto context_chunks_pos = context_chunks.get();
167 for (auto& params : array_range(params_array.params_array, params_array.num_params)) {
168 *context_chunks_pos++ = params.seed;
169 *context_chunks_pos++ = {params.nonce, sizeof(params.nonce)};
170 found_mine = found_mine || params == saved_params_;
171 }
172 assert(context_chunks_pos - num_chunks == context_chunks.get());
173
174 if (!found_mine) return KM_ERROR_INVALID_ARGUMENT;
175
176 if (!hmac_key_.Reset(SHA256_DIGEST_LENGTH)) return KM_ERROR_MEMORY_ALLOCATION_FAILED;
177 keymaster_error_t error = ckdf(
178 KeymasterKeyBlob(kFakeKeyAgreementKey, sizeof(kFakeKeyAgreementKey)),
179 KeymasterBlob(reinterpret_cast<const uint8_t*>(kSharedHmacLabel), strlen(kSharedHmacLabel)),
180 context_chunks.get(), num_chunks, //
181 &hmac_key_);
182 if (error != KM_ERROR_OK) return error;
183
184 keymaster_blob_t data = {reinterpret_cast<const uint8_t*>(kMacVerificationString),
185 strlen(kMacVerificationString)};
186 keymaster_blob_t data_chunks[] = {data};
187 return hmacSha256(hmac_key_, data_chunks, 1, sharingCheck);
188 }
189
190 VerifyAuthorizationResponse
VerifyAuthorization(const VerifyAuthorizationRequest & request)191 SoftKeymasterEnforcement::VerifyAuthorization(const VerifyAuthorizationRequest& request) {
192 // The only thing this implementation provides is timestamp and security level. Note that this
193 // is an acceptable implementation strategy for production use as well. Additional verification
194 // need only be provided by an implementation if it is interoperating with another
195 // implementation that requires more.
196 VerifyAuthorizationResponse response(request.message_version);
197 response.token.challenge = request.challenge;
198 response.token.timestamp = get_current_time_ms();
199 response.token.security_level = SecurityLevel();
200 keymaster_blob_t data_chunks[] = {
201 toBlob(kAuthVerificationLabel),
202 toBlob(response.token.challenge),
203 toBlob(response.token.timestamp),
204 toBlob(response.token.security_level),
205 {}, // parametersVerified
206 };
207 response.error = hmacSha256(hmac_key_, data_chunks, 5, &response.token.mac);
208
209 return response;
210 }
211
GenerateTimestampToken(TimestampToken * token)212 keymaster_error_t SoftKeymasterEnforcement::GenerateTimestampToken(TimestampToken* token) {
213 token->timestamp = get_current_time_ms();
214 token->security_level = SecurityLevel();
215 keymaster_blob_t data_chunks[] = {
216 toBlob(kAuthVerificationLabel),
217 toBlob(token->challenge),
218 toBlob(token->timestamp),
219 toBlob(token->security_level),
220 };
221 return hmacSha256(hmac_key_, data_chunks, 4, &token->mac);
222 }
223
224 } // namespace keymaster
225