session_manager_impl.cc revision 469ec33d58271390c7a5b77030b5e92f4e982a5e
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 37namespace { 38const size_t kWellKnownExponent = 0x10001; 39 40std::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 51namespace trunks { 52 53SessionManagerImpl::SessionManagerImpl(const TrunksFactory& factory) 54 : factory_(factory), 55 session_handle_(kUninitializedHandle) { 56 crypto::EnsureOpenSSLInit(); 57} 58 59SessionManagerImpl::~SessionManagerImpl() { 60 CloseSession(); 61} 62 63void 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 74TPM_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*>(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(kSaltingKey, 123 "", // salt_handle_name. 124 bind_entity, 125 "", // bind_entity_name. 126 nonce_caller, 127 encrypted_secret, 128 session_type, 129 symmetric_algorithm, 130 hash_algorithm, 131 &session_handle_, 132 &nonce_tpm, 133 nullptr); // No Authorization. 134 if (tpm_result) { 135 LOG(ERROR) << "Error creating an authorization session: " 136 << GetErrorString(tpm_result); 137 return tpm_result; 138 } 139 bool hmac_result = delegate->InitSession( 140 session_handle_, 141 nonce_tpm, 142 nonce_caller, 143 salt, 144 bind_authorization_value, 145 enable_encryption); 146 if (!hmac_result) { 147 LOG(ERROR) << "Failed to initialize an authorization session delegate."; 148 return TPM_RC_FAILURE; 149 } 150 return TPM_RC_SUCCESS; 151} 152 153TPM_RC SessionManagerImpl::EncryptSalt(const std::string& salt, 154 std::string* encrypted_salt) { 155 TPM2B_NAME out_name; 156 TPM2B_NAME qualified_name; 157 TPM2B_PUBLIC public_data; 158 public_data.public_area.unique.rsa.size = 0; 159 TPM_RC result = factory_.GetTpm()->ReadPublicSync( 160 kSaltingKey, "" /*object_handle_name (not used)*/, &public_data, 161 &out_name, &qualified_name, nullptr /*authorization_delegate*/); 162 if (result != TPM_RC_SUCCESS) { 163 LOG(ERROR) << "Error fetching salting key public info: " 164 << GetErrorString(result); 165 return result; 166 } 167 if (public_data.public_area.type != TPM_ALG_RSA || 168 public_data.public_area.unique.rsa.size != 256) { 169 LOG(ERROR) << "Invalid salting key attributes."; 170 return TRUNKS_RC_SESSION_SETUP_ERROR; 171 } 172 crypto::ScopedRSA salting_key_rsa(RSA_new()); 173 salting_key_rsa->e = BN_new(); 174 if (!salting_key_rsa->e) { 175 LOG(ERROR) << "Error creating exponent for RSA: " << GetOpenSSLError(); 176 return TRUNKS_RC_SESSION_SETUP_ERROR; 177 } 178 BN_set_word(salting_key_rsa->e, kWellKnownExponent); 179 salting_key_rsa->n = 180 BN_bin2bn(public_data.public_area.unique.rsa.buffer, 181 public_data.public_area.unique.rsa.size, nullptr); 182 if (!salting_key_rsa->n) { 183 LOG(ERROR) << "Error setting public area of rsa key: " << GetOpenSSLError(); 184 return TRUNKS_RC_SESSION_SETUP_ERROR; 185 } 186 crypto::ScopedEVP_PKEY salting_key(EVP_PKEY_new()); 187 if (!EVP_PKEY_set1_RSA(salting_key.get(), salting_key_rsa.get())) { 188 LOG(ERROR) << "Error setting up EVP_PKEY: " << GetOpenSSLError(); 189 return TRUNKS_RC_SESSION_SETUP_ERROR; 190 } 191 // Label for RSAES-OAEP. Defined in TPM2.0 Part1 Architecture, 192 // Appendix B.10.2. 193 const size_t kOaepLabelSize = 7; 194 const char kOaepLabelValue[] = "SECRET\0"; 195 // EVP_PKEY_CTX_set0_rsa_oaep_label takes ownership so we need to malloc. 196 uint8_t* oaep_label = static_cast<uint8_t*>(OPENSSL_malloc(kOaepLabelSize)); 197 memcpy(oaep_label, kOaepLabelValue, kOaepLabelSize); 198 crypto::ScopedEVP_PKEY_CTX salt_encrypt_context( 199 EVP_PKEY_CTX_new(salting_key.get(), nullptr)); 200 if (!EVP_PKEY_encrypt_init(salt_encrypt_context.get()) || 201 !EVP_PKEY_CTX_set_rsa_padding(salt_encrypt_context.get(), 202 RSA_PKCS1_OAEP_PADDING) || 203 !EVP_PKEY_CTX_set_rsa_oaep_md(salt_encrypt_context.get(), EVP_sha256()) || 204 !EVP_PKEY_CTX_set_rsa_mgf1_md(salt_encrypt_context.get(), EVP_sha256()) || 205 !EVP_PKEY_CTX_set0_rsa_oaep_label(salt_encrypt_context.get(), oaep_label, 206 kOaepLabelSize)) { 207 LOG(ERROR) << "Error setting up salt encrypt context: " 208 << GetOpenSSLError(); 209 return TRUNKS_RC_SESSION_SETUP_ERROR; 210 } 211 size_t out_length = EVP_PKEY_size(salting_key.get()); 212 encrypted_salt->resize(out_length); 213 if (!EVP_PKEY_encrypt( 214 salt_encrypt_context.get(), 215 reinterpret_cast<uint8_t*>(string_as_array(encrypted_salt)), 216 &out_length, reinterpret_cast<const uint8_t*>(salt.data()), 217 salt.size())) { 218 LOG(ERROR) << "Error encrypting salt: " << GetOpenSSLError(); 219 return TRUNKS_RC_SESSION_SETUP_ERROR; 220 } 221 encrypted_salt->resize(out_length); 222 return TPM_RC_SUCCESS; 223} 224 225} // namespace trunks 226