session_manager_impl.cc revision ee93b5e81e62fdc0053c74ad565957354e540a99
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/rand.h> 28#include <openssl/rsa.h> 29 30#include "trunks/error_codes.h" 31#include "trunks/tpm_generated.h" 32#include "trunks/tpm_utility.h" 33 34namespace { 35const size_t kWellKnownExponent = 0x10001; 36 37std::string GetOpenSSLError() { 38 BIO* bio = BIO_new(BIO_s_mem()); 39 ERR_print_errors(bio); 40 char* data = nullptr; 41 int data_len = BIO_get_mem_data(bio, &data); 42 std::string error_string(data, data_len); 43 BIO_free(bio); 44 return error_string; 45} 46} // namespace 47 48namespace trunks { 49 50SessionManagerImpl::SessionManagerImpl(const TrunksFactory& factory) 51 : factory_(factory), 52 session_handle_(kUninitializedHandle) { 53 crypto::EnsureOpenSSLInit(); 54} 55 56SessionManagerImpl::~SessionManagerImpl() { 57 CloseSession(); 58} 59 60void SessionManagerImpl::CloseSession() { 61 if (session_handle_ == kUninitializedHandle) { 62 return; 63 } 64 TPM_RC result = factory_.GetTpm()->FlushContextSync(session_handle_, nullptr); 65 if (result != TPM_RC_SUCCESS) { 66 LOG(WARNING) << "Error closing tpm session: " << GetErrorString(result); 67 } 68 session_handle_ = kUninitializedHandle; 69} 70 71TPM_RC SessionManagerImpl::StartSession( 72 TPM_SE session_type, 73 TPMI_DH_ENTITY bind_entity, 74 const std::string& bind_authorization_value, 75 bool enable_encryption, 76 HmacAuthorizationDelegate* delegate) { 77 CHECK(delegate); 78 // If we already have an active session, close it. 79 CloseSession(); 80 81 std::string salt(SHA256_DIGEST_SIZE, 0); 82 unsigned char* salt_buffer = 83 reinterpret_cast<unsigned char*>(string_as_array(&salt)); 84 CHECK_EQ(RAND_bytes(salt_buffer, salt.size()), 1) 85 << "Error generating a cryptographically random salt."; 86 // First we enccrypt the cryptographically secure salt using PKCS1_OAEP 87 // padded RSA public key encryption. This is specified in TPM2.0 88 // Part1 Architecture, Appendix B.10.2. 89 std::string encrypted_salt; 90 TPM_RC salt_result = EncryptSalt(salt, &encrypted_salt); 91 if (salt_result != TPM_RC_SUCCESS) { 92 LOG(ERROR) << "Error encrypting salt: " << GetErrorString(salt_result); 93 return salt_result; 94 } 95 96 TPM2B_ENCRYPTED_SECRET encrypted_secret = 97 Make_TPM2B_ENCRYPTED_SECRET(encrypted_salt); 98 // Then we use TPM2_StartAuthSession to start a HMAC session with the TPM. 99 // The tpm returns the tpm_nonce and the session_handle referencing the 100 // created session. 101 TPMI_ALG_HASH hash_algorithm = TPM_ALG_SHA256; 102 TPMT_SYM_DEF symmetric_algorithm; 103 symmetric_algorithm.algorithm = TPM_ALG_AES; 104 symmetric_algorithm.key_bits.aes = 128; 105 symmetric_algorithm.mode.aes = TPM_ALG_CFB; 106 107 TPM2B_NONCE nonce_caller; 108 TPM2B_NONCE nonce_tpm; 109 // We use sha1_digest_size here because that is the minimum length 110 // needed for the nonce. 111 nonce_caller.size = SHA1_DIGEST_SIZE; 112 CHECK_EQ(RAND_bytes(nonce_caller.buffer, nonce_caller.size), 1) 113 << "Error generating a cryptographically random nonce."; 114 115 Tpm* tpm = factory_.GetTpm(); 116 // The TPM2 command below needs no authorization. This is why we can use 117 // the empty string "", when referring to the handle names for the salting 118 // key and the bind entity. 119 TPM_RC tpm_result = tpm->StartAuthSessionSync(kSaltingKey, 120 "", // salt_handle_name. 121 bind_entity, 122 "", // bind_entity_name. 123 nonce_caller, 124 encrypted_secret, 125 session_type, 126 symmetric_algorithm, 127 hash_algorithm, 128 &session_handle_, 129 &nonce_tpm, 130 nullptr); // No Authorization. 131 if (tpm_result) { 132 LOG(ERROR) << "Error creating an authorization session: " 133 << GetErrorString(tpm_result); 134 return tpm_result; 135 } 136 bool hmac_result = delegate->InitSession( 137 session_handle_, 138 nonce_tpm, 139 nonce_caller, 140 salt, 141 bind_authorization_value, 142 enable_encryption); 143 if (!hmac_result) { 144 LOG(ERROR) << "Failed to initialize an authorization session delegate."; 145 return TPM_RC_FAILURE; 146 } 147 return TPM_RC_SUCCESS; 148} 149 150TPM_RC SessionManagerImpl::EncryptSalt(const std::string& salt, 151 std::string* encrypted_salt) { 152 TPM2B_NAME out_name; 153 TPM2B_NAME qualified_name; 154 TPM2B_PUBLIC public_data; 155 public_data.public_area.unique.rsa.size = 0; 156 TPM_RC result = factory_.GetTpm()->ReadPublicSync( 157 kSaltingKey, "" /*object_handle_name (not used)*/, &public_data, 158 &out_name, &qualified_name, nullptr /*authorization_delegate*/); 159 if (result != TPM_RC_SUCCESS) { 160 LOG(ERROR) << "Error fetching salting key public info: " 161 << GetErrorString(result); 162 return result; 163 } 164 crypto::ScopedRSA 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 crypto::ScopedEVP_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 crypto::ScopedEVP_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*>(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