• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
GetOpenSSLError()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 
SessionManagerImpl(const TrunksFactory & factory)51 SessionManagerImpl::SessionManagerImpl(const TrunksFactory& factory)
52     : factory_(factory),
53       session_handle_(kUninitializedHandle) {
54   crypto::EnsureOpenSSLInit();
55 }
56 
~SessionManagerImpl()57 SessionManagerImpl::~SessionManagerImpl() {
58   CloseSession();
59 }
60 
CloseSession()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 
StartSession(TPM_SE session_type,TPMI_DH_ENTITY bind_entity,const std::string & bind_authorization_value,bool enable_encryption,HmacAuthorizationDelegate * delegate)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 
EncryptSalt(const std::string & salt,std::string * encrypted_salt)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