This is an automated email from the ASF dual-hosted git repository.

masaori pushed a commit to branch quic-latest
in repository https://gitbox.apache.org/repos/asf/trafficserver.git


The following commit(s) were added to refs/heads/quic-latest by this push:
     new f9651e3  Add SSL_stateless() support in QUICTLS
f9651e3 is described below

commit f9651e356af77b531a03ab982345199db1d34a93
Author: Masaori Koshiba <masa...@apache.org>
AuthorDate: Tue Mar 13 16:08:42 2018 +0900

    Add SSL_stateless() support in QUICTLS
    
    Also add test cases for key_share mismatch, stateless retry and both.
    This is a piece of Client Address Validation support.
    
    This requires latest OpenSSL (1.1.1-rc3+) for 
SSL_CTX_set_stateless_cookie_{generate,verify}_cb
    - 
https://github.com/openssl/openssl/commit/3fa2812f32bdb922d47b84ab7b5a98a807d838c0
---
 iocore/net/quic/QUICTLS.cc                         |  75 +++-
 iocore/net/quic/QUICTLS.h                          |   7 +-
 iocore/net/quic/test/test_QUICHandshakeProtocol.cc | 422 ++++++++++++++++++++-
 3 files changed, 466 insertions(+), 38 deletions(-)

diff --git a/iocore/net/quic/QUICTLS.cc b/iocore/net/quic/QUICTLS.cc
index 7baa193..4441260 100644
--- a/iocore/net/quic/QUICTLS.cc
+++ b/iocore/net/quic/QUICTLS.cc
@@ -42,20 +42,19 @@ to_hex(uint8_t *out, uint8_t *in, int in_len)
   out[in_len * 2] = 0;
 }
 
-QUICTLS::QUICTLS(SSL *ssl, NetVConnectionContext_t nvc_ctx) : 
QUICHandshakeProtocol(), _ssl(ssl), _netvc_context(nvc_ctx)
+QUICTLS::QUICTLS(SSL *ssl, NetVConnectionContext_t nvc_ctx, bool stateless)
+  : QUICHandshakeProtocol(), _ssl(ssl), _netvc_context(nvc_ctx), 
_stateless(stateless)
 {
-  if (this->_netvc_context == NET_VCONNECTION_IN) {
-    SSL_set_accept_state(this->_ssl);
-  } else if (this->_netvc_context == NET_VCONNECTION_OUT) {
-    SSL_set_connect_state(this->_ssl);
-  } else {
-    ink_assert(false);
-  }
+  ink_assert(this->_netvc_context != NET_VCONNECTION_UNSET);
 
   this->_client_pp = new QUICPacketProtection();
   this->_server_pp = new QUICPacketProtection();
 }
 
+QUICTLS::QUICTLS(SSL *ssl, NetVConnectionContext_t nvc_ctx) : QUICTLS(ssl, 
nvc_ctx, false)
+{
+}
+
 QUICTLS::~QUICTLS()
 {
   delete this->_client_pp;
@@ -77,18 +76,50 @@ QUICTLS::handshake(uint8_t *out, size_t &out_len, size_t 
max_out_len, const uint
 
   int err = SSL_ERROR_NONE;
   if (!SSL_is_init_finished(this->_ssl)) {
-    if (!this->_early_data_processed) {
-      if (this->_read_early_data()) {
-        Debug(tag, "Early data processed");
-        this->_early_data_processed = true;
+    ERR_clear_error();
+    int ret = 0;
+    if (this->_netvc_context == NET_VCONNECTION_IN) {
+      // // process early data
+      if (!this->_early_data_processed) {
+        if (this->_read_early_data()) {
+          this->_early_data_processed = true;
+        }
+
+        if (SSL_get_early_data_status(this->_ssl) == SSL_EARLY_DATA_ACCEPTED) {
+          Debug(tag, "Early data processed");
+
+          if (!this->_client_pp->get_key(QUICKeyPhase::ZERORTT)) {
+            this->_generate_0rtt_key();
+          }
+        }
       }
-      if (!this->_client_pp->get_key(QUICKeyPhase::ZERORTT) && 
SSL_get_early_data_status(this->_ssl) == SSL_EARLY_DATA_ACCEPTED) {
-        this->_generate_0rtt_key();
+
+      // process stateless retry
+      if (this->_stateless && SSL_get_early_data_status(this->_ssl) != 
SSL_EARLY_DATA_ACCEPTED) {
+        // start over
+        // TODO: make sure no memory leaks
+        rbio = BIO_new(BIO_s_mem());
+        wbio = BIO_new(BIO_s_mem());
+        if (in != nullptr || in_len != 0) {
+          BIO_write(rbio, in, in_len);
+        }
+        SSL_set_bio(this->_ssl, rbio, wbio);
+
+        ret = SSL_stateless(this->_ssl);
+        if (ret >= 0) {
+          Debug(tag, "Sending HRR");
+          this->_stateless = false;
+        } else {
+          Debug(tag, "SSL_stateless error");
+        }
+      } else {
+        ret = SSL_accept(this->_ssl);
       }
+    } else {
+      ret = SSL_connect(this->_ssl);
     }
-    ERR_clear_error();
-    int ret = SSL_do_handshake(this->_ssl);
-    if (ret <= 0) {
+
+    if (ret < 0) {
       err = SSL_get_error(this->_ssl, ret);
 
       switch (err) {
@@ -97,8 +128,8 @@ QUICTLS::handshake(uint8_t *out, size_t &out_len, size_t 
max_out_len, const uint
         break;
       default:
         char err_buf[256] = {0};
-        ERR_error_string_n(err, err_buf, sizeof(err_buf));
-        Debug(tag, "Handshake error: %s (%d)", err_buf, err);
+        ERR_error_string_n(ERR_get_error(), err_buf, sizeof(err_buf));
+        Debug(tag, "Handshake: %s", err_buf);
         return err;
       }
     }
@@ -128,6 +159,12 @@ QUICTLS::is_key_derived(QUICKeyPhase key_phase) const
   }
 }
 
+bool
+QUICTLS::is_stateless()
+{
+  return this->_stateless;
+}
+
 int
 QUICTLS::initialize_key_materials(QUICConnectionId cid)
 {
diff --git a/iocore/net/quic/QUICTLS.h b/iocore/net/quic/QUICTLS.h
index 0ac7c10..5de0dcc 100644
--- a/iocore/net/quic/QUICTLS.h
+++ b/iocore/net/quic/QUICTLS.h
@@ -40,6 +40,7 @@ class QUICTLS : public QUICHandshakeProtocol
 {
 public:
   QUICTLS(SSL *ssl, NetVConnectionContext_t nvc_ctx);
+  QUICTLS(SSL *ssl, NetVConnectionContext_t nvc_ctx, bool stateless);
   ~QUICTLS();
 
   int handshake(uint8_t *out, size_t &out_len, size_t max_out_len, const 
uint8_t *in, size_t in_len) override;
@@ -54,6 +55,7 @@ public:
 
   // FIXME SSL handle should not be exported
   SSL *ssl_handle();
+  bool is_stateless();
 
 private:
   QUICKeyGenerator _keygen_for_client = 
QUICKeyGenerator(QUICKeyGenerator::Context::CLIENT);
@@ -80,8 +82,9 @@ private:
   QUICPacketProtection *_client_pp       = nullptr;
   QUICPacketProtection *_server_pp       = nullptr;
   NetVConnectionContext_t _netvc_context = NET_VCONNECTION_UNSET;
-
-  bool _early_data_processed = false;
+  bool _stateless                        = false;
+  bool _early_data_processed             = false;
+  bool _early_data                       = true;
   int _read_early_data();
   void _generate_0rtt_key();
 };
diff --git a/iocore/net/quic/test/test_QUICHandshakeProtocol.cc 
b/iocore/net/quic/test/test_QUICHandshakeProtocol.cc
index 0736067..ccc17ef 100644
--- a/iocore/net/quic/test/test_QUICHandshakeProtocol.cc
+++ b/iocore/net/quic/test/test_QUICHandshakeProtocol.cc
@@ -56,6 +56,54 @@ print_hex(const uint8_t *v, size_t len)
   return;
 }
 
+static const uint8_t original[] = {
+  0x41, 0x70, 0x61, 0x63, 0x68, 0x65, 0x20, 0x54, 0x72, 0x61, 0x66, 0x66, 
0x69, 0x63, 0x20, 0x53,
+  0x65, 0x72, 0x76, 0x65, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00,
+};
+static const uint64_t pkt_num = 0x123456789;
+static const uint8_t ad[]     = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f};
+
+/* Fixed value used in the ServerHello random field to identify an HRR */
+const unsigned char hrr_random[] = {
+  0xcf, 0x21, 0xad, 0x74, 0xe5, 0x9a, 0x61, 0x11, 0xbe, 0x1d, 0x8c, 0x02, 
0x1e, 0x65, 0xb8, 0x91,
+  0xc2, 0xa2, 0x11, 0x16, 0x7a, 0xbb, 0x8c, 0x5e, 0x07, 0x9e, 0x09, 0xe2, 
0xc8, 0xa8, 0x33, 0x9c,
+};
+
+static const bool
+is_hrr(uint8_t *msg, size_t msg_len)
+{
+  return memmem(msg, msg_len, hrr_random, sizeof(hrr_random)) != nullptr;
+}
+
+// dummy token to simplify test
+static uint8_t token[] = {0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 
0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef,
+                          0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 
0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef,
+                          0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 
0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef,
+                          0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 
0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef};
+
+static int
+generate_cookie_callback(SSL * /* ssl */, unsigned char *cookie, size_t 
*cookie_len)
+{
+  memcpy(cookie, token, sizeof(token));
+  *cookie_len = sizeof(token);
+
+  return 1;
+}
+
+static int
+verify_cookie_callback(SSL *ssl, const unsigned char *cookie, size_t 
cookie_len)
+{
+  if (memcmp(token, cookie, sizeof(token)) == 0) {
+    return 1;
+  } else {
+    return 0;
+  }
+}
+
+
+
 TEST_CASE("QUICHndshakeProtocol Cleartext", "[quic]")
 {
   // Client
@@ -80,15 +128,6 @@ TEST_CASE("QUICHndshakeProtocol Cleartext", "[quic]")
   CHECK(server->initialize_key_materials(0x8394c8f03e515700));
 
   // encrypt - decrypt
-  uint8_t original[] = {
-    0x41, 0x70, 0x61, 0x63, 0x68, 0x65, 0x20, 0x54, 0x72, 0x61, 0x66, 0x66, 
0x69, 0x63, 0x20, 0x53,
-    0x65, 0x72, 0x76, 0x65, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00,
-  };
-  uint64_t pkt_num = 0x123456789;
-  uint8_t ad[]     = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 
0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f};
-
   // client (encrypt) - server (decrypt)
   std::cout << "### Original Text" << std::endl;
   print_hex(original, sizeof(original));
@@ -175,15 +214,364 @@ TEST_CASE("QUICHandshakeProtocol 1-RTT", "[quic]")
   CHECK(server->update_key_materials());
 
   // encrypt - decrypt
-  uint8_t original[] = {
-    0x41, 0x70, 0x61, 0x63, 0x68, 0x65, 0x20, 0x54, 0x72, 0x61, 0x66, 0x66, 
0x69, 0x63, 0x20, 0x53,
-    0x65, 0x72, 0x76, 0x65, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00,
-  };
-  uint64_t pkt_num = 0x123456789;
-  uint8_t ad[]     = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 
0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f};
+  // client (encrypt) - server (decrypt)
+  std::cout << "### Original Text" << std::endl;
+  print_hex(original, sizeof(original));
+
+  uint8_t cipher[128] = {0}; // >= original len + EVP_AEAD_max_overhead
+  size_t cipher_len   = 0;
+  CHECK(client->encrypt(cipher, cipher_len, sizeof(cipher), original, 
sizeof(original), pkt_num, ad, sizeof(ad),
+                        QUICKeyPhase::PHASE_0));
+
+  std::cout << "### Encrypted Text" << std::endl;
+  print_hex(cipher, cipher_len);
+
+  uint8_t plain[128] = {0};
+  size_t plain_len   = 0;
+  CHECK(server->decrypt(plain, plain_len, sizeof(plain), cipher, cipher_len, 
pkt_num, ad, sizeof(ad), QUICKeyPhase::PHASE_0));
+
+  std::cout << "### Decrypted Text" << std::endl;
+  print_hex(plain, plain_len);
+
+  CHECK(sizeof(original) == (plain_len));
+  CHECK(memcmp(original, plain, plain_len) == 0);
+
+  // Teardown
+  delete client;
+  delete server;
+}
+
+// HRR - Incorrect DHE Share
+// NOTE: This is *NOT* client address validation.
+//       https://tools.ietf.org/html/draft-ietf-tls-tls13-26 - 2.1.  Incorrect 
DHE Share
+TEST_CASE("QUICHandshakeProtocol 1-RTT HRR key_share mismatch", "[quic]")
+{
+  // Client
+  SSL_CTX *client_ssl_ctx = SSL_CTX_new(TLS_method());
+  SSL_CTX_set_min_proto_version(client_ssl_ctx, TLS1_3_VERSION);
+  SSL_CTX_set_max_proto_version(client_ssl_ctx, TLS1_3_VERSION);
+  SSL_CTX_clear_options(client_ssl_ctx, SSL_OP_ENABLE_MIDDLEBOX_COMPAT);
+
+  QUICHandshakeProtocol *client = new QUICTLS(SSL_new(client_ssl_ctx), 
NET_VCONNECTION_OUT);
+
+  // Server
+  SSL_CTX *server_ssl_ctx = SSL_CTX_new(TLS_method());
+  SSL_CTX_set_min_proto_version(server_ssl_ctx, TLS1_3_VERSION);
+  SSL_CTX_set_max_proto_version(server_ssl_ctx, TLS1_3_VERSION);
+  SSL_CTX_clear_options(server_ssl_ctx, SSL_OP_ENABLE_MIDDLEBOX_COMPAT);
+  BIO *crt_bio(BIO_new_mem_buf(server_crt, sizeof(server_crt)));
+  SSL_CTX_use_certificate(server_ssl_ctx, PEM_read_bio_X509(crt_bio, nullptr, 
nullptr, nullptr));
+  BIO *key_bio(BIO_new_mem_buf(server_key, sizeof(server_key)));
+  SSL_CTX_use_PrivateKey(server_ssl_ctx, PEM_read_bio_PrivateKey(key_bio, 
nullptr, nullptr, nullptr));
+
+  // client key_share will be X25519 (default of OpenSSL)
+  if (SSL_CTX_set1_groups_list(server_ssl_ctx, "P-521:P-384:P-256") != 1) {
+    REQUIRE(false);
+  }
+
+  QUICHandshakeProtocol *server = new QUICTLS(SSL_new(server_ssl_ctx), 
NET_VCONNECTION_IN);
+
+  CHECK(client->initialize_key_materials(0x8394c8f03e515708));
+  CHECK(server->initialize_key_materials(0x8394c8f03e515708));
+
+  // Client Hello
+  uint8_t client_hello[MAX_HANDSHAKE_MSG_LEN] = {0};
+  size_t client_hello_len                     = 0;
+  REQUIRE(client->handshake(client_hello, client_hello_len, 
MAX_HANDSHAKE_MSG_LEN, nullptr, 0) == SSL_ERROR_WANT_READ);
+  REQUIRE(client_hello_len > 0);
+  std::cout << "### Client Hello" << std::endl;
+  print_hex(client_hello, client_hello_len);
+
+  // Hello Retry Request w/o cookie
+  uint8_t retry[MAX_HANDSHAKE_MSG_LEN] = {0};
+  size_t retry_len                     = 0;
+  REQUIRE(server->handshake(retry, retry_len, MAX_HANDSHAKE_MSG_LEN, 
client_hello, client_hello_len) == SSL_ERROR_WANT_READ);
+  REQUIRE(retry_len > 0);
+  REQUIRE(is_hrr(retry, retry_len));
+  std::cout << "### HRR" << std::endl;
+  print_hex(retry, retry_len);
+
+  // Client Hello w/ cookie
+  memset(client_hello, 0, MAX_HANDSHAKE_MSG_LEN);
+  client_hello_len = 0;
+  REQUIRE(client->handshake(client_hello, client_hello_len, 
MAX_HANDSHAKE_MSG_LEN, retry, retry_len) == SSL_ERROR_WANT_READ);
+  REQUIRE(client_hello_len > 0);
+  std::cout << "### Client Hello" << std::endl;
+  print_hex(client_hello, client_hello_len);
+
+  // Server Hello
+  uint8_t server_hello[MAX_HANDSHAKE_MSG_LEN] = {0};
+  size_t server_hello_len                     = 0;
+  REQUIRE(server->handshake(server_hello, server_hello_len, 
MAX_HANDSHAKE_MSG_LEN, client_hello, client_hello_len) ==
+          SSL_ERROR_WANT_READ);
+  REQUIRE(server_hello_len > 0);
+  std::cout << "### Server Hello" << std::endl;
+  print_hex(server_hello, server_hello_len);
+
+  // Client Fnished
+  uint8_t client_finished[MAX_HANDSHAKE_MSG_LEN] = {0};
+  size_t client_finished_len                     = 0;
+  REQUIRE(client->handshake(client_finished, client_finished_len, 
MAX_HANDSHAKE_MSG_LEN, server_hello, server_hello_len) ==
+          SSL_ERROR_NONE);
+  REQUIRE(client_finished_len > 0);
+  std::cout << "### Client Finished" << std::endl;
+  print_hex(client_finished, client_finished_len);
+
+  CHECK(client->update_key_materials());
+
+  // Post Handshake Msg
+  uint8_t post_handshake_msg[MAX_HANDSHAKE_MSG_LEN] = {0};
+  size_t post_handshake_msg_len                     = 0;
+  REQUIRE(server->handshake(post_handshake_msg, post_handshake_msg_len, 
MAX_HANDSHAKE_MSG_LEN, client_finished,
+                            client_finished_len) == SSL_ERROR_NONE);
+  std::cout << "### Post Handshake Message" << std::endl;
+  print_hex(post_handshake_msg, post_handshake_msg_len);
+
+  CHECK(server->update_key_materials());
+
+  // encrypt - decrypt
+  // client (encrypt) - server (decrypt)
+  std::cout << "### Original Text" << std::endl;
+  print_hex(original, sizeof(original));
 
+  uint8_t cipher[128] = {0}; // >= original len + EVP_AEAD_max_overhead
+  size_t cipher_len   = 0;
+  CHECK(client->encrypt(cipher, cipher_len, sizeof(cipher), original, 
sizeof(original), pkt_num, ad, sizeof(ad),
+                        QUICKeyPhase::PHASE_0));
+
+  std::cout << "### Encrypted Text" << std::endl;
+  print_hex(cipher, cipher_len);
+
+  uint8_t plain[128] = {0};
+  size_t plain_len   = 0;
+  CHECK(server->decrypt(plain, plain_len, sizeof(plain), cipher, cipher_len, 
pkt_num, ad, sizeof(ad), QUICKeyPhase::PHASE_0));
+
+  std::cout << "### Decrypted Text" << std::endl;
+  print_hex(plain, plain_len);
+
+  CHECK(sizeof(original) == (plain_len));
+  CHECK(memcmp(original, plain, plain_len) == 0);
+
+  // Teardown
+  delete client;
+  delete server;
+}
+
+// HRR for client address varidation
+TEST_CASE("QUICHandshakeProtocol 1-RTT HRR statless", "[quic]")
+{
+  // Client
+  SSL_CTX *client_ssl_ctx = SSL_CTX_new(TLS_method());
+  SSL_CTX_set_min_proto_version(client_ssl_ctx, TLS1_3_VERSION);
+  SSL_CTX_set_max_proto_version(client_ssl_ctx, TLS1_3_VERSION);
+  SSL_CTX_clear_options(client_ssl_ctx, SSL_OP_ENABLE_MIDDLEBOX_COMPAT);
+
+  QUICHandshakeProtocol *client = new QUICTLS(SSL_new(client_ssl_ctx), 
NET_VCONNECTION_OUT);
+
+  // Server
+  SSL_CTX *server_ssl_ctx = SSL_CTX_new(TLS_method());
+  SSL_CTX_set_min_proto_version(server_ssl_ctx, TLS1_3_VERSION);
+  SSL_CTX_set_max_proto_version(server_ssl_ctx, TLS1_3_VERSION);
+  SSL_CTX_clear_options(server_ssl_ctx, SSL_OP_ENABLE_MIDDLEBOX_COMPAT);
+  BIO *crt_bio(BIO_new_mem_buf(server_crt, sizeof(server_crt)));
+  SSL_CTX_use_certificate(server_ssl_ctx, PEM_read_bio_X509(crt_bio, nullptr, 
nullptr, nullptr));
+  BIO *key_bio(BIO_new_mem_buf(server_key, sizeof(server_key)));
+  SSL_CTX_use_PrivateKey(server_ssl_ctx, PEM_read_bio_PrivateKey(key_bio, 
nullptr, nullptr, nullptr));
+
+  // callbacks for cookie ext
+  // Requires OpenSSL-1.1.1-rc3+ : https://github.com/openssl/openssl/pull/5463
+  SSL_CTX_set_stateless_cookie_generate_cb(server_ssl_ctx, 
generate_cookie_callback);
+  SSL_CTX_set_stateless_cookie_verify_cb(server_ssl_ctx, 
verify_cookie_callback);
+
+  bool stateless                = true;
+  QUICHandshakeProtocol *server = new QUICTLS(SSL_new(server_ssl_ctx), 
NET_VCONNECTION_IN, stateless);
+
+  CHECK(client->initialize_key_materials(0x8394c8f03e515708));
+  CHECK(server->initialize_key_materials(0x8394c8f03e515708));
+
+  // Client Hello
+  uint8_t client_hello[MAX_HANDSHAKE_MSG_LEN] = {0};
+  size_t client_hello_len                     = 0;
+  REQUIRE(client->handshake(client_hello, client_hello_len, 
MAX_HANDSHAKE_MSG_LEN, nullptr, 0) == SSL_ERROR_WANT_READ);
+  REQUIRE(client_hello_len > 0);
+  std::cout << "### Client Hello" << std::endl;
+  print_hex(client_hello, client_hello_len);
+
+  // Hello Retry Request
+  uint8_t retry[MAX_HANDSHAKE_MSG_LEN] = {0};
+  size_t retry_len                     = 0;
+  CHECK(server->handshake(retry, retry_len, MAX_HANDSHAKE_MSG_LEN, 
client_hello, client_hello_len) == SSL_ERROR_NONE);
+  REQUIRE(retry_len > 0);
+  CHECK(is_hrr(retry, retry_len));
+  std::cout << "### HRR" << std::endl;
+  print_hex(retry, retry_len);
+
+  // Make sure "stateless"
+  delete server;
+  server = new QUICTLS(SSL_new(server_ssl_ctx), NET_VCONNECTION_IN, stateless);
+
+  // Client Hello w/ cookie
+  memset(client_hello, 0, MAX_HANDSHAKE_MSG_LEN);
+  client_hello_len = 0;
+  CHECK(client->handshake(client_hello, client_hello_len, 
MAX_HANDSHAKE_MSG_LEN, retry, retry_len) == SSL_ERROR_WANT_READ);
+  REQUIRE(client_hello_len > 0);
+  std::cout << "### Client Hello" << std::endl;
+  print_hex(client_hello, client_hello_len);
+
+  // Server Hello
+  uint8_t server_hello[MAX_HANDSHAKE_MSG_LEN] = {0};
+  size_t server_hello_len                     = 0;
+  REQUIRE(server->handshake(server_hello, server_hello_len, 
MAX_HANDSHAKE_MSG_LEN, client_hello, client_hello_len) ==
+          SSL_ERROR_NONE);
+  REQUIRE(server_hello_len > 0);
+  std::cout << "### Server Hello" << std::endl;
+  print_hex(server_hello, server_hello_len);
+
+  // Client Fnished
+  uint8_t client_finished[MAX_HANDSHAKE_MSG_LEN] = {0};
+  size_t client_finished_len                     = 0;
+  REQUIRE(client->handshake(client_finished, client_finished_len, 
MAX_HANDSHAKE_MSG_LEN, server_hello, server_hello_len) ==
+          SSL_ERROR_NONE);
+  REQUIRE(client_finished_len > 0);
+  std::cout << "### Client Finished" << std::endl;
+  print_hex(client_finished, client_finished_len);
+
+  CHECK(client->update_key_materials());
+
+  // Post Handshake Msg
+  uint8_t post_handshake_msg[MAX_HANDSHAKE_MSG_LEN] = {0};
+  size_t post_handshake_msg_len                     = 0;
+  REQUIRE(server->handshake(post_handshake_msg, post_handshake_msg_len, 
MAX_HANDSHAKE_MSG_LEN, client_finished,
+                            client_finished_len) == SSL_ERROR_NONE);
+  std::cout << "### Post Handshake Message" << std::endl;
+  print_hex(post_handshake_msg, post_handshake_msg_len);
+
+  CHECK(server->update_key_materials());
+
+  // encrypt - decrypt
+  // client (encrypt) - server (decrypt)
+  std::cout << "### Original Text" << std::endl;
+  print_hex(original, sizeof(original));
+
+  uint8_t cipher[128] = {0}; // >= original len + EVP_AEAD_max_overhead
+  size_t cipher_len   = 0;
+  CHECK(client->encrypt(cipher, cipher_len, sizeof(cipher), original, 
sizeof(original), pkt_num, ad, sizeof(ad),
+                        QUICKeyPhase::PHASE_0));
+
+  std::cout << "### Encrypted Text" << std::endl;
+  print_hex(cipher, cipher_len);
+
+  uint8_t plain[128] = {0};
+  size_t plain_len   = 0;
+  CHECK(server->decrypt(plain, plain_len, sizeof(plain), cipher, cipher_len, 
pkt_num, ad, sizeof(ad), QUICKeyPhase::PHASE_0));
+
+  std::cout << "### Decrypted Text" << std::endl;
+  print_hex(plain, plain_len);
+
+  CHECK(sizeof(original) == (plain_len));
+  CHECK(memcmp(original, plain, plain_len) == 0);
+
+  // Teardown
+  delete client;
+  delete server;
+}
+
+// HRR for client address varidation & Incorrect DHE Share
+TEST_CASE("QUICHandshakeProtocol 1-RTT HRR statless & key_share mismatch", 
"[quic]")
+{
+  // Client
+  SSL_CTX *client_ssl_ctx = SSL_CTX_new(TLS_method());
+  SSL_CTX_set_min_proto_version(client_ssl_ctx, TLS1_3_VERSION);
+  SSL_CTX_set_max_proto_version(client_ssl_ctx, TLS1_3_VERSION);
+  SSL_CTX_clear_options(client_ssl_ctx, SSL_OP_ENABLE_MIDDLEBOX_COMPAT);
+
+  QUICHandshakeProtocol *client = new QUICTLS(SSL_new(client_ssl_ctx), 
NET_VCONNECTION_OUT);
+
+  // Server
+  SSL_CTX *server_ssl_ctx = SSL_CTX_new(TLS_method());
+  SSL_CTX_set_min_proto_version(server_ssl_ctx, TLS1_3_VERSION);
+  SSL_CTX_set_max_proto_version(server_ssl_ctx, TLS1_3_VERSION);
+  SSL_CTX_clear_options(server_ssl_ctx, SSL_OP_ENABLE_MIDDLEBOX_COMPAT);
+  BIO *crt_bio(BIO_new_mem_buf(server_crt, sizeof(server_crt)));
+  SSL_CTX_use_certificate(server_ssl_ctx, PEM_read_bio_X509(crt_bio, nullptr, 
nullptr, nullptr));
+  BIO *key_bio(BIO_new_mem_buf(server_key, sizeof(server_key)));
+  SSL_CTX_use_PrivateKey(server_ssl_ctx, PEM_read_bio_PrivateKey(key_bio, 
nullptr, nullptr, nullptr));
+
+  // client key_share will be X25519 (default of OpenSSL)
+  if (SSL_CTX_set1_groups_list(server_ssl_ctx, "P-521:P-384:P-256") != 1) {
+    REQUIRE(false);
+  }
+
+  // callbacks for cookie ext
+  SSL_CTX_set_stateless_cookie_generate_cb(server_ssl_ctx, 
generate_cookie_callback);
+  SSL_CTX_set_stateless_cookie_verify_cb(server_ssl_ctx, 
verify_cookie_callback);
+
+  bool stateless                = true;
+  QUICHandshakeProtocol *server = new QUICTLS(SSL_new(server_ssl_ctx), 
NET_VCONNECTION_IN, stateless);
+
+  CHECK(client->initialize_key_materials(0x8394c8f03e515708));
+  CHECK(server->initialize_key_materials(0x8394c8f03e515708));
+
+  // Client Hello
+  uint8_t client_hello[MAX_HANDSHAKE_MSG_LEN] = {0};
+  size_t client_hello_len                     = 0;
+  REQUIRE(client->handshake(client_hello, client_hello_len, 
MAX_HANDSHAKE_MSG_LEN, nullptr, 0) == SSL_ERROR_WANT_READ);
+  REQUIRE(client_hello_len > 0);
+  std::cout << "### Client Hello" << std::endl;
+  print_hex(client_hello, client_hello_len);
+
+  // Hello Retry Request
+  uint8_t retry[MAX_HANDSHAKE_MSG_LEN] = {0};
+  size_t retry_len                     = 0;
+  CHECK(server->handshake(retry, retry_len, MAX_HANDSHAKE_MSG_LEN, 
client_hello, client_hello_len) == SSL_ERROR_NONE);
+  REQUIRE(retry_len > 0);
+  REQUIRE(is_hrr(retry, retry_len));
+  std::cout << "### HRR" << std::endl;
+  print_hex(retry, retry_len);
+
+  // Make sure "stateless"
+  delete server;
+  server = new QUICTLS(SSL_new(server_ssl_ctx), NET_VCONNECTION_IN, stateless);
+
+  // Client Hello w/ cookie
+  memset(client_hello, 0, MAX_HANDSHAKE_MSG_LEN);
+  client_hello_len = 0;
+  REQUIRE(client->handshake(client_hello, client_hello_len, 
MAX_HANDSHAKE_MSG_LEN, retry, retry_len) == SSL_ERROR_WANT_READ);
+  REQUIRE(client_hello_len > 0);
+  std::cout << "### Client Hello" << std::endl;
+  print_hex(client_hello, client_hello_len);
+
+  // Server Hello
+  uint8_t server_hello[MAX_HANDSHAKE_MSG_LEN] = {0};
+  size_t server_hello_len                     = 0;
+  REQUIRE(server->handshake(server_hello, server_hello_len, 
MAX_HANDSHAKE_MSG_LEN, client_hello, client_hello_len) ==
+          SSL_ERROR_NONE);
+  REQUIRE(server_hello_len > 0);
+  std::cout << "### Server Hello" << std::endl;
+  print_hex(server_hello, server_hello_len);
+
+  // Client Fnished
+  uint8_t client_finished[MAX_HANDSHAKE_MSG_LEN] = {0};
+  size_t client_finished_len                     = 0;
+  CHECK(client->handshake(client_finished, client_finished_len, 
MAX_HANDSHAKE_MSG_LEN, server_hello, server_hello_len) ==
+        SSL_ERROR_NONE);
+  REQUIRE(client_finished_len > 0);
+  std::cout << "### Client Finished" << std::endl;
+  print_hex(client_finished, client_finished_len);
+
+  CHECK(client->update_key_materials());
+
+  // Post Handshake Msg
+  uint8_t post_handshake_msg[MAX_HANDSHAKE_MSG_LEN] = {0};
+  size_t post_handshake_msg_len                     = 0;
+  REQUIRE(server->handshake(post_handshake_msg, post_handshake_msg_len, 
MAX_HANDSHAKE_MSG_LEN, client_finished,
+                            client_finished_len) == SSL_ERROR_NONE);
+  std::cout << "### Post Handshake Message" << std::endl;
+  print_hex(post_handshake_msg, post_handshake_msg_len);
+
+  CHECK(server->update_key_materials());
+
+  // encrypt - decrypt
   // client (encrypt) - server (decrypt)
   std::cout << "### Original Text" << std::endl;
   print_hex(original, sizeof(original));

-- 
To stop receiving notification emails like this one, please contact
masa...@apache.org.

Reply via email to