Skip to content

Commit 2fafbeb

Browse files
committed
Resolve SSL_PRIVATE_METHOD and certificate slots functionality
1 parent 3ef4347 commit 2fafbeb

File tree

4 files changed

+193
-13
lines changed

4 files changed

+193
-13
lines changed

ssl/ssl_cert.cc

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -262,15 +262,24 @@ static enum leaf_cert_and_privkey_result_t do_leaf_cert_and_privkey_checks(
262262
// returns |leaf_cert_and_privkey_mismatch|. Otherwise it returns
263263
// |leaf_cert_and_privkey_ok|.
264264
static enum leaf_cert_and_privkey_result_t check_leaf_cert_and_privkey(
265-
CRYPTO_BUFFER *leaf_buffer, EVP_PKEY *privkey) {
265+
CRYPTO_BUFFER *leaf_buffer, EVP_PKEY *privkey, int *out_pubslot_idx) {
266266
CBS cert_cbs;
267267
CRYPTO_BUFFER_init_CBS(leaf_buffer, &cert_cbs);
268268
UniquePtr<EVP_PKEY> pubkey = ssl_cert_parse_pubkey(&cert_cbs);
269269
if (pubkey == nullptr) {
270270
OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
271271
return leaf_cert_and_privkey_error;
272272
}
273-
return do_leaf_cert_and_privkey_checks(&cert_cbs, pubkey.get(), privkey);
273+
enum leaf_cert_and_privkey_result_t result = do_leaf_cert_and_privkey_checks(
274+
&cert_cbs, pubkey.get(), privkey);
275+
if(out_pubslot_idx != nullptr) {
276+
if(result == leaf_cert_and_privkey_ok) {
277+
*out_pubslot_idx = ssl_get_certificate_slot_index(pubkey.get());
278+
} else {
279+
*out_pubslot_idx = -1;
280+
}
281+
}
282+
return result;
274283
}
275284

276285
static int cert_set_chain_and_key(
@@ -291,7 +300,9 @@ static int cert_set_chain_and_key(
291300
return 0;
292301
}
293302

294-
switch (check_leaf_cert_and_privkey(leaf_buf, privkey)) {
303+
int slot_idx = -1;
304+
305+
switch (check_leaf_cert_and_privkey(leaf_buf, privkey, &slot_idx)) {
295306
case leaf_cert_and_privkey_error:
296307
return 0;
297308
case leaf_cert_and_privkey_mismatch:
@@ -300,27 +311,35 @@ static int cert_set_chain_and_key(
300311
case leaf_cert_and_privkey_ok:
301312
break;
302313
}
314+
assert(slot_idx >= 0);
303315

304316
if (!ssl_cert_check_cert_private_keys_usage(cert)) {
305317
return 0;
306318
}
307319

308-
// Certificate slot validity already checked in |check_leaf_cert_and_privkey|.
309-
int idx = ssl_get_certificate_slot_index(privkey);
310-
assert(idx >= 0);
311-
CERT_PKEY *cert_pkey = &cert->cert_private_keys[idx];
320+
// Certificate slot validity already checked and set by
321+
// |check_leaf_cert_and_privkey|.
322+
CERT_PKEY *cert_pkey = &cert->cert_private_keys[slot_idx];
312323

313-
// Update certificate slot index once all checks have passed.
324+
// If privatekey is currently set then reset it.
325+
// We are will either and a new privatekey or will be setting
326+
// a |privkey_method| which will affect all slots.
314327
if (cert_pkey->privatekey) {
315328
cert_pkey->privatekey.reset();
316329
}
317-
cert_pkey->privatekey = UpRef(privkey);
318-
cert->key_method = privkey_method;
330+
331+
if(privkey != nullptr) {
332+
cert_pkey->privatekey = UpRef(privkey);
333+
} else {
334+
cert->key_method = privkey_method;
335+
}
336+
319337
if (cert_pkey->chain) {
320338
cert_pkey->chain.reset();
321339
}
322340
cert_pkey->chain = std::move(certs);
323-
cert->cert_private_key_idx = idx;
341+
cert->cert_private_key_idx = slot_idx;
342+
324343
return 1;
325344
}
326345

ssl/ssl_privkey.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ static bool ssl_set_pkey(CERT *cert, EVP_PKEY *pkey) {
104104

105105
// Update certificate slot index once all checks have passed.
106106
cert->cert_private_keys[idx].privatekey = UpRef(pkey);
107+
cert->key_method = nullptr; // key_method should be cleared since we've set a private key
107108
cert->cert_private_key_idx = idx;
108109
return true;
109110
}

ssl/ssl_test.cc

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13637,5 +13637,165 @@ TEST(SSLTest, MixContextAndConnection) {
1363713637
EXPECT_FALSE(SSL_get_privatekey(ssl2.get()));
1363813638
}
1363913639

13640+
static size_t test_ecc_privkey_calls = 0;
13641+
13642+
static enum ssl_private_key_result_t test_ecc_privkey_complete(SSL *ssl,
13643+
uint8_t *out,
13644+
size_t *out_len,
13645+
size_t max_out) {
13646+
test_ecc_privkey_calls += 1;
13647+
return ssl_private_key_success;
13648+
}
13649+
13650+
static enum ssl_private_key_result_t test_ecc_privkey_sign(
13651+
SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out,
13652+
uint16_t signature_algorithm, const uint8_t *in, size_t in_len) {
13653+
bssl::UniquePtr<EVP_PKEY> pkey(GetECDSATestKey());
13654+
13655+
if (EVP_PKEY_id(pkey.get()) !=
13656+
SSL_get_signature_algorithm_key_type(signature_algorithm)) {
13657+
return ssl_private_key_failure;
13658+
}
13659+
13660+
// Determine the hash.
13661+
const EVP_MD *md = SSL_get_signature_algorithm_digest(signature_algorithm);
13662+
bssl::ScopedEVP_MD_CTX ctx;
13663+
EVP_PKEY_CTX *pctx;
13664+
if (!EVP_DigestSignInit(ctx.get(), &pctx, md, nullptr,
13665+
pkey.get())) {
13666+
return ssl_private_key_failure;
13667+
}
13668+
13669+
size_t len = 0;
13670+
if (!EVP_DigestSign(ctx.get(), nullptr, &len, in, in_len) || len > max_out) {
13671+
return ssl_private_key_failure;
13672+
}
13673+
13674+
*out_len = max_out;
13675+
13676+
if (!EVP_DigestSign(ctx.get(), out, out_len, in, in_len)) {
13677+
return ssl_private_key_failure;
13678+
}
13679+
13680+
return test_ecc_privkey_complete(ssl, out, out_len, max_out);
13681+
}
13682+
13683+
static enum ssl_private_key_result_t test_ecc_privkey_decrypt(
13684+
SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out, const uint8_t *in,
13685+
size_t in_len) {
13686+
return ssl_private_key_failure;
13687+
}
13688+
13689+
static const SSL_PRIVATE_KEY_METHOD test_ecc_private_key_method = {
13690+
test_ecc_privkey_sign,
13691+
test_ecc_privkey_decrypt,
13692+
test_ecc_privkey_complete,
13693+
};
13694+
13695+
static bssl::UniquePtr<CRYPTO_BUFFER> x509_to_buffer(X509 *x509) {
13696+
uint8_t *buf = NULL;
13697+
int cert_len = i2d_X509(x509, &buf);
13698+
if (cert_len <= 0) {
13699+
return 0;
13700+
}
13701+
13702+
UniquePtr<CRYPTO_BUFFER> buffer(CRYPTO_BUFFER_new(buf, cert_len, NULL));
13703+
OPENSSL_free(buf);
13704+
13705+
return buffer;
13706+
}
13707+
13708+
TEST(SSLTest, SSLPrivateKeyMethod) {
13709+
{
13710+
bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(TLS_method()));
13711+
bssl::UniquePtr<SSL_CTX> server_ctx(SSL_CTX_new(TLS_method()));
13712+
13713+
bssl::UniquePtr<X509> ecdsa_cert(GetECDSATestCertificate());
13714+
bssl::UniquePtr<CRYPTO_BUFFER> ecdsa_leaf =
13715+
x509_to_buffer(ecdsa_cert.get());
13716+
std::vector<CRYPTO_BUFFER *> chain = {
13717+
ecdsa_leaf.get(),
13718+
};
13719+
13720+
// Index should be have been set to default, 0, but no key loaded
13721+
EXPECT_EQ(server_ctx->cert->cert_private_key_idx, SSL_PKEY_RSA);
13722+
EXPECT_EQ(
13723+
server_ctx->cert->cert_private_keys[SSL_PKEY_RSA].privatekey.get(),
13724+
nullptr);
13725+
EXPECT_EQ(server_ctx->cert->key_method, nullptr);
13726+
13727+
13728+
// Load a certificate chain containg the leaf but set private key method
13729+
ASSERT_TRUE(SSL_CTX_set_chain_and_key(server_ctx.get(), &chain[0],
13730+
chain.size(), nullptr,
13731+
&test_ecc_private_key_method));
13732+
13733+
// Index must be ECC key now, but key_method must be set.
13734+
ASSERT_EQ(server_ctx->cert->cert_private_key_idx, SSL_PKEY_ECC);
13735+
ASSERT_EQ(server_ctx->cert->key_method, &test_ecc_private_key_method);
13736+
13737+
bssl::UniquePtr<SSL> client, server;
13738+
ASSERT_TRUE(ConnectClientAndServer(&client, &server, client_ctx.get(),
13739+
server_ctx.get(), ClientConfig(),
13740+
false));
13741+
13742+
ASSERT_TRUE(CompleteHandshakes(client.get(), server.get()));
13743+
13744+
// Check the internal slot index to verify that the correct slot was used
13745+
// during the handshake.
13746+
ASSERT_EQ(server->config->cert->cert_private_key_idx, SSL_PKEY_ECC);
13747+
ASSERT_EQ(server->config->cert->key_method, &test_ecc_private_key_method);
13748+
}
13749+
13750+
{
13751+
bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(TLS_method()));
13752+
bssl::UniquePtr<SSL_CTX> server_ctx(SSL_CTX_new(TLS_method()));
13753+
13754+
// Index should be have been set to default, 0, but no key loaded
13755+
EXPECT_EQ(server_ctx->cert->cert_private_key_idx, SSL_PKEY_RSA);
13756+
EXPECT_EQ(
13757+
server_ctx->cert->cert_private_keys[SSL_PKEY_RSA].privatekey.get(),
13758+
nullptr);
13759+
EXPECT_EQ(server_ctx->cert->key_method, nullptr);
13760+
13761+
bssl::UniquePtr<X509> ed_cert(GetED25519TestCertificate());
13762+
bssl::UniquePtr<EVP_PKEY> ed_key(GetED25519TestKey());
13763+
bssl::UniquePtr<CRYPTO_BUFFER> ed_leaf = x509_to_buffer(ed_cert.get());
13764+
std::vector<CRYPTO_BUFFER *> ed_chain = {
13765+
ed_leaf.get(),
13766+
};
13767+
13768+
// Load a certificate chain containg the leaf but set private key method
13769+
ASSERT_TRUE(SSL_CTX_set_chain_and_key(server_ctx.get(), &ed_chain[0],
13770+
ed_chain.size(), ed_key.get(),
13771+
nullptr));
13772+
13773+
// Index must be ECC key now, but key_method must be set.
13774+
ASSERT_EQ(server_ctx->cert->cert_private_key_idx, SSL_PKEY_ED25519);
13775+
ASSERT_EQ(server_ctx->cert->key_method, nullptr);
13776+
13777+
std::vector<uint16_t> sigalgs = {SSL_SIGN_ED25519};
13778+
13779+
ASSERT_TRUE(SSL_CTX_set_signing_algorithm_prefs(
13780+
client_ctx.get(), sigalgs.data(), sigalgs.size()));
13781+
ASSERT_TRUE(SSL_CTX_set_verify_algorithm_prefs(
13782+
client_ctx.get(), sigalgs.data(), sigalgs.size()));
13783+
13784+
bssl::UniquePtr<SSL> client, server;
13785+
ASSERT_TRUE(ConnectClientAndServer(&client, &server, client_ctx.get(),
13786+
server_ctx.get(), ClientConfig(),
13787+
false));
13788+
13789+
ASSERT_TRUE(CompleteHandshakes(client.get(), server.get()));
13790+
13791+
ASSERT_EQ(test_ecc_privkey_calls, (size_t)1);
13792+
13793+
// Check the internal slot index to verify that the correct slot was used
13794+
// during the handshake.
13795+
ASSERT_EQ(server->config->cert->cert_private_key_idx, SSL_PKEY_ED25519);
13796+
ASSERT_EQ(server->config->cert->key_method, nullptr);
13797+
}
13798+
}
13799+
1364013800
} // namespace
1364113801
BSSL_NAMESPACE_END

ssl/test/runner/runner.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1227,11 +1227,11 @@ func gdbOf(path string, args ...string) *exec.Cmd {
12271227
}
12281228

12291229
func lldbOf(path string, args ...string) *exec.Cmd {
1230-
xtermArgs := []string{"-geometry", xtermSize, "-e", "lldb", "--"}
1230+
xtermArgs := []string{"--"}
12311231
xtermArgs = append(xtermArgs, path)
12321232
xtermArgs = append(xtermArgs, args...)
12331233

1234-
return exec.Command("xterm", xtermArgs...)
1234+
return exec.Command("lldb", xtermArgs...)
12351235
}
12361236

12371237
func rrOf(path string, args ...string) *exec.Cmd {

0 commit comments

Comments
 (0)