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