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