1 //
2 // Copyright (C) 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 "trunks/hmac_authorization_delegate.h"
18
19 #include <base/logging.h>
20 #include <base/stl_util.h>
21 #include <crypto/secure_util.h>
22 #include <openssl/aes.h>
23 #include <openssl/hmac.h>
24 #include <openssl/rand.h>
25
26 namespace trunks {
27
28 namespace {
29
30 const uint32_t kDigestBits = 256;
31 const uint16_t kNonceMinSize = 16;
32 const uint16_t kNonceMaxSize = 32;
33 const uint8_t kDecryptSession = 1 << 5;
34 const uint8_t kEncryptSession = 1 << 6;
35 const uint8_t kLabelSize = 4;
36 const size_t kAesIVSize = 16;
37 const uint32_t kTpmBufferSize = 4096;
38
39 } // namespace
40
HmacAuthorizationDelegate()41 HmacAuthorizationDelegate::HmacAuthorizationDelegate()
42 : session_handle_(0),
43 is_parameter_encryption_enabled_(false),
44 nonce_generated_(false),
45 future_authorization_value_set_(false),
46 use_entity_authorization_for_encryption_only_(false) {
47 tpm_nonce_.size = 0;
48 caller_nonce_.size = 0;
49 }
50
~HmacAuthorizationDelegate()51 HmacAuthorizationDelegate::~HmacAuthorizationDelegate() {}
52
GetCommandAuthorization(const std::string & command_hash,bool is_command_parameter_encryption_possible,bool is_response_parameter_encryption_possible,std::string * authorization)53 bool HmacAuthorizationDelegate::GetCommandAuthorization(
54 const std::string& command_hash,
55 bool is_command_parameter_encryption_possible,
56 bool is_response_parameter_encryption_possible,
57 std::string* authorization) {
58 if (!session_handle_) {
59 authorization->clear();
60 LOG(ERROR) << "Delegate being used before Initialization,";
61 return false;
62 }
63 TPMS_AUTH_COMMAND auth;
64 auth.session_handle = session_handle_;
65 if (!nonce_generated_) {
66 RegenerateCallerNonce();
67 }
68 auth.nonce = caller_nonce_;
69 auth.session_attributes = kContinueSession;
70 if (is_parameter_encryption_enabled_) {
71 if (is_command_parameter_encryption_possible) {
72 auth.session_attributes |= kDecryptSession;
73 }
74 if (is_response_parameter_encryption_possible) {
75 auth.session_attributes |= kEncryptSession;
76 }
77 }
78 // We reset the |nonce_generated| flag in preperation of the next command.
79 nonce_generated_ = false;
80 std::string attributes_bytes;
81 CHECK_EQ(Serialize_TPMA_SESSION(auth.session_attributes, &attributes_bytes),
82 TPM_RC_SUCCESS)
83 << "Error serializing session attributes.";
84
85 std::string hmac_data;
86 std::string hmac_key;
87 if (!use_entity_authorization_for_encryption_only_) {
88 hmac_key = session_key_ + entity_authorization_value_;
89 } else {
90 hmac_key = session_key_;
91 }
92 hmac_data.append(command_hash);
93 hmac_data.append(reinterpret_cast<const char*>(caller_nonce_.buffer),
94 caller_nonce_.size);
95 hmac_data.append(reinterpret_cast<const char*>(tpm_nonce_.buffer),
96 tpm_nonce_.size);
97 hmac_data.append(attributes_bytes);
98 std::string digest = HmacSha256(hmac_key, hmac_data);
99 auth.hmac = Make_TPM2B_DIGEST(digest);
100
101 TPM_RC serialize_error = Serialize_TPMS_AUTH_COMMAND(auth, authorization);
102 if (serialize_error != TPM_RC_SUCCESS) {
103 LOG(ERROR) << "Could not serialize command auth.";
104 return false;
105 }
106 return true;
107 }
108
CheckResponseAuthorization(const std::string & response_hash,const std::string & authorization)109 bool HmacAuthorizationDelegate::CheckResponseAuthorization(
110 const std::string& response_hash,
111 const std::string& authorization) {
112 if (!session_handle_) {
113 return false;
114 }
115 TPMS_AUTH_RESPONSE auth_response;
116 std::string mutable_auth_string(authorization);
117 TPM_RC parse_error;
118 parse_error =
119 Parse_TPMS_AUTH_RESPONSE(&mutable_auth_string, &auth_response, nullptr);
120 if (parse_error != TPM_RC_SUCCESS) {
121 LOG(ERROR) << "Could not parse authorization response.";
122 return false;
123 }
124 if (auth_response.hmac.size != kHashDigestSize) {
125 LOG(ERROR) << "TPM auth hmac was incorrect size.";
126 return false;
127 }
128 if (auth_response.nonce.size < kNonceMinSize ||
129 auth_response.nonce.size > kNonceMaxSize) {
130 LOG(ERROR) << "TPM_nonce is not the correct length.";
131 return false;
132 }
133 tpm_nonce_ = auth_response.nonce;
134 std::string attributes_bytes;
135 CHECK_EQ(Serialize_TPMA_SESSION(auth_response.session_attributes,
136 &attributes_bytes),
137 TPM_RC_SUCCESS)
138 << "Error serializing session attributes.";
139
140 std::string hmac_data;
141 std::string hmac_key;
142 if (!use_entity_authorization_for_encryption_only_) {
143 // In a special case with TPM2_HierarchyChangeAuth, we need to use the
144 // auth_value that was set.
145 if (future_authorization_value_set_) {
146 hmac_key = session_key_ + future_authorization_value_;
147 future_authorization_value_set_ = false;
148 } else {
149 hmac_key = session_key_ + entity_authorization_value_;
150 }
151 } else {
152 hmac_key = session_key_;
153 }
154 hmac_data.append(response_hash);
155 hmac_data.append(reinterpret_cast<const char*>(tpm_nonce_.buffer),
156 tpm_nonce_.size);
157 hmac_data.append(reinterpret_cast<const char*>(caller_nonce_.buffer),
158 caller_nonce_.size);
159 hmac_data.append(attributes_bytes);
160 std::string digest = HmacSha256(hmac_key, hmac_data);
161 CHECK_EQ(digest.size(), auth_response.hmac.size);
162 if (!crypto::SecureMemEqual(digest.data(), auth_response.hmac.buffer,
163 digest.size())) {
164 LOG(ERROR) << "Authorization response hash did not match expected value.";
165 return false;
166 }
167 return true;
168 }
169
EncryptCommandParameter(std::string * parameter)170 bool HmacAuthorizationDelegate::EncryptCommandParameter(
171 std::string* parameter) {
172 CHECK(parameter);
173 if (!session_handle_) {
174 LOG(ERROR) << __func__ << ": Invalid session handle.";
175 return false;
176 }
177 if (!is_parameter_encryption_enabled_) {
178 // No parameter encryption enabled.
179 return true;
180 }
181 if (parameter->size() > kTpmBufferSize) {
182 LOG(ERROR) << "Parameter size is too large for TPM decryption.";
183 return false;
184 }
185 RegenerateCallerNonce();
186 nonce_generated_ = true;
187 AesOperation(parameter, caller_nonce_, tpm_nonce_, AES_ENCRYPT);
188 return true;
189 }
190
DecryptResponseParameter(std::string * parameter)191 bool HmacAuthorizationDelegate::DecryptResponseParameter(
192 std::string* parameter) {
193 CHECK(parameter);
194 if (!session_handle_) {
195 LOG(ERROR) << __func__ << ": Invalid session handle.";
196 return false;
197 }
198 if (!is_parameter_encryption_enabled_) {
199 // No parameter decryption enabled.
200 return true;
201 }
202 if (parameter->size() > kTpmBufferSize) {
203 LOG(ERROR) << "Parameter size is too large for TPM encryption.";
204 return false;
205 }
206 AesOperation(parameter, tpm_nonce_, caller_nonce_, AES_DECRYPT);
207 return true;
208 }
209
InitSession(TPM_HANDLE session_handle,const TPM2B_NONCE & tpm_nonce,const TPM2B_NONCE & caller_nonce,const std::string & salt,const std::string & bind_auth_value,bool enable_parameter_encryption)210 bool HmacAuthorizationDelegate::InitSession(TPM_HANDLE session_handle,
211 const TPM2B_NONCE& tpm_nonce,
212 const TPM2B_NONCE& caller_nonce,
213 const std::string& salt,
214 const std::string& bind_auth_value,
215 bool enable_parameter_encryption) {
216 session_handle_ = session_handle;
217 if (caller_nonce.size < kNonceMinSize || caller_nonce.size > kNonceMaxSize ||
218 tpm_nonce.size < kNonceMinSize || tpm_nonce.size > kNonceMaxSize) {
219 LOG(INFO) << "Session Nonces have to be between 16 and 32 bytes long.";
220 return false;
221 }
222 tpm_nonce_ = tpm_nonce;
223 caller_nonce_ = caller_nonce;
224 std::string session_key_label("ATH", kLabelSize);
225 is_parameter_encryption_enabled_ = enable_parameter_encryption;
226 if (salt.length() == 0 && bind_auth_value.length() == 0) {
227 // SessionKey is set to the empty string for unsalted and
228 // unbound sessions.
229 session_key_ = std::string();
230 } else {
231 session_key_ = CreateKey(bind_auth_value + salt, session_key_label,
232 tpm_nonce_, caller_nonce_);
233 }
234 return true;
235 }
236
set_future_authorization_value(const std::string & auth_value)237 void HmacAuthorizationDelegate::set_future_authorization_value(
238 const std::string& auth_value) {
239 future_authorization_value_ = auth_value;
240 future_authorization_value_set_ = true;
241 }
242
CreateKey(const std::string & hmac_key,const std::string & label,const TPM2B_NONCE & nonce_newer,const TPM2B_NONCE & nonce_older)243 std::string HmacAuthorizationDelegate::CreateKey(
244 const std::string& hmac_key,
245 const std::string& label,
246 const TPM2B_NONCE& nonce_newer,
247 const TPM2B_NONCE& nonce_older) {
248 std::string counter;
249 std::string digest_size_bits;
250 if (Serialize_uint32_t(1, &counter) != TPM_RC_SUCCESS ||
251 Serialize_uint32_t(kDigestBits, &digest_size_bits) != TPM_RC_SUCCESS) {
252 LOG(ERROR) << "Error serializing uint32_t during session key generation.";
253 return std::string();
254 }
255 CHECK_EQ(counter.size(), sizeof(uint32_t));
256 CHECK_EQ(digest_size_bits.size(), sizeof(uint32_t));
257 CHECK_EQ(label.size(), kLabelSize);
258
259 std::string data;
260 data.append(counter);
261 data.append(label);
262 data.append(reinterpret_cast<const char*>(nonce_newer.buffer),
263 nonce_newer.size);
264 data.append(reinterpret_cast<const char*>(nonce_older.buffer),
265 nonce_older.size);
266 data.append(digest_size_bits);
267 std::string key = HmacSha256(hmac_key, data);
268 return key;
269 }
270
HmacSha256(const std::string & key,const std::string & data)271 std::string HmacAuthorizationDelegate::HmacSha256(const std::string& key,
272 const std::string& data) {
273 unsigned char digest[EVP_MAX_MD_SIZE];
274 unsigned int digest_length;
275 HMAC(EVP_sha256(), key.data(), key.size(),
276 reinterpret_cast<const unsigned char*>(data.data()), data.size(), digest,
277 &digest_length);
278 CHECK_EQ(digest_length, kHashDigestSize);
279 return std::string(reinterpret_cast<char*>(digest), digest_length);
280 }
281
AesOperation(std::string * parameter,const TPM2B_NONCE & nonce_newer,const TPM2B_NONCE & nonce_older,int operation_type)282 void HmacAuthorizationDelegate::AesOperation(std::string* parameter,
283 const TPM2B_NONCE& nonce_newer,
284 const TPM2B_NONCE& nonce_older,
285 int operation_type) {
286 std::string label("CFB", kLabelSize);
287 std::string compound_key =
288 CreateKey(session_key_ + entity_authorization_value_, label, nonce_newer,
289 nonce_older);
290 CHECK_EQ(compound_key.size(), kAesKeySize + kAesIVSize);
291 unsigned char aes_key[kAesKeySize];
292 unsigned char aes_iv[kAesIVSize];
293 memcpy(aes_key, &compound_key[0], kAesKeySize);
294 memcpy(aes_iv, &compound_key[kAesKeySize], kAesIVSize);
295 AES_KEY key;
296 int iv_offset = 0;
297 AES_set_encrypt_key(aes_key, kAesKeySize * 8, &key);
298 unsigned char decrypted[kTpmBufferSize];
299 AES_cfb128_encrypt(reinterpret_cast<const unsigned char*>(parameter->data()),
300 decrypted, parameter->size(), &key, aes_iv, &iv_offset,
301 operation_type);
302 memcpy(string_as_array(parameter), decrypted, parameter->size());
303 }
304
RegenerateCallerNonce()305 void HmacAuthorizationDelegate::RegenerateCallerNonce() {
306 CHECK(session_handle_);
307 // RAND_bytes takes a signed number, but since nonce_size is guaranteed to be
308 // less than 32 bytes and greater than 16 we dont have to worry about it.
309 CHECK_EQ(RAND_bytes(caller_nonce_.buffer, caller_nonce_.size), 1)
310 << "Error regnerating a cryptographically random nonce.";
311 }
312
313 } // namespace trunks
314