blob: ba5361d99e71346e4460ae7bf62541dde6fa81c7 [file] [log] [blame]
Shawn Willden128ffe02014-08-06 12:31:33 -06001/*
2 * Copyright 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Shawn Willdenb6837e72015-05-16 09:20:59 -060017#include <keymaster/android_keymaster.h>
Shawn Willden567a4a02014-12-31 12:14:46 -070018
Shawn Willden128ffe02014-08-06 12:31:33 -060019#include <assert.h>
20#include <string.h>
21
Shawn Willden4db3fbd2014-08-08 22:13:44 -060022#include <cstddef>
23
Shawn Willden1615f2e2014-08-13 10:37:40 -060024#include <openssl/rand.h>
Shawn Willdenffd790c2014-08-18 21:20:06 -060025#include <openssl/x509.h>
Shawn Willden128ffe02014-08-06 12:31:33 -060026
27#include <UniquePtr.h>
28
Shawn Willdenb6837e72015-05-16 09:20:59 -060029#include <keymaster/android_keymaster_utils.h>
Shawn Willden0cb69422015-05-26 08:31:37 -060030#include <keymaster/keymaster_context.h>
Shawn Willden98d9b922014-08-26 08:14:10 -060031
Shawn Willden3879f862014-08-06 14:40:48 -060032#include "ae.h"
Shawn Willdend67afae2014-08-19 12:36:27 -060033#include "key.h"
Shawn Willden567a4a02014-12-31 12:14:46 -070034#include "openssl_err.h"
Shawn Willdend67afae2014-08-19 12:36:27 -060035#include "operation.h"
Shawn Willden23d4a742015-03-19 15:33:21 -060036#include "operation_table.h"
Shawn Willden128ffe02014-08-06 12:31:33 -060037
38namespace keymaster {
39
Shawn Willden2665e862014-11-24 14:46:21 -070040const uint8_t MAJOR_VER = 1;
41const uint8_t MINOR_VER = 0;
42const uint8_t SUBMINOR_VER = 0;
43
Shawn Willden0cb69422015-05-26 08:31:37 -060044AndroidKeymaster::AndroidKeymaster(KeymasterContext* context, size_t operation_table_size)
45 : context_(context), operation_table_(new OperationTable(operation_table_size)) {
Shawn Willden39b970b2014-08-11 09:11:21 -060046}
Shawn Willdena278f612014-12-23 11:22:21 -070047
Shawn Willdenb6837e72015-05-16 09:20:59 -060048AndroidKeymaster::~AndroidKeymaster() {
Shawn Willden39b970b2014-08-11 09:11:21 -060049}
Shawn Willden128ffe02014-08-06 12:31:33 -060050
Shawn Willden128ffe02014-08-06 12:31:33 -060051struct AE_CTX_Delete {
Shawn Willden802bb292014-08-18 10:46:29 -060052 void operator()(ae_ctx* ctx) const { ae_free(ctx); }
Shawn Willden128ffe02014-08-06 12:31:33 -060053};
54typedef UniquePtr<ae_ctx, AE_CTX_Delete> Unique_ae_ctx;
55
Shawn Willden19fca882015-01-22 16:35:30 -070056// TODO(swillden): Unify support analysis. Right now, we have per-keytype methods that determine if
Shawn Willdenb6837e72015-05-16 09:20:59 -060057// specific modes, padding, etc. are supported for that key type, and AndroidKeymaster also has
Shawn Willden19fca882015-01-22 16:35:30 -070058// methods that return the same information. They'll get out of sync. Best to put the knowledge in
Shawn Willdenb6837e72015-05-16 09:20:59 -060059// the keytypes and provide some mechanism for AndroidKeymaster to query the keytypes for the
Shawn Willden19fca882015-01-22 16:35:30 -070060// information.
Shawn Willden128ffe02014-08-06 12:31:33 -060061
62template <typename T>
63bool check_supported(keymaster_algorithm_t algorithm, SupportedResponse<T>* response) {
Shawn Willdena278f612014-12-23 11:22:21 -070064 if (KeyFactoryRegistry::Get(algorithm) == NULL) {
Shawn Willden128ffe02014-08-06 12:31:33 -060065 response->error = KM_ERROR_UNSUPPORTED_ALGORITHM;
66 return false;
67 }
68 return true;
69}
70
Shawn Willdenb6837e72015-05-16 09:20:59 -060071void AndroidKeymaster::GetVersion(const GetVersionRequest&, GetVersionResponse* rsp) {
Shawn Willden2665e862014-11-24 14:46:21 -070072 if (rsp == NULL)
73 return;
74
75 rsp->major_ver = MAJOR_VER;
76 rsp->minor_ver = MINOR_VER;
77 rsp->subminor_ver = SUBMINOR_VER;
78 rsp->error = KM_ERROR_OK;
79}
80
Shawn Willdenb6837e72015-05-16 09:20:59 -060081void AndroidKeymaster::SupportedAlgorithms(
Shawn Willden3809b932014-12-02 06:59:46 -070082 SupportedResponse<keymaster_algorithm_t>* response) const {
Shawn Willden128ffe02014-08-06 12:31:33 -060083 if (response == NULL)
84 return;
Shawn Willdena278f612014-12-23 11:22:21 -070085
86 size_t factory_count = 0;
87 const KeyFactory** factories = KeyFactoryRegistry::GetAll(&factory_count);
88 assert(factories != NULL);
89 assert(factory_count > 0);
90
91 UniquePtr<keymaster_algorithm_t[]> algorithms(new keymaster_algorithm_t[factory_count]);
92 if (!algorithms.get()) {
93 response->error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
94 return;
95 }
96
97 for (size_t i = 0; i < factory_count; ++i)
98 algorithms[i] = factories[i]->registry_key();
99
100 response->results = algorithms.release();
101 response->results_length = factory_count;
102 response->error = KM_ERROR_OK;
Shawn Willden128ffe02014-08-06 12:31:33 -0600103}
104
Shawn Willden63ac0432014-12-29 14:07:08 -0700105static OperationFactory* GetOperationFactory(keymaster_algorithm_t algorithm,
106 keymaster_purpose_t purpose,
107 keymaster_error_t* error) {
108 assert(error);
109 if (error)
110 *error = KM_ERROR_OK;
111
112 OperationFactory* factory =
113 OperationFactoryRegistry::Get(OperationFactory::KeyType(algorithm, purpose));
114 if (factory == NULL && error)
115 *error = KM_ERROR_UNSUPPORTED_PURPOSE;
116
117 return factory;
Shawn Willden128ffe02014-08-06 12:31:33 -0600118}
119
Shawn Willden63ac0432014-12-29 14:07:08 -0700120template <typename T>
121void GetSupported(keymaster_algorithm_t algorithm, keymaster_purpose_t purpose,
122 const T* (OperationFactory::*get_supported_method)(size_t* count) const,
123 SupportedResponse<T>* response) {
124 if (response == NULL || !check_supported(algorithm, response))
125 return;
126
127 OperationFactory* factory = GetOperationFactory(algorithm, purpose, &response->error);
128 if (!factory) {
129 response->error = KM_ERROR_UNSUPPORTED_PURPOSE;
130 return;
131 }
132
133 size_t count;
134 const T* supported = (factory->*get_supported_method)(&count);
135 response->SetResults(supported, count);
136}
137
Shawn Willdenb6837e72015-05-16 09:20:59 -0600138void AndroidKeymaster::SupportedBlockModes(
Shawn Willden63ac0432014-12-29 14:07:08 -0700139 keymaster_algorithm_t algorithm, keymaster_purpose_t purpose,
140 SupportedResponse<keymaster_block_mode_t>* response) const {
141 GetSupported(algorithm, purpose, &OperationFactory::SupportedBlockModes, response);
142}
Shawn Willden3809b932014-12-02 06:59:46 -0700143
Shawn Willdenb6837e72015-05-16 09:20:59 -0600144void AndroidKeymaster::SupportedPaddingModes(
Shawn Willden4200f212014-12-02 07:01:21 -0700145 keymaster_algorithm_t algorithm, keymaster_purpose_t purpose,
Shawn Willden3809b932014-12-02 06:59:46 -0700146 SupportedResponse<keymaster_padding_t>* response) const {
Shawn Willden63ac0432014-12-29 14:07:08 -0700147 GetSupported(algorithm, purpose, &OperationFactory::SupportedPaddingModes, response);
Shawn Willden128ffe02014-08-06 12:31:33 -0600148}
149
Shawn Willdenb6837e72015-05-16 09:20:59 -0600150void AndroidKeymaster::SupportedDigests(keymaster_algorithm_t algorithm,
151 keymaster_purpose_t purpose,
152 SupportedResponse<keymaster_digest_t>* response) const {
Shawn Willden63ac0432014-12-29 14:07:08 -0700153 GetSupported(algorithm, purpose, &OperationFactory::SupportedDigests, response);
Shawn Willden128ffe02014-08-06 12:31:33 -0600154}
155
Shawn Willdenb6837e72015-05-16 09:20:59 -0600156void AndroidKeymaster::SupportedImportFormats(
Shawn Willden3809b932014-12-02 06:59:46 -0700157 keymaster_algorithm_t algorithm, SupportedResponse<keymaster_key_format_t>* response) const {
Shawn Willden128ffe02014-08-06 12:31:33 -0600158 if (response == NULL || !check_supported(algorithm, response))
159 return;
160
Shawn Willdena278f612014-12-23 11:22:21 -0700161 size_t count;
162 const keymaster_key_format_t* formats =
163 KeyFactoryRegistry::Get(algorithm)->SupportedImportFormats(&count);
164 response->SetResults(formats, count);
Shawn Willden128ffe02014-08-06 12:31:33 -0600165}
166
Shawn Willdenb6837e72015-05-16 09:20:59 -0600167void AndroidKeymaster::SupportedExportFormats(
Shawn Willden3809b932014-12-02 06:59:46 -0700168 keymaster_algorithm_t algorithm, SupportedResponse<keymaster_key_format_t>* response) const {
Shawn Willden128ffe02014-08-06 12:31:33 -0600169 if (response == NULL || !check_supported(algorithm, response))
170 return;
171
Shawn Willdena278f612014-12-23 11:22:21 -0700172 size_t count;
173 const keymaster_key_format_t* formats =
174 KeyFactoryRegistry::Get(algorithm)->SupportedExportFormats(&count);
175 response->SetResults(formats, count);
Shawn Willden128ffe02014-08-06 12:31:33 -0600176}
177
Shawn Willden0cb69422015-05-26 08:31:37 -0600178keymaster_error_t AndroidKeymaster::AddRngEntropy(const AddEntropyRequest& request) {
179 return context_->AddRngEntropy(request.random_data.peek_read(),
180 request.random_data.available_read());
181}
182
Shawn Willdenb6837e72015-05-16 09:20:59 -0600183void AndroidKeymaster::GenerateKey(const GenerateKeyRequest& request,
184 GenerateKeyResponse* response) {
Shawn Willden128ffe02014-08-06 12:31:33 -0600185 if (response == NULL)
186 return;
Shawn Willden128ffe02014-08-06 12:31:33 -0600187
Shawn Willdena278f612014-12-23 11:22:21 -0700188 keymaster_algorithm_t algorithm;
189 KeyFactory* factory = 0;
190 UniquePtr<Key> key;
191 if (!request.key_description.GetTagValue(TAG_ALGORITHM, &algorithm) ||
192 !(factory = KeyFactoryRegistry::Get(algorithm)))
193 response->error = KM_ERROR_UNSUPPORTED_ALGORITHM;
Shawn Willden0cb69422015-05-26 08:31:37 -0600194 else {
195 KeymasterKeyBlob key_blob;
196 response->error = factory->GenerateKey(request.key_description, &key_blob,
197 &response->enforced, &response->unenforced);
198 if (response->error == KM_ERROR_OK)
199 response->key_blob = key_blob.release();
200 }
Shawn Willden128ffe02014-08-06 12:31:33 -0600201}
202
Shawn Willdenb6837e72015-05-16 09:20:59 -0600203void AndroidKeymaster::GetKeyCharacteristics(const GetKeyCharacteristicsRequest& request,
204 GetKeyCharacteristicsResponse* response) {
Shawn Willden1615f2e2014-08-13 10:37:40 -0600205 if (response == NULL)
206 return;
Shawn Willden76364712014-08-11 17:48:04 -0600207
Shawn Willden0cb69422015-05-26 08:31:37 -0600208 KeymasterKeyBlob key_material;
209 response->error =
210 context_->ParseKeyBlob(KeymasterKeyBlob(request.key_blob), request.additional_params,
211 &key_material, &response->enforced, &response->unenforced);
212 if (response->error != KM_ERROR_OK)
Shawn Willden1615f2e2014-08-13 10:37:40 -0600213 return;
Shawn Willden0cb69422015-05-26 08:31:37 -0600214}
Shawn Willden1615f2e2014-08-13 10:37:40 -0600215
Shawn Willden0cb69422015-05-26 08:31:37 -0600216static KeyFactory* GetKeyFactory(const AuthorizationSet& hw_enforced,
217 const AuthorizationSet& sw_enforced,
218 keymaster_algorithm_t* algorithm, keymaster_error_t* error) {
219 *error = KM_ERROR_UNSUPPORTED_ALGORITHM;
220 if (!hw_enforced.GetTagValue(TAG_ALGORITHM, algorithm) &&
221 !sw_enforced.GetTagValue(TAG_ALGORITHM, algorithm))
222 return nullptr;
223 KeyFactory* factory = KeyFactoryRegistry::Get(*algorithm);
224 if (factory)
225 *error = KM_ERROR_OK;
226 return factory;
Shawn Willden1615f2e2014-08-13 10:37:40 -0600227}
228
Shawn Willdenb6837e72015-05-16 09:20:59 -0600229void AndroidKeymaster::BeginOperation(const BeginOperationRequest& request,
230 BeginOperationResponse* response) {
Shawn Willden1615f2e2014-08-13 10:37:40 -0600231 if (response == NULL)
232 return;
Shawn Willden1615f2e2014-08-13 10:37:40 -0600233 response->op_handle = 0;
234
Shawn Willden0cb69422015-05-26 08:31:37 -0600235 AuthorizationSet hw_enforced;
236 AuthorizationSet sw_enforced;
Shawn Willden63ac0432014-12-29 14:07:08 -0700237 keymaster_algorithm_t algorithm;
Shawn Willden0cb69422015-05-26 08:31:37 -0600238 UniquePtr<Key> key;
239 response->error = LoadKey(request.key_blob, request.additional_params, &hw_enforced,
240 &sw_enforced, &algorithm, &key);
Shawn Willden1615f2e2014-08-13 10:37:40 -0600241
Shawn Willdenedb79942015-05-08 06:46:44 -0600242 // TODO(swillden): Move this check to a general authorization checker.
Shawn Willden0cb69422015-05-26 08:31:37 -0600243 // TODO(swillden): Consider introducing error codes for unauthorized usages.
244 response->error = KM_ERROR_INCOMPATIBLE_PURPOSE;
245 if (!hw_enforced.Contains(TAG_PURPOSE, request.purpose) &&
246 !sw_enforced.Contains(TAG_PURPOSE, request.purpose))
Shawn Willdenedb79942015-05-08 06:46:44 -0600247 return;
Shawn Willdenedb79942015-05-08 06:46:44 -0600248
Shawn Willden0cb69422015-05-26 08:31:37 -0600249 response->error = KM_ERROR_UNSUPPORTED_PURPOSE;
250 OperationFactory* factory = OperationFactoryRegistry::Get({algorithm, request.purpose});
251 if (!factory)
Shawn Willden63ac0432014-12-29 14:07:08 -0700252 return;
Shawn Willden63ac0432014-12-29 14:07:08 -0700253
Shawn Willden3ed6d062015-04-15 13:39:38 -0600254 UniquePtr<Operation> operation(
255 factory->CreateOperation(*key, request.additional_params, &response->error));
Shawn Willdend67afae2014-08-19 12:36:27 -0600256 if (operation.get() == NULL)
Shawn Willden76364712014-08-11 17:48:04 -0600257 return;
Shawn Willden1615f2e2014-08-13 10:37:40 -0600258
Shawn Willden111edb32015-02-05 22:44:24 -0700259 response->output_params.Clear();
260 response->error = operation->Begin(request.additional_params, &response->output_params);
Shawn Willden1615f2e2014-08-13 10:37:40 -0600261 if (response->error != KM_ERROR_OK)
262 return;
263
Shawn Willden23d4a742015-03-19 15:33:21 -0600264 response->error = operation_table_->Add(operation.release(), &response->op_handle);
Shawn Willden1615f2e2014-08-13 10:37:40 -0600265}
266
Shawn Willdenb6837e72015-05-16 09:20:59 -0600267void AndroidKeymaster::UpdateOperation(const UpdateOperationRequest& request,
268 UpdateOperationResponse* response) {
Shawn Willdend6cd7e32014-12-17 08:01:26 -0700269 if (response == NULL)
270 return;
271
Shawn Willden23d4a742015-03-19 15:33:21 -0600272 response->error = KM_ERROR_INVALID_OPERATION_HANDLE;
273 Operation* operation = operation_table_->Find(request.op_handle);
274 if (operation == NULL)
Shawn Willden1615f2e2014-08-13 10:37:40 -0600275 return;
Shawn Willden1615f2e2014-08-13 10:37:40 -0600276
Shawn Willden23d4a742015-03-19 15:33:21 -0600277 response->error = operation->Update(request.additional_params, request.input, &response->output,
278 &response->input_consumed);
Shawn Willden1615f2e2014-08-13 10:37:40 -0600279 if (response->error != KM_ERROR_OK) {
280 // Any error invalidates the operation.
Shawn Willden23d4a742015-03-19 15:33:21 -0600281 operation_table_->Delete(request.op_handle);
Shawn Willden1615f2e2014-08-13 10:37:40 -0600282 }
283}
284
Shawn Willdenb6837e72015-05-16 09:20:59 -0600285void AndroidKeymaster::FinishOperation(const FinishOperationRequest& request,
286 FinishOperationResponse* response) {
Shawn Willdend6cd7e32014-12-17 08:01:26 -0700287 if (response == NULL)
288 return;
289
Shawn Willden23d4a742015-03-19 15:33:21 -0600290 response->error = KM_ERROR_INVALID_OPERATION_HANDLE;
291 Operation* operation = operation_table_->Find(request.op_handle);
292 if (operation == NULL)
Shawn Willden1615f2e2014-08-13 10:37:40 -0600293 return;
Shawn Willden1615f2e2014-08-13 10:37:40 -0600294
Shawn Willden6bfbff02015-02-06 19:48:24 -0700295 response->error =
Shawn Willden23d4a742015-03-19 15:33:21 -0600296 operation->Finish(request.additional_params, request.signature, &response->output);
297 operation_table_->Delete(request.op_handle);
Shawn Willden1615f2e2014-08-13 10:37:40 -0600298}
299
Shawn Willdenb6837e72015-05-16 09:20:59 -0600300keymaster_error_t AndroidKeymaster::AbortOperation(const keymaster_operation_handle_t op_handle) {
Shawn Willden23d4a742015-03-19 15:33:21 -0600301 Operation* operation = operation_table_->Find(op_handle);
302 if (operation == NULL)
Shawn Willden1615f2e2014-08-13 10:37:40 -0600303 return KM_ERROR_INVALID_OPERATION_HANDLE;
Shawn Willden23d4a742015-03-19 15:33:21 -0600304
305 keymaster_error_t error = operation->Abort();
306 operation_table_->Delete(op_handle);
Shawn Willden7ec74f92014-12-11 13:57:59 -0700307 if (error != KM_ERROR_OK)
308 return error;
Shawn Willden1615f2e2014-08-13 10:37:40 -0600309 return KM_ERROR_OK;
Shawn Willden76364712014-08-11 17:48:04 -0600310}
311
Shawn Willdenb6837e72015-05-16 09:20:59 -0600312void AndroidKeymaster::ExportKey(const ExportKeyRequest& request, ExportKeyResponse* response) {
Shawn Willdenffd790c2014-08-18 21:20:06 -0600313 if (response == NULL)
314 return;
315
Shawn Willden0cb69422015-05-26 08:31:37 -0600316 AuthorizationSet hw_enforced;
317 AuthorizationSet sw_enforced;
318 KeymasterKeyBlob key_material;
319 response->error =
320 context_->ParseKeyBlob(KeymasterKeyBlob(request.key_blob), request.additional_params,
321 &key_material, &hw_enforced, &sw_enforced);
322 if (response->error != KM_ERROR_OK)
323 return;
324
Shawn Willden63ac0432014-12-29 14:07:08 -0700325 keymaster_algorithm_t algorithm;
Shawn Willden0cb69422015-05-26 08:31:37 -0600326 KeyFactory* key_factory = GetKeyFactory(hw_enforced, sw_enforced, &algorithm, &response->error);
327 if (!key_factory)
328 return;
329
330 UniquePtr<Key> key;
331 response->error = key_factory->LoadKey(key_material, hw_enforced, sw_enforced, &key);
332 if (response->error != KM_ERROR_OK)
Shawn Willdenffd790c2014-08-18 21:20:06 -0600333 return;
334
Shawn Willdenf268d742014-08-19 15:36:26 -0600335 UniquePtr<uint8_t[]> out_key;
336 size_t size;
Shawn Willden0cb69422015-05-26 08:31:37 -0600337 response->error = key->formatted_key_material(request.key_format, &out_key, &size);
Shawn Willdenf268d742014-08-19 15:36:26 -0600338 if (response->error == KM_ERROR_OK) {
339 response->key_data = out_key.release();
340 response->key_data_length = size;
Shawn Willdenffd790c2014-08-18 21:20:06 -0600341 }
Shawn Willdenffd790c2014-08-18 21:20:06 -0600342}
343
Shawn Willdenb6837e72015-05-16 09:20:59 -0600344void AndroidKeymaster::ImportKey(const ImportKeyRequest& request, ImportKeyResponse* response) {
Shawn Willden437fbd12014-08-20 11:59:49 -0600345 if (response == NULL)
Shawn Willdenffd790c2014-08-18 21:20:06 -0600346 return;
Shawn Willdenffd790c2014-08-18 21:20:06 -0600347
Shawn Willdena278f612014-12-23 11:22:21 -0700348 keymaster_algorithm_t algorithm;
349 KeyFactory* factory = 0;
350 UniquePtr<Key> key;
351 if (!request.key_description.GetTagValue(TAG_ALGORITHM, &algorithm) ||
352 !(factory = KeyFactoryRegistry::Get(algorithm)))
353 response->error = KM_ERROR_UNSUPPORTED_ALGORITHM;
Shawn Willden0cb69422015-05-26 08:31:37 -0600354 else {
355 keymaster_key_blob_t key_material = {request.key_data, request.key_data_length};
356 KeymasterKeyBlob key_blob;
357 response->error = factory->ImportKey(request.key_description, request.key_format,
358 KeymasterKeyBlob(key_material), &key_blob,
359 &response->enforced, &response->unenforced);
360 if (response->error == KM_ERROR_OK)
361 response->key_blob = key_blob.release();
362 }
Shawn Willdenffd790c2014-08-18 21:20:06 -0600363}
364
Shawn Willden0cb69422015-05-26 08:31:37 -0600365keymaster_error_t AndroidKeymaster::LoadKey(const keymaster_key_blob_t& key_blob,
366 const AuthorizationSet& additional_params,
367 AuthorizationSet* hw_enforced,
368 AuthorizationSet* sw_enforced,
369 keymaster_algorithm_t* algorithm, UniquePtr<Key>* key) {
370 KeymasterKeyBlob key_material;
371 keymaster_error_t error = context_->ParseKeyBlob(KeymasterKeyBlob(key_blob), additional_params,
372 &key_material, hw_enforced, sw_enforced);
Shawn Willden437fbd12014-08-20 11:59:49 -0600373 if (error != KM_ERROR_OK)
374 return error;
375
Shawn Willden0cb69422015-05-26 08:31:37 -0600376 KeyFactory* key_factory = GetKeyFactory(*hw_enforced, *sw_enforced, algorithm, &error);
377 if (error != KM_ERROR_OK) {
378 assert(!key_factory);
Shawn Willden437fbd12014-08-20 11:59:49 -0600379 return error;
Shawn Willden128ffe02014-08-06 12:31:33 -0600380 }
381
Shawn Willden0cb69422015-05-26 08:31:37 -0600382 return key_factory->LoadKey(key_material, *hw_enforced, *sw_enforced, key);
Shawn Willden128ffe02014-08-06 12:31:33 -0600383}
384
Shawn Willden128ffe02014-08-06 12:31:33 -0600385} // namespace keymaster