Skip to content

Commit a0587a3

Browse files
add support for SSL_get_key_update_type and SSL_KEY_UPDATE_NONE (aws#1011)
mySQL consumes `SSL_get_key_update_type` along with `SSL_KEY_UPDATE_NONE` when building with OpenSSL1.1.1. OpenSSL indicates that: SSL_get_key_update_type can be used to determine whether a key update operation has been scheduled but not yet performed. The type of the pending key update operation will be returned if there is one, or SSL_KEY_UPDATE_NONE otherwise. AWS-LC does have existing related symbols (`SSL_key_update` and `SSL_KEY_UPDATE_(NOT_)REQUESTED`) and a `key_update_pending` boolean in the underlying SSL3 structure which may seem to be reusable in this case. However, in OpenSSL, `SSL_get_key_update_type` has 3 possible values (`SSL_KEY_UPDATE_REQUESTED`, `SSL_KEY_UPDATE_NOT_REQUESTED`, `SSL_KEY_UPDATE_NONE`). We could return `SSL_KEY_UPDATE_NONE` when `key_update_pending` is false in AWS-LC, but we wouldn't be able to easily differentiate between `SSL_KEY_UPDATE_REQUESTED/NOT_REQUESTED` because both values are setting `key_pending` to true. The way to work around this was to change `key_update_pending` into an `int`, so that it can maintain the 3 possible states that OpenSSL has.
1 parent b4a717f commit a0587a3

File tree

7 files changed

+82
-16
lines changed

7 files changed

+82
-16
lines changed

include/openssl/ssl.h

+26-4
Original file line numberDiff line numberDiff line change
@@ -461,20 +461,42 @@ OPENSSL_EXPORT int SSL_write_ex(SSL *s, const void *buf, size_t num,
461461
#define SSL_KEY_UPDATE_REQUESTED 1
462462

463463
// SSL_KEY_UPDATE_NOT_REQUESTED indicates that the peer should not reply with
464-
// it's own KeyUpdate message.
464+
// its own KeyUpdate message.
465465
#define SSL_KEY_UPDATE_NOT_REQUESTED 0
466466

467+
// SSL_KEY_UPDATE_NONE should not be set by the user and is only used to
468+
// indicate that there isn't a pending key operation. OpenSSL indicates that -1
469+
// is used, so that it will be an invalid value for the on-the-wire protocol
470+
// when calling |SSL_key_update|.
471+
#define SSL_KEY_UPDATE_NONE -1
472+
467473
// SSL_key_update queues a TLS 1.3 KeyUpdate message to be sent on |ssl|
468-
// if one is not already queued. The |request_type| argument must one of the
469-
// |SSL_KEY_UPDATE_*| values. This function requires that |ssl| have completed a
470-
// TLS >= 1.3 handshake. It returns one on success or zero on error.
474+
// if one is not already queued. The |request_type| argument must be either
475+
// |SSL_KEY_UPDATE_REQUESTED| or |SSL_KEY_UPDATE_NOT_REQUESTED|. This function
476+
// requires that |ssl| have completed a TLS >= 1.3 handshake. It returns one on
477+
// success or zero on error.
478+
//
479+
// If |request_type| is set to |SSL_KEY_UPDATE_NOT_REQUESTED|, then the sending
480+
// keys for this connection will be updated and the peer will be informed of the
481+
// change.
482+
// If |request_type| is set to |SSL_KEY_UPDATE_REQUESTED|, then the sending keys
483+
// for this connection will be updated and the peer will be informed of the change
484+
// along with a request for the peer to additionally update its sending keys.
485+
// RFC: https://datatracker.ietf.org/doc/html/rfc8446#section-4.6.3
471486
//
472487
// Note that this function does not _send_ the message itself. The next call to
473488
// |SSL_write| will cause the message to be sent. |SSL_write| may be called with
474489
// a zero length to flush a KeyUpdate message when no application data is
475490
// pending.
476491
OPENSSL_EXPORT int SSL_key_update(SSL *ssl, int request_type);
477492

493+
// SSL_get_key_update_type returns the state of the pending key operation in
494+
// |ssl|. The type of pending key operation will be either
495+
// |SSL_KEY_UPDATE_REQUESTED| or |SSL_KEY_UPDATE_NOT_REQUESTED| if there is one,
496+
// and |SSL_KEY_UPDATE_NONE| otherwise. This can be used to indicate whether
497+
// a key update operation has been scheduled but not yet performed.
498+
OPENSSL_EXPORT int SSL_get_key_update_type(const SSL *ssl);
499+
478500
// SSL_shutdown shuts down |ssl|. It runs in two stages. First, it sends
479501
// close_notify and returns zero or one on success or -1 on failure. Zero
480502
// indicates that close_notify was sent, but not received, and one additionally

ssl/internal.h

+6-4
Original file line numberDiff line numberDiff line change
@@ -2719,6 +2719,12 @@ struct SSL3_STATE {
27192719
// needs re-doing when in SSL_accept or SSL_connect
27202720
int rwstate = SSL_ERROR_NONE;
27212721

2722+
// key_update_pending will be either |SSL_KEY_UPDATE_REQUESTED| or
2723+
// |SSL_KEY_UPDATE_NOT_REQUESTED| if we have a KeyUpdate acknowledgment
2724+
// outstanding. |SSL_KEY_UPDATE_NONE| indicates that no KeyUpdates
2725+
// acknowledgements are pending.
2726+
int key_update_pending = SSL_KEY_UPDATE_NONE;
2727+
27222728
enum ssl_encryption_level_t read_level = ssl_encryption_initial;
27232729
enum ssl_encryption_level_t write_level = ssl_encryption_initial;
27242730

@@ -2773,10 +2779,6 @@ struct SSL3_STATE {
27732779
// Channel ID and the |channel_id| field is filled in.
27742780
bool channel_id_valid : 1;
27752781

2776-
// key_update_pending is true if we have a KeyUpdate acknowledgment
2777-
// outstanding.
2778-
bool key_update_pending : 1;
2779-
27802782
// early_data_accepted is true if early data was accepted by the server.
27812783
bool early_data_accepted : 1;
27822784

ssl/s3_lib.cc

-1
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,6 @@ SSL3_STATE::SSL3_STATE()
174174
delegated_credential_used(false),
175175
send_connection_binding(false),
176176
channel_id_valid(false),
177-
key_update_pending(false),
178177
early_data_accepted(false),
179178
alert_dispatch(false),
180179
renegotiate_pending(false),

ssl/s3_pkt.cc

+1-1
Original file line numberDiff line numberDiff line change
@@ -290,7 +290,7 @@ static int do_tls_write(SSL *ssl, size_t *out_bytes_written, uint8_t type,
290290

291291
// Now that we've made progress on the connection, uncork KeyUpdate
292292
// acknowledgments.
293-
ssl->s3->key_update_pending = false;
293+
ssl->s3->key_update_pending = SSL_KEY_UPDATE_NONE;
294294

295295
// Flush the write buffer.
296296
ret = ssl_write_buffer_flush(ssl);

ssl/ssl_lib.cc

+5-1
Original file line numberDiff line numberDiff line change
@@ -1131,7 +1131,7 @@ int SSL_key_update(SSL *ssl, int request_type) {
11311131
return 0;
11321132
}
11331133

1134-
if (!ssl->s3->key_update_pending &&
1134+
if (ssl->s3->key_update_pending == SSL_KEY_UPDATE_NONE &&
11351135
!tls13_add_key_update(ssl, request_type)) {
11361136
return 0;
11371137
}
@@ -1752,6 +1752,10 @@ long SSL_get_default_timeout(const SSL *ssl) {
17521752
return SSL_DEFAULT_SESSION_TIMEOUT;
17531753
}
17541754

1755+
int SSL_get_key_update_type(const SSL *ssl) {
1756+
return ssl->s3->key_update_pending;
1757+
}
1758+
17551759
int SSL_renegotiate(SSL *ssl) {
17561760
// Caller-initiated renegotiation is not supported.
17571761
if (!ssl->s3->renegotiate_pending) {

ssl/ssl_test.cc

+40-3
Original file line numberDiff line numberDiff line change
@@ -6193,9 +6193,9 @@ TEST_P(EncodeDecodeKATTest, RoundTrips) {
61936193
ASSERT_EQ(memcmp(output_bytes.data(), encoded, encoded_len), 0);
61946194
}
61956195

6196-
TEST(SSLTest, ZeroSizedWiteFlushesHandshakeMessages) {
6197-
// If there are pending handshake mesages, an |SSL_write| of zero bytes should
6198-
// flush them.
6196+
TEST(SSLTest, ZeroSizedWriteFlushesHandshakeMessages) {
6197+
// If there are pending handshake messages, an |SSL_write| of zero bytes
6198+
// should flush them.
61996199
bssl::UniquePtr<SSL_CTX> server_ctx(
62006200
CreateContextWithTestCertificate(TLS_method()));
62016201
ASSERT_TRUE(server_ctx);
@@ -6219,6 +6219,43 @@ TEST(SSLTest, ZeroSizedWiteFlushesHandshakeMessages) {
62196219
EXPECT_NE(0u, BIO_wpending(client_wbio));
62206220
}
62216221

6222+
TEST(SSLTest, SSLGetKeyUpdate) {
6223+
bssl::UniquePtr<SSL_CTX> server_ctx(
6224+
CreateContextWithTestCertificate(TLS_method()));
6225+
ASSERT_TRUE(server_ctx);
6226+
EXPECT_TRUE(SSL_CTX_set_max_proto_version(server_ctx.get(), TLS1_3_VERSION));
6227+
EXPECT_TRUE(SSL_CTX_set_min_proto_version(server_ctx.get(), TLS1_3_VERSION));
6228+
6229+
bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(TLS_method()));
6230+
ASSERT_TRUE(client_ctx);
6231+
EXPECT_TRUE(SSL_CTX_set_max_proto_version(client_ctx.get(), TLS1_3_VERSION));
6232+
EXPECT_TRUE(SSL_CTX_set_min_proto_version(client_ctx.get(), TLS1_3_VERSION));
6233+
6234+
bssl::UniquePtr<SSL> client, server;
6235+
ASSERT_TRUE(ConnectClientAndServer(&client, &server, client_ctx.get(),
6236+
server_ctx.get()));
6237+
6238+
// Initial state should be |SSL_KEY_UPDATE_NONE|.
6239+
EXPECT_EQ(SSL_get_key_update_type(client.get()), SSL_KEY_UPDATE_NONE);
6240+
6241+
// Test setting |SSL_key_update| with |SSL_KEY_UPDATE_REQUESTED|.
6242+
EXPECT_TRUE(SSL_key_update(client.get(), SSL_KEY_UPDATE_REQUESTED));
6243+
// |SSL_get_key_update_type| is used to determine whether a key update
6244+
// operation has been scheduled but not yet performed.
6245+
EXPECT_EQ(SSL_get_key_update_type(client.get()), SSL_KEY_UPDATE_REQUESTED);
6246+
EXPECT_EQ(0, SSL_write(client.get(), nullptr, 0));
6247+
// Key update operation should have been performed by now.
6248+
EXPECT_EQ(SSL_get_key_update_type(client.get()), SSL_KEY_UPDATE_NONE);
6249+
6250+
// Test setting |SSL_key_update| with |SSL_KEY_UPDATE_NOT_REQUESTED|.
6251+
EXPECT_TRUE(SSL_key_update(client.get(), SSL_KEY_UPDATE_NOT_REQUESTED));
6252+
EXPECT_EQ(SSL_get_key_update_type(client.get()),
6253+
SSL_KEY_UPDATE_NOT_REQUESTED);
6254+
EXPECT_EQ(0, SSL_write(client.get(), nullptr, 0));
6255+
// Key update operation should have been performed by now.
6256+
EXPECT_EQ(SSL_get_key_update_type(client.get()), SSL_KEY_UPDATE_NONE);
6257+
}
6258+
62226259
TEST_P(SSLVersionTest, VerifyBeforeCertRequest) {
62236260
// Configure the server to request client certificates.
62246261
SSL_CTX_set_custom_verify(

ssl/tls13_both.cc

+4-2
Original file line numberDiff line numberDiff line change
@@ -623,6 +623,8 @@ bool tls13_add_key_update(SSL *ssl, int update_requested) {
623623
CBB body_cbb;
624624
if (!ssl->method->init_message(ssl, cbb.get(), &body_cbb,
625625
SSL3_MT_KEY_UPDATE) ||
626+
(update_requested != SSL_KEY_UPDATE_NOT_REQUESTED &&
627+
update_requested != SSL_KEY_UPDATE_REQUESTED) ||
626628
!CBB_add_u8(&body_cbb, update_requested) ||
627629
!ssl_add_message_cbb(ssl, cbb.get()) ||
628630
!tls13_rotate_traffic_key(ssl, evp_aead_seal)) {
@@ -632,7 +634,7 @@ bool tls13_add_key_update(SSL *ssl, int update_requested) {
632634
// Suppress KeyUpdate acknowledgments until this change is written to the
633635
// wire. This prevents us from accumulating write obligations when read and
634636
// write progress at different rates. See RFC 8446, section 4.6.3.
635-
ssl->s3->key_update_pending = true;
637+
ssl->s3->key_update_pending = update_requested;
636638

637639
return true;
638640
}
@@ -655,7 +657,7 @@ static bool tls13_receive_key_update(SSL *ssl, const SSLMessage &msg) {
655657

656658
// Acknowledge the KeyUpdate
657659
if (key_update_request == SSL_KEY_UPDATE_REQUESTED &&
658-
!ssl->s3->key_update_pending &&
660+
ssl->s3->key_update_pending == SSL_KEY_UPDATE_NONE &&
659661
!tls13_add_key_update(ssl, SSL_KEY_UPDATE_NOT_REQUESTED)) {
660662
return false;
661663
}

0 commit comments

Comments
 (0)