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(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