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