hmac_authorization_delegate.cc revision 4dc4629c415e7ca90ff146d7bb75b5646ecd8b17
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
27namespace trunks {
28
29namespace {
30
31const uint32_t kDigestBits = 256;
32const uint16_t kNonceMinSize = 16;
33const uint16_t kNonceMaxSize = 32;
34const uint8_t kDecryptSession = 1 << 5;
35const uint8_t kEncryptSession = 1 << 6;
36const uint8_t kLabelSize = 4;
37const size_t kAesIVSize = 16;
38const uint32_t kTpmBufferSize = 4096;
39
40}  // namespace
41
42HmacAuthorizationDelegate::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
52HmacAuthorizationDelegate::~HmacAuthorizationDelegate() {}
53
54bool 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)
84      << "Error serializing session attributes.";
85
86  std::string hmac_data;
87  std::string hmac_key;
88  if (!use_entity_authorization_for_encryption_only_) {
89    hmac_key = session_key_ + entity_authorization_value_;
90  } else {
91    hmac_key = session_key_;
92  }
93  hmac_data.append(command_hash);
94  hmac_data.append(reinterpret_cast<const char*>(caller_nonce_.buffer),
95                   caller_nonce_.size);
96  hmac_data.append(reinterpret_cast<const char*>(tpm_nonce_.buffer),
97                   tpm_nonce_.size);
98  hmac_data.append(attributes_bytes);
99  std::string digest = HmacSha256(hmac_key, hmac_data);
100  auth.hmac = Make_TPM2B_DIGEST(digest);
101
102  TPM_RC serialize_error = Serialize_TPMS_AUTH_COMMAND(auth, authorization);
103  if (serialize_error != TPM_RC_SUCCESS) {
104    LOG(ERROR) << "Could not serialize command auth.";
105    return false;
106  }
107  return true;
108}
109
110bool HmacAuthorizationDelegate::CheckResponseAuthorization(
111    const std::string& response_hash,
112    const std::string& authorization) {
113  if (!session_handle_) {
114    return false;
115  }
116  TPMS_AUTH_RESPONSE auth_response;
117  std::string mutable_auth_string(authorization);
118  TPM_RC parse_error;
119  parse_error =
120      Parse_TPMS_AUTH_RESPONSE(&mutable_auth_string, &auth_response, 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)
139      << "Error serializing session attributes.";
140
141  std::string hmac_data;
142  std::string hmac_key;
143  if (!use_entity_authorization_for_encryption_only_) {
144    // In a special case with TPM2_HierarchyChangeAuth, we need to use the
145    // auth_value that was set.
146    if (future_authorization_value_set_) {
147      hmac_key = session_key_ + future_authorization_value_;
148      future_authorization_value_set_ = false;
149    } else {
150      hmac_key = session_key_ + entity_authorization_value_;
151    }
152  } else {
153    hmac_key = session_key_;
154  }
155  hmac_data.append(response_hash);
156  hmac_data.append(reinterpret_cast<const char*>(tpm_nonce_.buffer),
157                   tpm_nonce_.size);
158  hmac_data.append(reinterpret_cast<const char*>(caller_nonce_.buffer),
159                   caller_nonce_.size);
160  hmac_data.append(attributes_bytes);
161  std::string digest = HmacSha256(hmac_key, hmac_data);
162  CHECK_EQ(digest.size(), auth_response.hmac.size);
163  if (!crypto::SecureMemEqual(digest.data(), auth_response.hmac.buffer,
164                              digest.size())) {
165    LOG(ERROR) << "Authorization response hash did not match expected value.";
166    return false;
167  }
168  return true;
169}
170
171bool HmacAuthorizationDelegate::EncryptCommandParameter(
172    std::string* parameter) {
173  CHECK(parameter);
174  if (!session_handle_) {
175    LOG(ERROR) << __func__ << ": Invalid session handle.";
176    return false;
177  }
178  if (!is_parameter_encryption_enabled_) {
179    // No parameter encryption enabled.
180    return true;
181  }
182  if (parameter->size() > kTpmBufferSize) {
183    LOG(ERROR) << "Parameter size is too large for TPM decryption.";
184    return false;
185  }
186  RegenerateCallerNonce();
187  nonce_generated_ = true;
188  AesOperation(parameter, caller_nonce_, tpm_nonce_, AES_ENCRYPT);
189  return true;
190}
191
192bool HmacAuthorizationDelegate::DecryptResponseParameter(
193    std::string* parameter) {
194  CHECK(parameter);
195  if (!session_handle_) {
196    LOG(ERROR) << __func__ << ": Invalid session handle.";
197    return false;
198  }
199  if (!is_parameter_encryption_enabled_) {
200    // No parameter decryption enabled.
201    return true;
202  }
203  if (parameter->size() > kTpmBufferSize) {
204    LOG(ERROR) << "Parameter size is too large for TPM encryption.";
205    return false;
206  }
207  AesOperation(parameter, tpm_nonce_, caller_nonce_, AES_DECRYPT);
208  return true;
209}
210
211bool HmacAuthorizationDelegate::InitSession(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, session_key_label,
233                             tpm_nonce_, caller_nonce_);
234  }
235  return true;
236}
237
238void HmacAuthorizationDelegate::set_future_authorization_value(
239    const std::string& auth_value) {
240  future_authorization_value_ = auth_value;
241  future_authorization_value_set_ = true;
242}
243
244std::string HmacAuthorizationDelegate::CreateKey(
245    const std::string& hmac_key,
246    const std::string& label,
247    const TPM2B_NONCE& nonce_newer,
248    const TPM2B_NONCE& nonce_older) {
249  std::string counter;
250  std::string digest_size_bits;
251  if (Serialize_uint32_t(1, &counter) != TPM_RC_SUCCESS ||
252      Serialize_uint32_t(kDigestBits, &digest_size_bits) != TPM_RC_SUCCESS) {
253    LOG(ERROR) << "Error serializing uint32_t during session key generation.";
254    return std::string();
255  }
256  CHECK_EQ(counter.size(), sizeof(uint32_t));
257  CHECK_EQ(digest_size_bits.size(), sizeof(uint32_t));
258  CHECK_EQ(label.size(), kLabelSize);
259
260  std::string data;
261  data.append(counter);
262  data.append(label);
263  data.append(reinterpret_cast<const char*>(nonce_newer.buffer),
264              nonce_newer.size);
265  data.append(reinterpret_cast<const char*>(nonce_older.buffer),
266              nonce_older.size);
267  data.append(digest_size_bits);
268  std::string key = HmacSha256(hmac_key, data);
269  return key;
270}
271
272std::string HmacAuthorizationDelegate::HmacSha256(const std::string& key,
273                                                  const std::string& data) {
274  unsigned char digest[EVP_MAX_MD_SIZE];
275  unsigned int digest_length;
276  HMAC(EVP_sha256(), key.data(), key.size(),
277       reinterpret_cast<const unsigned char*>(data.data()), data.size(), digest,
278       &digest_length);
279  CHECK_EQ(digest_length, kHashDigestSize);
280  return std::string(reinterpret_cast<char*>(digest), digest_length);
281}
282
283void HmacAuthorizationDelegate::AesOperation(std::string* parameter,
284                                             const TPM2B_NONCE& nonce_newer,
285                                             const TPM2B_NONCE& nonce_older,
286                                             int operation_type) {
287  std::string label("CFB", kLabelSize);
288  std::string compound_key =
289      CreateKey(session_key_ + entity_authorization_value_, label, nonce_newer,
290                nonce_older);
291  CHECK_EQ(compound_key.size(), kAesKeySize + kAesIVSize);
292  unsigned char aes_key[kAesKeySize];
293  unsigned char aes_iv[kAesIVSize];
294  memcpy(aes_key, &compound_key[0], kAesKeySize);
295  memcpy(aes_iv, &compound_key[kAesKeySize], kAesIVSize);
296  AES_KEY key;
297  int iv_offset = 0;
298  AES_set_encrypt_key(aes_key, kAesKeySize * 8, &key);
299  unsigned char decrypted[kTpmBufferSize];
300  AES_cfb128_encrypt(reinterpret_cast<const unsigned char*>(parameter->data()),
301                     decrypted, parameter->size(), &key, aes_iv, &iv_offset,
302                     operation_type);
303  memcpy(string_as_array(parameter), decrypted, parameter->size());
304}
305
306void HmacAuthorizationDelegate::RegenerateCallerNonce() {
307  CHECK(session_handle_);
308  // RAND_bytes takes a signed number, but since nonce_size is guaranteed to be
309  // less than 32 bytes and greater than 16 we dont have to worry about it.
310  CHECK_EQ(RAND_bytes(caller_nonce_.buffer, caller_nonce_.size), 1)
311      << "Error regnerating a cryptographically random nonce.";
312}
313
314}  // namespace trunks
315