• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/memory/scoped_ptr.h>
21 #include <base/stl_util.h>
22 #include <crypto/secure_util.h>
23 #include <openssl/aes.h>
24 #include <openssl/hmac.h>
25 #include <openssl/rand.h>
26 
27 namespace trunks {
28 
29 namespace {
30 
31 const uint32_t kDigestBits = 256;
32 const uint16_t kNonceMinSize = 16;
33 const uint16_t kNonceMaxSize = 32;
34 const uint8_t kDecryptSession = 1<<5;
35 const uint8_t kEncryptSession = 1<<6;
36 const uint8_t kLabelSize = 4;
37 const size_t kAesIVSize = 16;
38 const uint32_t kTpmBufferSize = 4096;
39 
40 }  // namespace
41 
HmacAuthorizationDelegate()42 HmacAuthorizationDelegate::HmacAuthorizationDelegate()
43     : session_handle_(0),
44       is_parameter_encryption_enabled_(false),
45       nonce_generated_(false),
46       future_authorization_value_set_(false),
47       use_entity_authorization_for_encryption_only_(false) {
48   tpm_nonce_.size = 0;
49   caller_nonce_.size = 0;
50 }
51 
~HmacAuthorizationDelegate()52 HmacAuthorizationDelegate::~HmacAuthorizationDelegate() {}
53 
GetCommandAuthorization(const std::string & command_hash,bool is_command_parameter_encryption_possible,bool is_response_parameter_encryption_possible,std::string * authorization)54 bool HmacAuthorizationDelegate::GetCommandAuthorization(
55     const std::string& command_hash,
56     bool is_command_parameter_encryption_possible,
57     bool is_response_parameter_encryption_possible,
58     std::string* authorization) {
59   if (!session_handle_) {
60     authorization->clear();
61     LOG(ERROR) << "Delegate being used before Initialization,";
62     return false;
63   }
64   TPMS_AUTH_COMMAND auth;
65   auth.session_handle = session_handle_;
66   if (!nonce_generated_) {
67     RegenerateCallerNonce();
68   }
69   auth.nonce = caller_nonce_;
70   auth.session_attributes = kContinueSession;
71   if (is_parameter_encryption_enabled_) {
72     if (is_command_parameter_encryption_possible) {
73       auth.session_attributes |= kDecryptSession;
74     }
75     if (is_response_parameter_encryption_possible) {
76       auth.session_attributes |= kEncryptSession;
77     }
78   }
79   // We reset the |nonce_generated| flag in preperation of the next command.
80   nonce_generated_ = false;
81   std::string attributes_bytes;
82   CHECK_EQ(Serialize_TPMA_SESSION(auth.session_attributes, &attributes_bytes),
83            TPM_RC_SUCCESS) << "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 = Parse_TPMS_AUTH_RESPONSE(&mutable_auth_string,
119                                          &auth_response,
120                                          nullptr);
121   if (parse_error != TPM_RC_SUCCESS) {
122     LOG(ERROR) << "Could not parse authorization response.";
123     return false;
124   }
125   if (auth_response.hmac.size != kHashDigestSize) {
126     LOG(ERROR) << "TPM auth hmac was incorrect size.";
127     return false;
128   }
129   if (auth_response.nonce.size < kNonceMinSize ||
130       auth_response.nonce.size > kNonceMaxSize) {
131     LOG(ERROR) << "TPM_nonce is not the correct length.";
132     return false;
133   }
134   tpm_nonce_ = auth_response.nonce;
135   std::string attributes_bytes;
136   CHECK_EQ(Serialize_TPMA_SESSION(auth_response.session_attributes,
137                                   &attributes_bytes),
138            TPM_RC_SUCCESS) << "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(
211     TPM_HANDLE session_handle,
212     const TPM2B_NONCE& tpm_nonce,
213     const TPM2B_NONCE& caller_nonce,
214     const std::string& salt,
215     const std::string& bind_auth_value,
216     bool enable_parameter_encryption) {
217   session_handle_ = session_handle;
218   if (caller_nonce.size < kNonceMinSize || caller_nonce.size > kNonceMaxSize ||
219       tpm_nonce.size < kNonceMinSize || tpm_nonce.size > kNonceMaxSize) {
220     LOG(INFO) << "Session Nonces have to be between 16 and 32 bytes long.";
221     return false;
222   }
223   tpm_nonce_ = tpm_nonce;
224   caller_nonce_ = caller_nonce;
225   std::string session_key_label("ATH", kLabelSize);
226   is_parameter_encryption_enabled_ = enable_parameter_encryption;
227   if (salt.length() == 0 && bind_auth_value.length() == 0) {
228     // SessionKey is set to the empty string for unsalted and
229     // unbound sessions.
230     session_key_ = std::string();
231   } else {
232     session_key_ = CreateKey(bind_auth_value + salt,
233                              session_key_label,
234                              tpm_nonce_,
235                              caller_nonce_);
236   }
237   return true;
238 }
239 
set_future_authorization_value(const std::string & auth_value)240 void HmacAuthorizationDelegate::set_future_authorization_value(
241     const std::string& auth_value) {
242   future_authorization_value_ = auth_value;
243   future_authorization_value_set_ = true;
244 }
245 
CreateKey(const std::string & hmac_key,const std::string & label,const TPM2B_NONCE & nonce_newer,const TPM2B_NONCE & nonce_older)246 std::string HmacAuthorizationDelegate::CreateKey(
247     const std::string& hmac_key,
248     const std::string& label,
249     const TPM2B_NONCE& nonce_newer,
250     const TPM2B_NONCE& nonce_older) {
251   std::string counter;
252   std::string digest_size_bits;
253   if (Serialize_uint32_t(1, &counter) != TPM_RC_SUCCESS ||
254       Serialize_uint32_t(kDigestBits, &digest_size_bits) != TPM_RC_SUCCESS) {
255     LOG(ERROR) << "Error serializing uint32_t during session key generation.";
256     return std::string();
257   }
258   CHECK_EQ(counter.size(), sizeof(uint32_t));
259   CHECK_EQ(digest_size_bits.size(), sizeof(uint32_t));
260   CHECK_EQ(label.size(), kLabelSize);
261 
262   std::string data;
263   data.append(counter);
264   data.append(label);
265   data.append(reinterpret_cast<const char*>(nonce_newer.buffer),
266               nonce_newer.size);
267   data.append(reinterpret_cast<const char*>(nonce_older.buffer),
268               nonce_older.size);
269   data.append(digest_size_bits);
270   std::string key = HmacSha256(hmac_key, data);
271   return key;
272 }
273 
HmacSha256(const std::string & key,const std::string & data)274 std::string HmacAuthorizationDelegate::HmacSha256(const std::string& key,
275                                                   const std::string& data) {
276   unsigned char digest[EVP_MAX_MD_SIZE];
277   unsigned int digest_length;
278   HMAC(EVP_sha256(),
279        key.data(),
280        key.size(),
281        reinterpret_cast<const unsigned char*>(data.data()),
282        data.size(),
283        digest,
284        &digest_length);
285   CHECK_EQ(digest_length, kHashDigestSize);
286   return std::string(reinterpret_cast<char*>(digest), digest_length);
287 }
288 
AesOperation(std::string * parameter,const TPM2B_NONCE & nonce_newer,const TPM2B_NONCE & nonce_older,int operation_type)289 void HmacAuthorizationDelegate::AesOperation(std::string* parameter,
290                                              const TPM2B_NONCE& nonce_newer,
291                                              const TPM2B_NONCE& nonce_older,
292                                              int operation_type) {
293   std::string label("CFB", kLabelSize);
294   std::string compound_key = CreateKey(
295       session_key_ + entity_authorization_value_,
296       label,
297       nonce_newer,
298       nonce_older);
299   CHECK_EQ(compound_key.size(), kAesKeySize + kAesIVSize);
300   unsigned char aes_key[kAesKeySize];
301   unsigned char aes_iv[kAesIVSize];
302   memcpy(aes_key, &compound_key[0], kAesKeySize);
303   memcpy(aes_iv, &compound_key[kAesKeySize], kAesIVSize);
304   AES_KEY key;
305   int iv_offset = 0;
306   AES_set_encrypt_key(aes_key, kAesKeySize*8, &key);
307   unsigned char decrypted[kTpmBufferSize];
308   AES_cfb128_encrypt(reinterpret_cast<const unsigned char*>(parameter->data()),
309                      decrypted,
310                      parameter->size(),
311                      &key, aes_iv,
312                      &iv_offset,
313                      operation_type);
314   memcpy(string_as_array(parameter), decrypted, parameter->size());
315 }
316 
RegenerateCallerNonce()317 void HmacAuthorizationDelegate::RegenerateCallerNonce() {
318   CHECK(session_handle_);
319   // RAND_bytes takes a signed number, but since nonce_size is guaranteed to be
320   // less than 32 bytes and greater than 16 we dont have to worry about it.
321   CHECK_EQ(RAND_bytes(caller_nonce_.buffer, caller_nonce_.size), 1) <<
322       "Error regnerating a cryptographically random nonce.";
323 }
324 
325 }  // namespace trunks
326