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/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 
     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 
     52 HmacAuthorizationDelegate::~HmacAuthorizationDelegate() {}
     53 
     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 
    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 
    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(
    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 
    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 
    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 
    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 
    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 
    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