Home | History | Annotate | Download | only in trunks
      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 
     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 
     51 HmacAuthorizationDelegate::~HmacAuthorizationDelegate() {}
     52 
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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(base::string_as_array(parameter), decrypted, parameter->size());
    303 }
    304 
    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