1 // 2 // Copyright (C) 2015 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/session_manager_impl.h" 18 19 #include <string> 20 21 #include <base/logging.h> 22 #include <base/stl_util.h> 23 #include <crypto/openssl_util.h> 24 #include <openssl/bio.h> 25 #include <openssl/bn.h> 26 #include <openssl/err.h> 27 #include <openssl/evp.h> 28 #if defined(OPENSSL_IS_BORINGSSL) 29 #include <openssl/mem.h> 30 #endif 31 #include <openssl/rand.h> 32 #include <openssl/rsa.h> 33 34 #include "trunks/error_codes.h" 35 #include "trunks/tpm_generated.h" 36 #include "trunks/tpm_utility.h" 37 38 namespace { 39 const size_t kWellKnownExponent = 0x10001; 40 41 std::string GetOpenSSLError() { 42 BIO* bio = BIO_new(BIO_s_mem()); 43 ERR_print_errors(bio); 44 char* data = nullptr; 45 int data_len = BIO_get_mem_data(bio, &data); 46 std::string error_string(data, data_len); 47 BIO_free(bio); 48 return error_string; 49 } 50 } // namespace 51 52 namespace trunks { 53 54 SessionManagerImpl::SessionManagerImpl(const TrunksFactory& factory) 55 : factory_(factory), session_handle_(kUninitializedHandle) { 56 crypto::EnsureOpenSSLInit(); 57 } 58 59 SessionManagerImpl::~SessionManagerImpl() { 60 CloseSession(); 61 } 62 63 void SessionManagerImpl::CloseSession() { 64 if (session_handle_ == kUninitializedHandle) { 65 return; 66 } 67 TPM_RC result = factory_.GetTpm()->FlushContextSync(session_handle_, nullptr); 68 if (result != TPM_RC_SUCCESS) { 69 LOG(WARNING) << "Error closing tpm session: " << GetErrorString(result); 70 } 71 session_handle_ = kUninitializedHandle; 72 } 73 74 TPM_RC SessionManagerImpl::StartSession( 75 TPM_SE session_type, 76 TPMI_DH_ENTITY bind_entity, 77 const std::string& bind_authorization_value, 78 bool enable_encryption, 79 HmacAuthorizationDelegate* delegate) { 80 CHECK(delegate); 81 // If we already have an active session, close it. 82 CloseSession(); 83 84 std::string salt(SHA256_DIGEST_SIZE, 0); 85 unsigned char* salt_buffer = 86 reinterpret_cast<unsigned char*>(base::string_as_array(&salt)); 87 CHECK_EQ(RAND_bytes(salt_buffer, salt.size()), 1) 88 << "Error generating a cryptographically random salt."; 89 // First we encrypt the cryptographically secure salt using PKCS1_OAEP 90 // padded RSA public key encryption. This is specified in TPM2.0 91 // Part1 Architecture, Appendix B.10.2. 92 std::string encrypted_salt; 93 TPM_RC salt_result = EncryptSalt(salt, &encrypted_salt); 94 if (salt_result != TPM_RC_SUCCESS) { 95 LOG(ERROR) << "Error encrypting salt: " << GetErrorString(salt_result); 96 return salt_result; 97 } 98 99 TPM2B_ENCRYPTED_SECRET encrypted_secret = 100 Make_TPM2B_ENCRYPTED_SECRET(encrypted_salt); 101 // Then we use TPM2_StartAuthSession to start a HMAC session with the TPM. 102 // The tpm returns the tpm_nonce and the session_handle referencing the 103 // created session. 104 TPMI_ALG_HASH hash_algorithm = TPM_ALG_SHA256; 105 TPMT_SYM_DEF symmetric_algorithm; 106 symmetric_algorithm.algorithm = TPM_ALG_AES; 107 symmetric_algorithm.key_bits.aes = 128; 108 symmetric_algorithm.mode.aes = TPM_ALG_CFB; 109 110 TPM2B_NONCE nonce_caller; 111 TPM2B_NONCE nonce_tpm; 112 // We use sha1_digest_size here because that is the minimum length 113 // needed for the nonce. 114 nonce_caller.size = SHA1_DIGEST_SIZE; 115 CHECK_EQ(RAND_bytes(nonce_caller.buffer, nonce_caller.size), 1) 116 << "Error generating a cryptographically random nonce."; 117 118 Tpm* tpm = factory_.GetTpm(); 119 // The TPM2 command below needs no authorization. This is why we can use 120 // the empty string "", when referring to the handle names for the salting 121 // key and the bind entity. 122 TPM_RC tpm_result = tpm->StartAuthSessionSync( 123 kSaltingKey, 124 "", // salt_handle_name. 125 bind_entity, 126 "", // bind_entity_name. 127 nonce_caller, encrypted_secret, session_type, symmetric_algorithm, 128 hash_algorithm, &session_handle_, &nonce_tpm, 129 nullptr); // No Authorization. 130 if (tpm_result) { 131 LOG(ERROR) << "Error creating an authorization session: " 132 << GetErrorString(tpm_result); 133 return tpm_result; 134 } 135 bool hmac_result = 136 delegate->InitSession(session_handle_, nonce_tpm, nonce_caller, salt, 137 bind_authorization_value, enable_encryption); 138 if (!hmac_result) { 139 LOG(ERROR) << "Failed to initialize an authorization session delegate."; 140 return TPM_RC_FAILURE; 141 } 142 return TPM_RC_SUCCESS; 143 } 144 145 TPM_RC SessionManagerImpl::EncryptSalt(const std::string& salt, 146 std::string* encrypted_salt) { 147 TPM2B_NAME out_name; 148 TPM2B_NAME qualified_name; 149 TPM2B_PUBLIC public_data; 150 public_data.public_area.unique.rsa.size = 0; 151 TPM_RC result = factory_.GetTpm()->ReadPublicSync( 152 kSaltingKey, "" /*object_handle_name (not used)*/, &public_data, 153 &out_name, &qualified_name, nullptr /*authorization_delegate*/); 154 if (result != TPM_RC_SUCCESS) { 155 LOG(ERROR) << "Error fetching salting key public info: " 156 << GetErrorString(result); 157 return result; 158 } 159 if (public_data.public_area.type != TPM_ALG_RSA || 160 public_data.public_area.unique.rsa.size != 256) { 161 LOG(ERROR) << "Invalid salting key attributes."; 162 return TRUNKS_RC_SESSION_SETUP_ERROR; 163 } 164 bssl::UniquePtr<RSA> salting_key_rsa(RSA_new()); 165 salting_key_rsa->e = BN_new(); 166 if (!salting_key_rsa->e) { 167 LOG(ERROR) << "Error creating exponent for RSA: " << GetOpenSSLError(); 168 return TRUNKS_RC_SESSION_SETUP_ERROR; 169 } 170 BN_set_word(salting_key_rsa->e, kWellKnownExponent); 171 salting_key_rsa->n = 172 BN_bin2bn(public_data.public_area.unique.rsa.buffer, 173 public_data.public_area.unique.rsa.size, nullptr); 174 if (!salting_key_rsa->n) { 175 LOG(ERROR) << "Error setting public area of rsa key: " << GetOpenSSLError(); 176 return TRUNKS_RC_SESSION_SETUP_ERROR; 177 } 178 bssl::UniquePtr<EVP_PKEY> salting_key(EVP_PKEY_new()); 179 if (!EVP_PKEY_set1_RSA(salting_key.get(), salting_key_rsa.get())) { 180 LOG(ERROR) << "Error setting up EVP_PKEY: " << GetOpenSSLError(); 181 return TRUNKS_RC_SESSION_SETUP_ERROR; 182 } 183 // Label for RSAES-OAEP. Defined in TPM2.0 Part1 Architecture, 184 // Appendix B.10.2. 185 const size_t kOaepLabelSize = 7; 186 const char kOaepLabelValue[] = "SECRET\0"; 187 // EVP_PKEY_CTX_set0_rsa_oaep_label takes ownership so we need to malloc. 188 uint8_t* oaep_label = static_cast<uint8_t*>(OPENSSL_malloc(kOaepLabelSize)); 189 memcpy(oaep_label, kOaepLabelValue, kOaepLabelSize); 190 bssl::UniquePtr<EVP_PKEY_CTX> salt_encrypt_context( 191 EVP_PKEY_CTX_new(salting_key.get(), nullptr)); 192 if (!EVP_PKEY_encrypt_init(salt_encrypt_context.get()) || 193 !EVP_PKEY_CTX_set_rsa_padding(salt_encrypt_context.get(), 194 RSA_PKCS1_OAEP_PADDING) || 195 !EVP_PKEY_CTX_set_rsa_oaep_md(salt_encrypt_context.get(), EVP_sha256()) || 196 !EVP_PKEY_CTX_set_rsa_mgf1_md(salt_encrypt_context.get(), EVP_sha256()) || 197 !EVP_PKEY_CTX_set0_rsa_oaep_label(salt_encrypt_context.get(), oaep_label, 198 kOaepLabelSize)) { 199 LOG(ERROR) << "Error setting up salt encrypt context: " 200 << GetOpenSSLError(); 201 return TRUNKS_RC_SESSION_SETUP_ERROR; 202 } 203 size_t out_length = EVP_PKEY_size(salting_key.get()); 204 encrypted_salt->resize(out_length); 205 if (!EVP_PKEY_encrypt( 206 salt_encrypt_context.get(), 207 reinterpret_cast<uint8_t*>(base::string_as_array(encrypted_salt)), 208 &out_length, reinterpret_cast<const uint8_t*>(salt.data()), 209 salt.size())) { 210 LOG(ERROR) << "Error encrypting salt: " << GetOpenSSLError(); 211 return TRUNKS_RC_SESSION_SETUP_ERROR; 212 } 213 encrypted_salt->resize(out_length); 214 return TPM_RC_SUCCESS; 215 } 216 217 } // namespace trunks 218