blob: b29b855565d77079ec9985781e73b2af4bb9fcd3 [file] [log] [blame]
Shawn Willden4db3fbd2014-08-08 22:13:44 -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
17#include <assert.h>
18
19#include <openssl/aes.h>
20#include <openssl/sha.h>
21
Shawn Willden98d9b922014-08-26 08:14:10 -060022#include <keymaster/google_keymaster_utils.h>
23
Shawn Willden4db3fbd2014-08-08 22:13:44 -060024#include "ae.h"
25#include "key_blob.h"
Shawn Willden4db3fbd2014-08-08 22:13:44 -060026
27namespace keymaster {
28
29struct AeCtxDelete {
30 void operator()(ae_ctx* p) {
31 ae_clear(p);
32 ae_free(p);
33 }
34};
35
36const size_t KeyBlob::NONCE_LENGTH;
37const size_t KeyBlob::TAG_LENGTH;
38
39KeyBlob::KeyBlob(const AuthorizationSet& enforced, const AuthorizationSet& unenforced,
Shawn Willden39b970b2014-08-11 09:11:21 -060040 const AuthorizationSet& hidden, const keymaster_key_blob_t& key,
Shawn Willdenebf627f2014-08-12 11:15:29 -060041 const keymaster_key_blob_t& master_key, const uint8_t nonce[NONCE_LENGTH])
Shawn Willdenf2282b32014-08-25 06:49:54 -060042 : error_(KM_ERROR_OK), nonce_(new uint8_t[NONCE_LENGTH]), tag_(new uint8_t[TAG_LENGTH]),
43 enforced_(enforced), unenforced_(unenforced), hidden_(hidden) {
Shawn Willden407d4122014-08-25 16:49:13 -060044 if (!nonce_.get() || !tag_.get()) {
45 error_ = KM_ERROR_MEMORY_ALLOCATION_FAILED;
46 return;
47 }
48 error_ = KM_ERROR_OK;
49
Shawn Willden4db3fbd2014-08-08 22:13:44 -060050 if (enforced_.is_valid() == AuthorizationSet::ALLOCATION_FAILURE ||
Shawn Willden76364712014-08-11 17:48:04 -060051 unenforced_.is_valid() == AuthorizationSet::ALLOCATION_FAILURE ||
52 hidden_.is_valid() == AuthorizationSet::ALLOCATION_FAILURE) {
Shawn Willden4db3fbd2014-08-08 22:13:44 -060053 error_ = KM_ERROR_MEMORY_ALLOCATION_FAILED;
54 return;
55 }
56
57 if (enforced_.is_valid() != AuthorizationSet::OK ||
Shawn Willden76364712014-08-11 17:48:04 -060058 unenforced_.is_valid() != AuthorizationSet::OK ||
59 hidden_.is_valid() != AuthorizationSet::OK) {
Shawn Willden4db3fbd2014-08-08 22:13:44 -060060 error_ = KM_ERROR_UNKNOWN_ERROR;
61 return;
62 }
63
Shawn Willden1615f2e2014-08-13 10:37:40 -060064 if (!ExtractKeyCharacteristics())
65 return;
66
Shawn Willden4db3fbd2014-08-08 22:13:44 -060067 key_material_length_ = key.key_material_size;
68 key_material_.reset(new uint8_t[key_material_length_]);
69 encrypted_key_material_.reset(new uint8_t[key_material_length_]);
70
Shawn Willdenf2282b32014-08-25 06:49:54 -060071 if (!key_material_.get() || !encrypted_key_material_.get() || !nonce_.get() || !tag_.get()) {
Shawn Willden4db3fbd2014-08-08 22:13:44 -060072 error_ = KM_ERROR_MEMORY_ALLOCATION_FAILED;
73 return;
74 }
75
Shawn Willdenf2282b32014-08-25 06:49:54 -060076 memcpy(nonce_.get(), nonce, NONCE_LENGTH);
Shawn Willden4db3fbd2014-08-08 22:13:44 -060077 memcpy(key_material_.get(), key.key_material, key_material_length_);
78 EncryptKey(master_key);
79}
80
Shawn Willden39b970b2014-08-11 09:11:21 -060081KeyBlob::KeyBlob(const keymaster_key_blob_t& key, const AuthorizationSet& hidden,
82 const keymaster_key_blob_t& master_key)
Shawn Willdenf2282b32014-08-25 06:49:54 -060083 : nonce_(new uint8_t[NONCE_LENGTH]), tag_(new uint8_t[TAG_LENGTH]), hidden_(hidden) {
Shawn Willden407d4122014-08-25 16:49:13 -060084 if (!nonce_.get() || !tag_.get()) {
85 error_ = KM_ERROR_MEMORY_ALLOCATION_FAILED;
86 return;
87 }
88 error_ = KM_ERROR_OK;
89
Shawn Willden172f8c92014-08-17 07:50:34 -060090 const uint8_t* p = key.key_material;
91 if (!Deserialize(&p, key.key_material + key.key_material_size))
Shawn Willden4db3fbd2014-08-08 22:13:44 -060092 return;
93 DecryptKey(master_key);
94}
95
Shawn Willden407d4122014-08-25 16:49:13 -060096KeyBlob::KeyBlob(const uint8_t* key_blob, size_t blob_size)
97 : nonce_(new uint8_t[NONCE_LENGTH]), tag_(new uint8_t[TAG_LENGTH]) {
98 if (!nonce_.get() || !tag_.get()) {
99 error_ = KM_ERROR_MEMORY_ALLOCATION_FAILED;
100 return;
101 }
102 error_ = KM_ERROR_OK;
103
104 if (!Deserialize(&key_blob, key_blob + blob_size))
105 return;
106}
107
Shawn Willden4db3fbd2014-08-08 22:13:44 -0600108size_t KeyBlob::SerializedSize() const {
109 return NONCE_LENGTH + sizeof(uint32_t) + key_material_length() + TAG_LENGTH +
110 enforced_.SerializedSize() + unenforced_.SerializedSize();
111}
112
113uint8_t* KeyBlob::Serialize(uint8_t* buf, const uint8_t* end) const {
114 const uint8_t* start = buf;
115 buf = append_to_buf(buf, end, nonce(), NONCE_LENGTH);
116 buf = append_size_and_data_to_buf(buf, end, encrypted_key_material(), key_material_length());
117 buf = append_to_buf(buf, end, tag(), TAG_LENGTH);
118 buf = enforced_.Serialize(buf, end);
119 buf = unenforced_.Serialize(buf, end);
120 assert(buf - start == static_cast<ptrdiff_t>(SerializedSize()));
121 return buf;
122}
123
Shawn Willden172f8c92014-08-17 07:50:34 -0600124bool KeyBlob::Deserialize(const uint8_t** buf_ptr, const uint8_t* end) {
Shawn Willdenf2282b32014-08-25 06:49:54 -0600125 UniquePtr<uint8_t[]> tmp_key_ptr;
126 if (!copy_from_buf(buf_ptr, end, nonce_.get(), NONCE_LENGTH) ||
Shawn Willden172f8c92014-08-17 07:50:34 -0600127 !copy_size_and_data_from_buf(buf_ptr, end, &key_material_length_, &tmp_key_ptr) ||
Shawn Willdenf2282b32014-08-25 06:49:54 -0600128 !copy_from_buf(buf_ptr, end, tag_.get(), TAG_LENGTH) ||
129 !enforced_.Deserialize(buf_ptr, end) || !unenforced_.Deserialize(buf_ptr, end)) {
Shawn Willden4db3fbd2014-08-08 22:13:44 -0600130 error_ = KM_ERROR_INVALID_KEY_BLOB;
131 return false;
132 }
133
Shawn Willden1615f2e2014-08-13 10:37:40 -0600134 if (!ExtractKeyCharacteristics())
135 return false;
136
Shawn Willdenf2282b32014-08-25 06:49:54 -0600137 encrypted_key_material_.reset(tmp_key_ptr.release());
Shawn Willden4db3fbd2014-08-08 22:13:44 -0600138 key_material_.reset(new uint8_t[key_material_length_]);
139 return true;
140}
141
142void KeyBlob::EncryptKey(const keymaster_key_blob_t& master_key) {
143 UniquePtr<ae_ctx, AeCtxDelete> ctx(InitializeKeyWrappingContext(master_key, &error_));
144 if (error_ != KM_ERROR_OK)
145 return;
146
Shawn Willdenf2282b32014-08-25 06:49:54 -0600147 int ae_err = ae_encrypt(ctx.get(), nonce_.get(), key_material(), key_material_length(),
Shawn Willden4db3fbd2014-08-08 22:13:44 -0600148 NULL /* additional data */, 0 /* additional data length */,
Shawn Willdenf2282b32014-08-25 06:49:54 -0600149 encrypted_key_material_.get(), tag_.get(), 1 /* final */);
Shawn Willden4db3fbd2014-08-08 22:13:44 -0600150 if (ae_err < 0) {
151 error_ = KM_ERROR_UNKNOWN_ERROR;
152 return;
153 }
154 assert(ae_err == static_cast<int>(key_material_length_));
155 error_ = KM_ERROR_OK;
156}
157
158void KeyBlob::DecryptKey(const keymaster_key_blob_t& master_key) {
159 UniquePtr<ae_ctx, AeCtxDelete> ctx(InitializeKeyWrappingContext(master_key, &error_));
160 if (error_ != KM_ERROR_OK)
161 return;
162
Shawn Willdenf2282b32014-08-25 06:49:54 -0600163 int ae_err =
164 ae_decrypt(ctx.get(), nonce_.get(), encrypted_key_material(), key_material_length(),
165 NULL /* additional data */, 0 /* additional data length */, key_material_.get(),
166 tag_.get(), 1 /* final */);
Shawn Willden4db3fbd2014-08-08 22:13:44 -0600167 if (ae_err == AE_INVALID) {
168 // Authentication failed! Decryption probably succeeded(ish), but we don't want to return
169 // any data when the authentication fails, so clear it.
Shawn Willden74aff352014-08-11 14:08:31 -0600170 memset_s(key_material_.get(), 0, key_material_length());
Shawn Willden4db3fbd2014-08-08 22:13:44 -0600171 error_ = KM_ERROR_INVALID_KEY_BLOB;
172 return;
173 } else if (ae_err < 0) {
174 error_ = KM_ERROR_UNKNOWN_ERROR;
175 return;
176 }
Shawn Willdenf2282b32014-08-25 06:49:54 -0600177 assert(ae_err == static_cast<int>(key_material_length()));
Shawn Willden4db3fbd2014-08-08 22:13:44 -0600178 error_ = KM_ERROR_OK;
179}
180
181ae_ctx* KeyBlob::InitializeKeyWrappingContext(const keymaster_key_blob_t& master_key,
182 keymaster_error_t* error) const {
Shawn Willden39b970b2014-08-11 09:11:21 -0600183 size_t derivation_data_length;
184 UniquePtr<const uint8_t[]> derivation_data(BuildDerivationData(&derivation_data_length));
185 if (derivation_data.get() == NULL) {
Shawn Willden4db3fbd2014-08-08 22:13:44 -0600186 *error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
187 return NULL;
188 }
189
190 *error = KM_ERROR_OK;
191 UniquePtr<ae_ctx, AeCtxDelete> ctx(ae_allocate(NULL));
192
193 SHA256_CTX sha256_ctx;
194 UniquePtr<uint8_t[]> hash_buf(new uint8_t[SHA256_DIGEST_LENGTH]);
195 Eraser hash_eraser(hash_buf.get(), SHA256_DIGEST_LENGTH);
196 UniquePtr<uint8_t[]> derived_key(new uint8_t[AES_BLOCK_SIZE]);
197 Eraser derived_key_eraser(derived_key.get(), AES_BLOCK_SIZE);
198
199 if (ctx.get() == NULL || hash_buf.get() == NULL || derived_key.get() == NULL) {
200 *error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
201 return NULL;
202 }
203
204 Eraser sha256_ctx_eraser(sha256_ctx);
205
206 // Hash derivation data.
207 SHA256_Init(&sha256_ctx);
Shawn Willden39b970b2014-08-11 09:11:21 -0600208 SHA256_Update(&sha256_ctx, derivation_data.get(), derivation_data_length);
Shawn Willden4db3fbd2014-08-08 22:13:44 -0600209 SHA256_Final(hash_buf.get(), &sha256_ctx);
210
211 // Encrypt hash with master key to build derived key.
212 AES_KEY aes_key;
213 Eraser aes_key_eraser(AES_KEY);
214 if (AES_set_encrypt_key(master_key.key_material, master_key.key_material_size * 8, &aes_key) !=
215 0) {
216 *error = KM_ERROR_UNKNOWN_ERROR;
217 return NULL;
218 }
219 AES_encrypt(hash_buf.get(), derived_key.get(), &aes_key);
220
221 // Set up AES OCB context using derived key.
222 if (ae_init(ctx.get(), derived_key.get(), AES_BLOCK_SIZE, NONCE_LENGTH, TAG_LENGTH) ==
223 AE_SUCCESS)
224 return ctx.release();
225 else {
Shawn Willden74aff352014-08-11 14:08:31 -0600226 memset_s(ctx.get(), 0, ae_ctx_sizeof());
Shawn Willden4db3fbd2014-08-08 22:13:44 -0600227 return NULL;
228 }
229}
230
Shawn Willden39b970b2014-08-11 09:11:21 -0600231const uint8_t* KeyBlob::BuildDerivationData(size_t* derivation_data_length) const {
232 *derivation_data_length =
233 hidden_.SerializedSize() + enforced_.SerializedSize() + unenforced_.SerializedSize();
234 uint8_t* derivation_data = new uint8_t[*derivation_data_length];
235 if (derivation_data != NULL) {
236 uint8_t* buf = derivation_data;
237 uint8_t* end = derivation_data + *derivation_data_length;
238 buf = hidden_.Serialize(buf, end);
239 buf = enforced_.Serialize(buf, end);
240 buf = unenforced_.Serialize(buf, end);
241 }
242 return derivation_data;
Shawn Willden4db3fbd2014-08-08 22:13:44 -0600243}
244
Shawn Willden1615f2e2014-08-13 10:37:40 -0600245bool KeyBlob::ExtractKeyCharacteristics() {
246 if (!enforced_.GetTagValue(TAG_ALGORITHM, &algorithm_) &&
247 !unenforced_.GetTagValue(TAG_ALGORITHM, &algorithm_)) {
248 error_ = KM_ERROR_UNSUPPORTED_ALGORITHM;
249 return false;
250 }
251 if (!enforced_.GetTagValue(TAG_KEY_SIZE, &key_size_bits_) &&
252 !unenforced_.GetTagValue(TAG_KEY_SIZE, &key_size_bits_)) {
253 error_ = KM_ERROR_UNSUPPORTED_KEY_SIZE;
254 return false;
255 }
256 return true;
257}
258
Shawn Willden4db3fbd2014-08-08 22:13:44 -0600259} // namespace keymaster