hmac_authorization_delegate.cc revision 30c921db09d27768acc1ea0d8b6a9c8e814f931a
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
26namespace trunks {
27
28namespace {
29
30const uint32_t kDigestBits = 256;
31const uint16_t kNonceMinSize = 16;
32const uint16_t kNonceMaxSize = 32;
33const uint8_t kDecryptSession = 1 << 5;
34const uint8_t kEncryptSession = 1 << 6;
35const uint8_t kLabelSize = 4;
36const size_t kAesIVSize = 16;
37const uint32_t kTpmBufferSize = 4096;
38
39}  // namespace
40
41HmacAuthorizationDelegate::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
51HmacAuthorizationDelegate::~HmacAuthorizationDelegate() {}
52
53bool 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
109bool 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
170bool 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
191bool 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
210bool 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
237void 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
243std::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
271std::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
282void 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
305void 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