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