You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficserver.apache.org by ma...@apache.org on 2018/09/07 03:29:45 UTC

[trafficserver] branch quic-latest updated (dafca89 -> 0014b36)

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

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


    from dafca89  Forward limit of local flow controller with the largest reordered stream frame
     new 6c7cef9  [draft-13] Update Transport Error Codes
     new e7c493a  Handle TLS Alerts on msg_cb
     new 656dffa  Make type of error code uint16_t for CRYPTO_ERROR (0x100 - 0x1FF)
     new 0014b36  Return QUICConnectionError if QUICHandshakeMsgs has error_code

The 4 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 iocore/net/QUICNetVConnection.cc                   |  20 +-
 iocore/net/quic/QUICDebugNames.cc                  |  40 ++--
 iocore/net/quic/QUICDebugNames.h                   |   2 +-
 iocore/net/quic/QUICFrame.cc                       |  21 +-
 iocore/net/quic/QUICFrame.h                        |  11 +-
 iocore/net/quic/QUICHandshake.cc                   |  27 ++-
 iocore/net/quic/QUICHandshake.h                    |   2 +-
 iocore/net/quic/QUICHandshakeProtocol.h            |   7 +-
 iocore/net/quic/QUICStream.cc                      |   6 +-
 iocore/net/quic/QUICTLS.cc                         |   6 +
 iocore/net/quic/QUICTLS.h                          |   1 +
 iocore/net/quic/QUICTLS_openssl.cc                 |  31 +--
 iocore/net/quic/QUICTypes.cc                       |  12 +-
 iocore/net/quic/QUICTypes.h                        |  40 ++--
 iocore/net/quic/test/test_QUICFrame.cc             |  14 +-
 iocore/net/quic/test/test_QUICHandshakeProtocol.cc | 221 ++++++++++++---------
 .../net/quic/test/test_QUICIncomingFrameBuffer.cc  |  12 +-
 iocore/net/quic/test/test_QUICStream.cc            |   2 +-
 18 files changed, 262 insertions(+), 213 deletions(-)


[trafficserver] 04/04: Return QUICConnectionError if QUICHandshakeMsgs has error_code

Posted by ma...@apache.org.
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

commit 0014b3664c83d33b0fa1aabb6bfeacbc083698d0
Author: Masaori Koshiba <ma...@apache.org>
AuthorDate: Fri Sep 7 11:41:54 2018 +0900

    Return QUICConnectionError if QUICHandshakeMsgs has error_code
---
 iocore/net/QUICNetVConnection.cc |  2 +-
 iocore/net/quic/QUICHandshake.cc | 27 +++++++++++++++++----------
 iocore/net/quic/QUICHandshake.h  |  2 +-
 3 files changed, 19 insertions(+), 12 deletions(-)

diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc
index abe1b46..63a4148 100644
--- a/iocore/net/QUICNetVConnection.cc
+++ b/iocore/net/QUICNetVConnection.cc
@@ -900,7 +900,7 @@ QUICNetVConnection::_state_handshake_process_initial_packet(QUICPacketUPtr packe
     if (this->_handshake_handler->is_version_negotiated()) {
       error = this->_recv_and_ack(std::move(packet));
 
-      if (!this->_handshake_handler->has_remote_tp()) {
+      if (error->cls == QUICErrorClass::NONE && !this->_handshake_handler->has_remote_tp()) {
         error = QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::TRANSPORT_PARAMETER_ERROR));
       }
     }
diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc
index dffe998..a949011 100644
--- a/iocore/net/quic/QUICHandshake.cc
+++ b/iocore/net/quic/QUICHandshake.cc
@@ -320,7 +320,7 @@ QUICHandshake::handle_frame(QUICEncryptionLevel level, const QUICFrame &frame)
     break;
   }
 
-  this->do_handshake();
+  error = this->do_handshake();
 
   return error;
 }
@@ -389,9 +389,11 @@ QUICHandshake::_load_local_client_transport_parameters(QUICVersion initial_versi
   this->_local_transport_parameters = std::unique_ptr<QUICTransportParameters>(tp);
 }
 
-int
+QUICErrorUPtr
 QUICHandshake::do_handshake()
 {
+  QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError());
+
   QUICHandshakeMsgs in;
   uint8_t in_buf[UDP_MAXIMUM_PAYLOAD_SIZE] = {0};
   in.buf                                   = in_buf;
@@ -420,17 +422,22 @@ QUICHandshake::do_handshake()
 
   int result = this->_hs_protocol->handshake(&out, &in);
 
-  for (auto level : QUIC_ENCRYPTION_LEVELS) {
-    int index                = static_cast<int>(level);
-    QUICCryptoStream *stream = &this->_crypto_streams[index];
-    size_t len               = out.offsets[index + 1] - out.offsets[index];
-    // TODO: check size
-    if (len > 0) {
-      stream->write(out.buf + out.offsets[index], len);
+  if (result == 1) {
+    for (auto level : QUIC_ENCRYPTION_LEVELS) {
+      int index                = static_cast<int>(level);
+      QUICCryptoStream *stream = &this->_crypto_streams[index];
+      size_t len               = out.offsets[index + 1] - out.offsets[index];
+      // TODO: check size
+      if (len > 0) {
+        stream->write(out.buf + out.offsets[index], len);
+      }
     }
+  } else if (out.error_code != 0) {
+    this->_hs_protocol->abort_handshake();
+    error = std::make_unique<QUICConnectionError>(QUICErrorClass::TRANSPORT, out.error_code);
   }
 
-  return result;
+  return error;
 }
 
 void
diff --git a/iocore/net/quic/QUICHandshake.h b/iocore/net/quic/QUICHandshake.h
index f9bcd75..fb5cc21 100644
--- a/iocore/net/quic/QUICHandshake.h
+++ b/iocore/net/quic/QUICHandshake.h
@@ -61,7 +61,7 @@ public:
   // for server side
   QUICErrorUPtr start(const QUICPacket *initial_packet, QUICPacketFactory *packet_factory);
 
-  int do_handshake();
+  QUICErrorUPtr do_handshake();
 
   // Getters
   QUICVersion negotiated_version();


[trafficserver] 01/04: [draft-13] Update Transport Error Codes

Posted by ma...@apache.org.
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

commit 6c7cef9c8d1c927d6f856e8eaa514ae9d532113f
Author: Masaori Koshiba <ma...@apache.org>
AuthorDate: Tue Sep 4 14:20:47 2018 +0900

    [draft-13] Update Transport Error Codes
---
 iocore/net/QUICNetVConnection.cc  |  4 ++--
 iocore/net/quic/QUICDebugNames.cc | 17 +++++++----------
 iocore/net/quic/QUICTypes.h       |  8 +++-----
 3 files changed, 12 insertions(+), 17 deletions(-)

diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc
index ab150be..4732751 100644
--- a/iocore/net/QUICNetVConnection.cc
+++ b/iocore/net/QUICNetVConnection.cc
@@ -549,7 +549,7 @@ QUICNetVConnection::state_handshake(int event, Event *data)
       if (result == QUICPacketCreationResult::NOT_READY) {
         error = QUICErrorUPtr(new QUICNoError());
       } else if (result == QUICPacketCreationResult::FAILED) {
-        error = QUICConnectionErrorUPtr(new QUICConnectionError(QUICTransErrorCode::TLS_FATAL_ALERT_GENERATED));
+        error = QUICConnectionErrorUPtr(new QUICConnectionError(QUICTransErrorCode::INTERNAL_ERROR));
       } else if (result == QUICPacketCreationResult::SUCCESS || result == QUICPacketCreationResult::UNSUPPORTED) {
         error = this->_state_handshake_process_packet(std::move(packet));
       }
@@ -974,7 +974,7 @@ QUICNetVConnection::_state_common_receive_packet()
   do {
     QUICPacketUPtr p = this->_dequeue_recv_packet(result);
     if (result == QUICPacketCreationResult::FAILED) {
-      return QUICConnectionErrorUPtr(new QUICConnectionError(QUICTransErrorCode::TLS_FATAL_ALERT_GENERATED));
+      return QUICConnectionErrorUPtr(new QUICConnectionError(QUICTransErrorCode::INTERNAL_ERROR));
     } else if (result == QUICPacketCreationResult::NO_PACKET) {
       return QUICErrorUPtr(new QUICNoError());
     } else if (result == QUICPacketCreationResult::NOT_READY) {
diff --git a/iocore/net/quic/QUICDebugNames.cc b/iocore/net/quic/QUICDebugNames.cc
index de86f8e..a30e97c 100644
--- a/iocore/net/quic/QUICDebugNames.cc
+++ b/iocore/net/quic/QUICDebugNames.cc
@@ -125,24 +125,21 @@ QUICDebugNames::error_code(QUICTransErrorCode code)
     return "STREAM_STATE_ERROR";
   case QUICTransErrorCode::FINAL_OFFSET_ERROR:
     return "FINAL_OFFSET_ERROR";
-  case QUICTransErrorCode::FRAME_FORMAT_ERROR:
-    return "FRAME_FORMAT_ERROR";
+  case QUICTransErrorCode::FRAME_ENCODING_ERROR:
+    return "FRAME_ENCODING_ERROR";
   case QUICTransErrorCode::TRANSPORT_PARAMETER_ERROR:
     return "TRANSPORT_PARAMETER_ERROR";
   case QUICTransErrorCode::VERSION_NEGOTIATION_ERROR:
     return "VERSION_NEGOTIATION_ERROR";
   case QUICTransErrorCode::PROTOCOL_VIOLATION:
     return "PROTOCOL_VIOLATION";
-  case QUICTransErrorCode::TLS_HANDSHAKE_FAILED:
-    return "TLS_HANDSHAKE_FAILED";
-  case QUICTransErrorCode::TLS_FATAL_ALERT_GENERATED:
-    return "TLS_FATAL_ALERT_GENERATED";
-  case QUICTransErrorCode::TLS_FATAL_ALERT_RECEIVED:
-    return "TLS_FATAL_ALERT_RECEIVED";
+  case QUICTransErrorCode::UNSOLICITED_PATH_RESPONSE:
+    return "UNSOLICITED_PATH_RESPONSE";
+  case QUICTransErrorCode::INVALID_MIGRATION:
+    return "INVALID_MIGRATION";
   default:
     if (0x0100 <= static_cast<uint16_t>(code) && static_cast<uint16_t>(code) <= 0x01FF) {
-      // TODO: Add frame types
-      return "FRAME_ERROR";
+      return "CRYPTO_ERROR";
     }
     return "UNKNOWN";
   }
diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h
index 3076a2d..1089619 100644
--- a/iocore/net/quic/QUICTypes.h
+++ b/iocore/net/quic/QUICTypes.h
@@ -152,15 +152,13 @@ enum class QUICTransErrorCode : uint16_t {
   STREAM_ID_ERROR,
   STREAM_STATE_ERROR,
   FINAL_OFFSET_ERROR,
-  FRAME_FORMAT_ERROR,
+  FRAME_ENCODING_ERROR,
   TRANSPORT_PARAMETER_ERROR,
   VERSION_NEGOTIATION_ERROR,
   PROTOCOL_VIOLATION,
   UNSOLICITED_PATH_RESPONSE = 0x0B,
-  FRAME_ERROR               = 0x0100, // 0x100 - 0x1FF
-  TLS_HANDSHAKE_FAILED      = 0x0201,
-  TLS_FATAL_ALERT_GENERATED,
-  TLS_FATAL_ALERT_RECEIVED,
+  INVALID_MIGRATION         = 0x0C,
+  CRYPTO_ERROR              = 0x0100, // 0x100 - 0x1FF
 };
 
 // Application Protocol Error Codes defined in application


[trafficserver] 02/04: Handle TLS Alerts on msg_cb

Posted by ma...@apache.org.
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

commit e7c493ae72eef75958409ccade0b1b8313ace494
Author: Masaori Koshiba <ma...@apache.org>
AuthorDate: Tue Sep 4 16:20:30 2018 +0900

    Handle TLS Alerts on msg_cb
---
 iocore/net/quic/QUICHandshakeProtocol.h            |   7 +-
 iocore/net/quic/QUICTLS.cc                         |   6 +
 iocore/net/quic/QUICTLS.h                          |   1 +
 iocore/net/quic/QUICTLS_openssl.cc                 |  31 +--
 iocore/net/quic/test/test_QUICHandshakeProtocol.cc | 221 ++++++++++++---------
 5 files changed, 158 insertions(+), 108 deletions(-)

diff --git a/iocore/net/quic/QUICHandshakeProtocol.h b/iocore/net/quic/QUICHandshakeProtocol.h
index abc4410..f489e30 100644
--- a/iocore/net/quic/QUICHandshakeProtocol.h
+++ b/iocore/net/quic/QUICHandshakeProtocol.h
@@ -59,9 +59,10 @@ private:
 };
 
 struct QUICHandshakeMsgs {
-  uint8_t *buf       = nullptr; //< pointer to the buffer
-  size_t max_buf_len = 0;       //< size of buffer
-  size_t offsets[5]  = {0};     //< offset to the each encryption level - {initial, zero_rtt, handshake, one_rtt, total length}
+  uint8_t *buf        = nullptr; //< pointer to the buffer
+  size_t max_buf_len  = 0;       //< size of buffer
+  size_t offsets[5]   = {0};     //< offset to the each encryption level - {initial, zero_rtt, handshake, one_rtt, total length}
+  uint16_t error_code = 0;       //< CRYPTO_ERROR - TLS Alert Desciption + 0x100
 };
 
 class QUICHandshakeProtocol
diff --git a/iocore/net/quic/QUICTLS.cc b/iocore/net/quic/QUICTLS.cc
index bfbff38..23dbfab 100644
--- a/iocore/net/quic/QUICTLS.cc
+++ b/iocore/net/quic/QUICTLS.cc
@@ -45,6 +45,12 @@ QUICTLS::~QUICTLS()
   delete this->_server_pp;
 }
 
+uint16_t
+QUICTLS::convert_to_quic_trans_error_code(uint8_t alert)
+{
+  return 0x100 | alert;
+}
+
 bool
 QUICTLS::is_handshake_finished() const
 {
diff --git a/iocore/net/quic/QUICTLS.h b/iocore/net/quic/QUICTLS.h
index 7e040ac..d7f2ec1 100644
--- a/iocore/net/quic/QUICTLS.h
+++ b/iocore/net/quic/QUICTLS.h
@@ -49,6 +49,7 @@ public:
   };
 
   static QUICEncryptionLevel get_encryption_level(int msg_type);
+  static uint16_t convert_to_quic_trans_error_code(uint8_t alert);
 
   // FIXME Should not exist
   SSL *ssl_handle();
diff --git a/iocore/net/quic/QUICTLS_openssl.cc b/iocore/net/quic/QUICTLS_openssl.cc
index 6f3d25f..bdeda68 100644
--- a/iocore/net/quic/QUICTLS_openssl.cc
+++ b/iocore/net/quic/QUICTLS_openssl.cc
@@ -39,7 +39,7 @@ content_type_str(int type)
   case SSL3_RT_CHANGE_CIPHER_SPEC:
     return "SSL3_RT_CHANGE_CIPHER_SPEC";
   case SSL3_RT_ALERT:
-    return "SSL3_RT_ALERT 21";
+    return "SSL3_RT_ALERT";
   case SSL3_RT_HANDSHAKE:
     return "SSL3_RT_HANDSHAKE";
   case SSL3_RT_APPLICATION_DATA:
@@ -102,25 +102,30 @@ msg_cb(int write_p, int version, int content_type, const void *buf, size_t len,
     return;
   }
 
-  const uint8_t *tmp = reinterpret_cast<const uint8_t *>(buf);
-  int msg_type       = tmp[0];
-
-  QUICEncryptionLevel level = QUICTLS::get_encryption_level(msg_type);
-  int index                 = static_cast<int>(level);
-  int next_index            = index + 1;
-
   QUICHandshakeMsgs *msg = reinterpret_cast<QUICHandshakeMsgs *>(arg);
   if (msg == nullptr) {
     return;
   }
 
-  size_t offset            = msg->offsets[next_index];
-  size_t next_level_offset = offset + len;
+  const uint8_t *msg_buf = reinterpret_cast<const uint8_t *>(buf);
+
+  if (content_type == SSL3_RT_HANDSHAKE) {
+    int msg_type = msg_buf[0];
 
-  memcpy(msg->buf + offset, buf, len);
+    QUICEncryptionLevel level = QUICTLS::get_encryption_level(msg_type);
+    int index                 = static_cast<int>(level);
+    int next_index            = index + 1;
 
-  for (int i = next_index; i < 5; ++i) {
-    msg->offsets[i] = next_level_offset;
+    size_t offset            = msg->offsets[next_index];
+    size_t next_level_offset = offset + len;
+
+    memcpy(msg->buf + offset, buf, len);
+
+    for (int i = next_index; i < 5; ++i) {
+      msg->offsets[i] = next_level_offset;
+    }
+  } else if (content_type == SSL3_RT_ALERT && msg_buf[0] == SSL3_AL_FATAL && len == 2) {
+    msg->error_code = QUICTLS::convert_to_quic_trans_error_code(msg_buf[1]);
   }
 
   return;
diff --git a/iocore/net/quic/test/test_QUICHandshakeProtocol.cc b/iocore/net/quic/test/test_QUICHandshakeProtocol.cc
index 818cf8a..cf81b88 100644
--- a/iocore/net/quic/test/test_QUICHandshakeProtocol.cc
+++ b/iocore/net/quic/test/test_QUICHandshakeProtocol.cc
@@ -154,7 +154,7 @@ static const uint8_t ad[]     = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
 //   delete server;
 // }
 
-TEST_CASE("QUICHandshakeProtocol Full Handshake", "[quic]")
+TEST_CASE("QUICHandshakeProtocol")
 {
   // Client
   SSL_CTX *client_ssl_ctx = SSL_CTX_new(TLS_method());
@@ -164,7 +164,6 @@ TEST_CASE("QUICHandshakeProtocol Full Handshake", "[quic]")
 #ifdef SSL_MODE_QUIC_HACK
   SSL_CTX_set_mode(client_ssl_ctx, SSL_MODE_QUIC_HACK);
 #endif
-  QUICHandshakeProtocol *client = new QUICTLS(client_ssl_ctx, NET_VCONNECTION_OUT);
 
   // Server
   SSL_CTX *server_ssl_ctx = SSL_CTX_new(TLS_method());
@@ -180,116 +179,154 @@ TEST_CASE("QUICHandshakeProtocol Full Handshake", "[quic]")
   BIO *key_bio(BIO_new_mem_buf(server_key, sizeof(server_key)));
   EVP_PKEY *pkey = PEM_read_bio_PrivateKey(key_bio, nullptr, nullptr, nullptr);
   SSL_CTX_use_PrivateKey(server_ssl_ctx, pkey);
-  QUICHandshakeProtocol *server = new QUICTLS(server_ssl_ctx, NET_VCONNECTION_IN);
 
-  BIO_free(crt_bio);
-  BIO_free(key_bio);
+  SECTION("Full Handshake", "[quic]")
+  {
+    QUICHandshakeProtocol *client = new QUICTLS(client_ssl_ctx, NET_VCONNECTION_OUT);
+    QUICHandshakeProtocol *server = new QUICTLS(server_ssl_ctx, NET_VCONNECTION_IN);
 
-  X509_free(x509);
-  EVP_PKEY_free(pkey);
+    CHECK(client->initialize_key_materials({reinterpret_cast<const uint8_t *>("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8}));
+    CHECK(server->initialize_key_materials({reinterpret_cast<const uint8_t *>("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8}));
 
-  CHECK(client->initialize_key_materials({reinterpret_cast<const uint8_t *>("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8}));
-  CHECK(server->initialize_key_materials({reinterpret_cast<const uint8_t *>("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8}));
+    // CH
+    QUICHandshakeMsgs msg1;
+    uint8_t msg1_buf[MAX_HANDSHAKE_MSG_LEN] = {0};
+    msg1.buf                                = msg1_buf;
+    msg1.max_buf_len                        = MAX_HANDSHAKE_MSG_LEN;
 
-  // CH
-  QUICHandshakeMsgs msg1;
-  uint8_t msg1_buf[MAX_HANDSHAKE_MSG_LEN] = {0};
-  msg1.buf                                = msg1_buf;
-  msg1.max_buf_len                        = MAX_HANDSHAKE_MSG_LEN;
+    REQUIRE(client->handshake(&msg1, nullptr) == 1);
+    std::cout << "### Messages from client" << std::endl;
+    print_hex(msg1.buf, msg1.offsets[4]);
 
-  REQUIRE(client->handshake(&msg1, nullptr) == 1);
-  std::cout << "### Messages from client" << std::endl;
-  print_hex(msg1.buf, msg1.offsets[4]);
+    // SH, EE, CERT, CV, FIN
+    QUICHandshakeMsgs msg2;
+    uint8_t msg2_buf[MAX_HANDSHAKE_MSG_LEN] = {0};
+    msg2.buf                                = msg2_buf;
+    msg2.max_buf_len                        = MAX_HANDSHAKE_MSG_LEN;
 
-  // SH, EE, CERT, CV, FIN
-  QUICHandshakeMsgs msg2;
-  uint8_t msg2_buf[MAX_HANDSHAKE_MSG_LEN] = {0};
-  msg2.buf                                = msg2_buf;
-  msg2.max_buf_len                        = MAX_HANDSHAKE_MSG_LEN;
+    REQUIRE(server->handshake(&msg2, &msg1) == 1);
+    std::cout << "### Messages from server" << std::endl;
+    print_hex(msg2.buf, msg2.offsets[4]);
 
-  REQUIRE(server->handshake(&msg2, &msg1) == 1);
-  std::cout << "### Messages from server" << std::endl;
-  print_hex(msg2.buf, msg2.offsets[4]);
-
-  // FIN
-  QUICHandshakeMsgs msg3;
-  uint8_t msg3_buf[MAX_HANDSHAKE_MSG_LEN] = {0};
-  msg3.buf                                = msg3_buf;
-  msg3.max_buf_len                        = MAX_HANDSHAKE_MSG_LEN;
+    // FIN
+    QUICHandshakeMsgs msg3;
+    uint8_t msg3_buf[MAX_HANDSHAKE_MSG_LEN] = {0};
+    msg3.buf                                = msg3_buf;
+    msg3.max_buf_len                        = MAX_HANDSHAKE_MSG_LEN;
 
 #ifdef SSL_MODE_QUIC_HACK
-  // -- Hacks for OpenSSL with SSL_MODE_QUIC_HACK --
-  // SH
-  QUICHandshakeMsgs msg2_1;
-  uint8_t msg2_1_buf[MAX_HANDSHAKE_MSG_LEN] = {0};
-  msg2_1.buf                                = msg2_1_buf;
-  msg2_1.max_buf_len                        = MAX_HANDSHAKE_MSG_LEN;
-
-  memcpy(msg2_1.buf, msg2.buf, msg2.offsets[1]);
-  msg2_1.offsets[0] = 0;
-  msg2_1.offsets[1] = msg2.offsets[1];
-  msg2_1.offsets[2] = msg2.offsets[1];
-  msg2_1.offsets[3] = msg2.offsets[1];
-  msg2_1.offsets[4] = msg2.offsets[1];
-
-  // EE - FIN
-  QUICHandshakeMsgs msg2_2;
-  uint8_t msg2_2_buf[MAX_HANDSHAKE_MSG_LEN] = {0};
-  msg2_2.buf                                = msg2_2_buf;
-  msg2_2.max_buf_len                        = MAX_HANDSHAKE_MSG_LEN;
-
-  size_t len = msg2.offsets[3] - msg2.offsets[2];
-  memcpy(msg2_2.buf, msg2.buf + msg2.offsets[1], len);
-  msg2_2.offsets[0] = 0;
-  msg2_2.offsets[1] = 0;
-  msg2_2.offsets[2] = 0;
-  msg2_2.offsets[3] = len;
-  msg2_2.offsets[4] = len;
-
-  REQUIRE(client->handshake(&msg3, &msg2_1) == 1);
-  REQUIRE(client->handshake(&msg3, &msg2_2) == 1);
+    // -- Hacks for OpenSSL with SSL_MODE_QUIC_HACK --
+    // SH
+    QUICHandshakeMsgs msg2_1;
+    uint8_t msg2_1_buf[MAX_HANDSHAKE_MSG_LEN] = {0};
+    msg2_1.buf                                = msg2_1_buf;
+    msg2_1.max_buf_len                        = MAX_HANDSHAKE_MSG_LEN;
+
+    memcpy(msg2_1.buf, msg2.buf, msg2.offsets[1]);
+    msg2_1.offsets[0] = 0;
+    msg2_1.offsets[1] = msg2.offsets[1];
+    msg2_1.offsets[2] = msg2.offsets[1];
+    msg2_1.offsets[3] = msg2.offsets[1];
+    msg2_1.offsets[4] = msg2.offsets[1];
+
+    // EE - FIN
+    QUICHandshakeMsgs msg2_2;
+    uint8_t msg2_2_buf[MAX_HANDSHAKE_MSG_LEN] = {0};
+    msg2_2.buf                                = msg2_2_buf;
+    msg2_2.max_buf_len                        = MAX_HANDSHAKE_MSG_LEN;
+
+    size_t len = msg2.offsets[3] - msg2.offsets[2];
+    memcpy(msg2_2.buf, msg2.buf + msg2.offsets[1], len);
+    msg2_2.offsets[0] = 0;
+    msg2_2.offsets[1] = 0;
+    msg2_2.offsets[2] = 0;
+    msg2_2.offsets[3] = len;
+    msg2_2.offsets[4] = len;
+
+    REQUIRE(client->handshake(&msg3, &msg2_1) == 1);
+    REQUIRE(client->handshake(&msg3, &msg2_2) == 1);
 #else
-  REQUIRE(client->handshake(&msg3, &msg2) == 1);
+    REQUIRE(client->handshake(&msg3, &msg2) == 1);
 #endif
-  std::cout << "### Messages from client" << std::endl;
-  print_hex(msg3.buf, msg3.offsets[4]);
+    std::cout << "### Messages from client" << std::endl;
+    print_hex(msg3.buf, msg3.offsets[4]);
+
+    // NS
+    QUICHandshakeMsgs msg4;
+    uint8_t msg4_buf[MAX_HANDSHAKE_MSG_LEN] = {0};
+    msg4.buf                                = msg4_buf;
+    msg4.max_buf_len                        = MAX_HANDSHAKE_MSG_LEN;
+
+    REQUIRE(server->handshake(&msg4, &msg3) == 1);
+    std::cout << "### Messages from server" << std::endl;
+    print_hex(msg4.buf, msg4.offsets[4]);
 
-  // NS
-  QUICHandshakeMsgs msg4;
-  uint8_t msg4_buf[MAX_HANDSHAKE_MSG_LEN] = {0};
-  msg4.buf                                = msg4_buf;
-  msg4.max_buf_len                        = MAX_HANDSHAKE_MSG_LEN;
+    // encrypt - decrypt
+    // client (encrypt) - server (decrypt)
+    std::cout << "### Original Text" << std::endl;
+    print_hex(original, sizeof(original));
 
-  REQUIRE(server->handshake(&msg4, &msg3) == 1);
-  std::cout << "### Messages from server" << std::endl;
-  print_hex(msg4.buf, msg4.offsets[4]);
+    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));
 
-  // encrypt - decrypt
-  // client (encrypt) - server (decrypt)
-  std::cout << "### Original Text" << std::endl;
-  print_hex(original, sizeof(original));
+    std::cout << "### Encrypted Text" << std::endl;
+    print_hex(cipher, cipher_len);
 
-  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));
+    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 << "### Encrypted Text" << std::endl;
-  print_hex(cipher, cipher_len);
+    std::cout << "### Decrypted Text" << std::endl;
+    print_hex(plain, plain_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));
+    CHECK(sizeof(original) == (plain_len));
+    CHECK(memcmp(original, plain, plain_len) == 0);
 
-  std::cout << "### Decrypted Text" << std::endl;
-  print_hex(plain, plain_len);
+    // Teardown
+    delete client;
+    delete server;
+  }
 
-  CHECK(sizeof(original) == (plain_len));
-  CHECK(memcmp(original, plain, plain_len) == 0);
+  SECTION("Alert", "[quic]")
+  {
+    QUICHandshakeProtocol *server = new QUICTLS(server_ssl_ctx, NET_VCONNECTION_IN);
+    CHECK(server->initialize_key_materials({reinterpret_cast<const uint8_t *>("\x83\x94\xc8\xf0\x3e\x51\x57\x00"), 8}));
+
+    // Malformed CH (finished)
+    uint8_t msg1_buf[] = {0x14, 0x00, 0x00, 0x30, 0x35, 0xb9, 0x82, 0x9d, 0xb9, 0x14, 0x70, 0x03, 0x60,
+                          0xd2, 0x5a, 0x03, 0x12, 0x12, 0x3d, 0x17, 0xc2, 0x13, 0x8c, 0xd7, 0x8b, 0x6e,
+                          0xc5, 0x4e, 0x50, 0x0a, 0x78, 0x6e, 0xa8, 0x54, 0x5f, 0x74, 0xfb, 0xf5, 0x6e,
+                          0x09, 0x90, 0x07, 0x58, 0x5a, 0x30, 0x5a, 0xe9, 0xcb, 0x1b, 0xa0, 0x69, 0x35};
+    size_t msg1_len    = sizeof(msg1_buf);
+
+    QUICHandshakeMsgs msg1;
+    msg1.buf         = msg1_buf;
+    msg1.max_buf_len = MAX_HANDSHAKE_MSG_LEN;
+    msg1.offsets[0]  = 0;
+    msg1.offsets[1]  = msg1_len;
+    msg1.offsets[2]  = msg1_len;
+    msg1.offsets[3]  = msg1_len;
+    msg1.offsets[4]  = msg1_len;
+
+    QUICHandshakeMsgs msg2;
+    uint8_t msg2_buf[MAX_HANDSHAKE_MSG_LEN] = {0};
+    msg2.buf                                = msg2_buf;
+    msg2.max_buf_len                        = MAX_HANDSHAKE_MSG_LEN;
+
+    CHECK(server->handshake(&msg2, &msg1) != 1);
+    CHECK(msg2.error_code == 0x10a); //< 0x100 + unexpected_message(10)
+
+    // Teardown
+    delete server;
+  }
 
-  // Teardown
-  delete client;
-  delete server;
+  BIO_free(crt_bio);
+  BIO_free(key_bio);
+
+  X509_free(x509);
+  EVP_PKEY_free(pkey);
 
   SSL_CTX_free(server_ssl_ctx);
   SSL_CTX_free(client_ssl_ctx);


[trafficserver] 03/04: Make type of error code uint16_t for CRYPTO_ERROR (0x100 - 0x1FF)

Posted by ma...@apache.org.
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

commit 656dffaa349db242141ba88deb3a03147d527325
Author: Masaori Koshiba <ma...@apache.org>
AuthorDate: Thu Sep 6 16:28:22 2018 +0900

    Make type of error code uint16_t for CRYPTO_ERROR (0x100 - 0x1FF)
---
 iocore/net/QUICNetVConnection.cc                   | 14 +++++-----
 iocore/net/quic/QUICDebugNames.cc                  | 29 ++++++++++----------
 iocore/net/quic/QUICDebugNames.h                   |  2 +-
 iocore/net/quic/QUICFrame.cc                       | 21 +++++++-------
 iocore/net/quic/QUICFrame.h                        | 11 ++++----
 iocore/net/quic/QUICStream.cc                      |  6 ++--
 iocore/net/quic/QUICTypes.cc                       | 12 ++------
 iocore/net/quic/QUICTypes.h                        | 32 ++++++++++------------
 iocore/net/quic/test/test_QUICFrame.cc             | 14 ++++++----
 .../net/quic/test/test_QUICIncomingFrameBuffer.cc  | 12 +++++---
 iocore/net/quic/test/test_QUICStream.cc            |  2 +-
 11 files changed, 76 insertions(+), 79 deletions(-)

diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc
index 4732751..abe1b46 100644
--- a/iocore/net/QUICNetVConnection.cc
+++ b/iocore/net/QUICNetVConnection.cc
@@ -481,11 +481,11 @@ QUICNetVConnection::handle_frame(QUICEncryptionLevel level, const QUICFrame &fra
     // An endpoint MAY transition from the closing period to the draining period if it can confirm that its peer is also closing or
     // draining. Receiving a closing frame is sufficient confirmation, as is receiving a stateless reset.
     if (frame.type() == QUICFrameType::APPLICATION_CLOSE) {
-      this->_switch_to_draining_state(
-        QUICConnectionErrorUPtr(new QUICConnectionError(static_cast<const QUICApplicationCloseFrame &>(frame).error_code())));
+      this->_switch_to_draining_state(QUICConnectionErrorUPtr(
+        new QUICConnectionError(QUICErrorClass::APPLICATION, static_cast<const QUICApplicationCloseFrame &>(frame).error_code())));
     } else {
-      this->_switch_to_draining_state(
-        QUICConnectionErrorUPtr(new QUICConnectionError(static_cast<const QUICConnectionCloseFrame &>(frame).error_code())));
+      this->_switch_to_draining_state(QUICConnectionErrorUPtr(
+        new QUICConnectionError(QUICErrorClass::TRANSPORT, static_cast<const QUICConnectionCloseFrame &>(frame).error_code())));
     }
     break;
   default:
@@ -629,7 +629,7 @@ QUICNetVConnection::state_connection_established(int event, Event *data)
   }
 
   if (error->cls != QUICErrorClass::NONE) {
-    QUICConDebug("QUICError: cls=%u, code=0x%" PRIu16, static_cast<unsigned int>(error->cls), error->code());
+    QUICConDebug("QUICError: cls=%u, code=0x%" PRIu16, static_cast<unsigned int>(error->cls), error->code);
     this->_handle_error(std::move(error));
   }
 
@@ -1477,10 +1477,10 @@ QUICNetVConnection::_handle_error(QUICErrorUPtr error)
 {
   if (error->cls == QUICErrorClass::APPLICATION) {
     QUICError("QUICError: %s (%u), APPLICATION ERROR (0x%" PRIu16 ")", QUICDebugNames::error_class(error->cls),
-              static_cast<unsigned int>(error->cls), error->code());
+              static_cast<unsigned int>(error->cls), error->code);
   } else {
     QUICError("QUICError: %s (%u), %s (0x%" PRIu16 ")", QUICDebugNames::error_class(error->cls),
-              static_cast<unsigned int>(error->cls), QUICDebugNames::error_code(error->trans_error_code), error->code());
+              static_cast<unsigned int>(error->cls), QUICDebugNames::error_code(error->code), error->code);
   }
 
   if (dynamic_cast<QUICStreamError *>(error.get()) != nullptr) {
diff --git a/iocore/net/quic/QUICDebugNames.cc b/iocore/net/quic/QUICDebugNames.cc
index a30e97c..44f13eb 100644
--- a/iocore/net/quic/QUICDebugNames.cc
+++ b/iocore/net/quic/QUICDebugNames.cc
@@ -110,37 +110,38 @@ QUICDebugNames::error_class(QUICErrorClass cls)
 }
 
 const char *
-QUICDebugNames::error_code(QUICTransErrorCode code)
+QUICDebugNames::error_code(uint16_t code)
 {
   switch (code) {
-  case QUICTransErrorCode::NO_ERROR:
+  case static_cast<uint16_t>(QUICTransErrorCode::NO_ERROR):
     return "NO_ERROR";
-  case QUICTransErrorCode::INTERNAL_ERROR:
+  case static_cast<uint16_t>(QUICTransErrorCode::INTERNAL_ERROR):
     return "INTERNAL_ERROR";
-  case QUICTransErrorCode::FLOW_CONTROL_ERROR:
+  case static_cast<uint16_t>(QUICTransErrorCode::FLOW_CONTROL_ERROR):
     return "FLOW_CONTROL_ERROR";
-  case QUICTransErrorCode::STREAM_ID_ERROR:
+  case static_cast<uint16_t>(QUICTransErrorCode::STREAM_ID_ERROR):
     return "STREAM_ID_ERROR";
-  case QUICTransErrorCode::STREAM_STATE_ERROR:
+  case static_cast<uint16_t>(QUICTransErrorCode::STREAM_STATE_ERROR):
     return "STREAM_STATE_ERROR";
-  case QUICTransErrorCode::FINAL_OFFSET_ERROR:
+  case static_cast<uint16_t>(QUICTransErrorCode::FINAL_OFFSET_ERROR):
     return "FINAL_OFFSET_ERROR";
-  case QUICTransErrorCode::FRAME_ENCODING_ERROR:
+  case static_cast<uint16_t>(QUICTransErrorCode::FRAME_ENCODING_ERROR):
     return "FRAME_ENCODING_ERROR";
-  case QUICTransErrorCode::TRANSPORT_PARAMETER_ERROR:
+  case static_cast<uint16_t>(QUICTransErrorCode::TRANSPORT_PARAMETER_ERROR):
     return "TRANSPORT_PARAMETER_ERROR";
-  case QUICTransErrorCode::VERSION_NEGOTIATION_ERROR:
+  case static_cast<uint16_t>(QUICTransErrorCode::VERSION_NEGOTIATION_ERROR):
     return "VERSION_NEGOTIATION_ERROR";
-  case QUICTransErrorCode::PROTOCOL_VIOLATION:
+  case static_cast<uint16_t>(QUICTransErrorCode::PROTOCOL_VIOLATION):
     return "PROTOCOL_VIOLATION";
-  case QUICTransErrorCode::UNSOLICITED_PATH_RESPONSE:
+  case static_cast<uint16_t>(QUICTransErrorCode::UNSOLICITED_PATH_RESPONSE):
     return "UNSOLICITED_PATH_RESPONSE";
-  case QUICTransErrorCode::INVALID_MIGRATION:
+  case static_cast<uint16_t>(QUICTransErrorCode::INVALID_MIGRATION):
     return "INVALID_MIGRATION";
   default:
-    if (0x0100 <= static_cast<uint16_t>(code) && static_cast<uint16_t>(code) <= 0x01FF) {
+    if (0x0100 <= code && code <= 0x01FF) {
       return "CRYPTO_ERROR";
     }
+
     return "UNKNOWN";
   }
 }
diff --git a/iocore/net/quic/QUICDebugNames.h b/iocore/net/quic/QUICDebugNames.h
index b2ce4ec..25411cf 100644
--- a/iocore/net/quic/QUICDebugNames.h
+++ b/iocore/net/quic/QUICDebugNames.h
@@ -34,7 +34,7 @@ public:
   static const char *packet_type(QUICPacketType type);
   static const char *frame_type(QUICFrameType type);
   static const char *error_class(QUICErrorClass cls);
-  static const char *error_code(QUICTransErrorCode code);
+  static const char *error_code(uint16_t code);
   static const char *transport_parameter_id(QUICTransportParameterId id);
   static const char *stream_state(const QUICStreamState &state);
   static const char *quic_event(int event);
diff --git a/iocore/net/quic/QUICFrame.cc b/iocore/net/quic/QUICFrame.cc
index 71ae896..43459f2 100644
--- a/iocore/net/quic/QUICFrame.cc
+++ b/iocore/net/quic/QUICFrame.cc
@@ -1214,8 +1214,8 @@ QUICPaddingFrame::store(uint8_t *buf, size_t *len, size_t limit) const
 //
 // CONNECTION_CLOSE frame
 //
-QUICConnectionCloseFrame::QUICConnectionCloseFrame(QUICTransErrorCode error_code, QUICFrameType frame_type,
-                                                   uint64_t reason_phrase_length, const char *reason_phrase, bool protection)
+QUICConnectionCloseFrame::QUICConnectionCloseFrame(uint16_t error_code, QUICFrameType frame_type, uint64_t reason_phrase_length,
+                                                   const char *reason_phrase, bool protection)
   : QUICFrame(protection),
     _error_code(error_code),
     _frame_type(frame_type),
@@ -1312,7 +1312,7 @@ QUICConnectionCloseFrame::debug_msg(char *msg, size_t msg_len) const
   return len;
 }
 
-QUICTransErrorCode
+uint16_t
 QUICConnectionCloseFrame::error_code() const
 {
   if (this->_buf) {
@@ -2625,8 +2625,8 @@ QUICFrameFactory::create_ack_frame(QUICPacketNumber largest_acknowledged, uint64
 }
 
 std::unique_ptr<QUICConnectionCloseFrame, QUICFrameDeleterFunc>
-QUICFrameFactory::create_connection_close_frame(QUICTransErrorCode error_code, QUICFrameType frame_type,
-                                                uint16_t reason_phrase_length, const char *reason_phrase)
+QUICFrameFactory::create_connection_close_frame(uint16_t error_code, QUICFrameType frame_type, uint16_t reason_phrase_length,
+                                                const char *reason_phrase)
 {
   QUICConnectionCloseFrame *frame = quicConnectionCloseFrameAllocator.alloc();
   new (frame) QUICConnectionCloseFrame(error_code, frame_type, reason_phrase_length, reason_phrase);
@@ -2638,10 +2638,9 @@ QUICFrameFactory::create_connection_close_frame(QUICConnectionErrorUPtr error)
 {
   ink_assert(error->cls == QUICErrorClass::TRANSPORT);
   if (error->msg) {
-    return QUICFrameFactory::create_connection_close_frame(error->trans_error_code, error->frame_type(), strlen(error->msg),
-                                                           error->msg);
+    return QUICFrameFactory::create_connection_close_frame(error->code, error->frame_type(), strlen(error->msg), error->msg);
   } else {
-    return QUICFrameFactory::create_connection_close_frame(error->trans_error_code, error->frame_type());
+    return QUICFrameFactory::create_connection_close_frame(error->code, error->frame_type());
   }
 }
 
@@ -2659,9 +2658,9 @@ QUICFrameFactory::create_application_close_frame(QUICConnectionErrorUPtr error)
 {
   ink_assert(error->cls == QUICErrorClass::APPLICATION);
   if (error->msg) {
-    return QUICFrameFactory::create_application_close_frame(error->app_error_code, strlen(error->msg), error->msg);
+    return QUICFrameFactory::create_application_close_frame(error->code, strlen(error->msg), error->msg);
   } else {
-    return QUICFrameFactory::create_application_close_frame(error->app_error_code);
+    return QUICFrameFactory::create_application_close_frame(error->code);
   }
 }
 
@@ -2754,7 +2753,7 @@ QUICFrameFactory::create_rst_stream_frame(QUICStreamId stream_id, QUICAppErrorCo
 std::unique_ptr<QUICRstStreamFrame, QUICFrameDeleterFunc>
 QUICFrameFactory::create_rst_stream_frame(QUICStreamErrorUPtr error)
 {
-  return QUICFrameFactory::create_rst_stream_frame(error->stream->id(), error->app_error_code, error->stream->final_offset());
+  return QUICFrameFactory::create_rst_stream_frame(error->stream->id(), error->code, error->stream->final_offset());
 }
 
 std::unique_ptr<QUICStopSendingFrame, QUICFrameDeleterFunc>
diff --git a/iocore/net/quic/QUICFrame.h b/iocore/net/quic/QUICFrame.h
index a82ac07..0a9769d 100644
--- a/iocore/net/quic/QUICFrame.h
+++ b/iocore/net/quic/QUICFrame.h
@@ -350,15 +350,15 @@ class QUICConnectionCloseFrame : public QUICFrame
 public:
   QUICConnectionCloseFrame() : QUICFrame() {}
   QUICConnectionCloseFrame(const uint8_t *buf, size_t len, bool protection = true) : QUICFrame(buf, len, protection) {}
-  QUICConnectionCloseFrame(QUICTransErrorCode error_code, QUICFrameType frame_type, uint64_t reason_phrase_length,
-                           const char *reason_phrase, bool protection = true);
+  QUICConnectionCloseFrame(uint16_t error_code, QUICFrameType frame_type, uint64_t reason_phrase_length, const char *reason_phrase,
+                           bool protection = true);
   QUICFrameUPtr clone() const override;
   virtual QUICFrameType type() const override;
   virtual size_t size() const override;
   virtual size_t store(uint8_t *buf, size_t *len, size_t limit) const override;
   virtual int debug_msg(char *msg, size_t msg_len) const override;
 
-  QUICTransErrorCode error_code() const;
+  uint16_t error_code() const;
   QUICFrameType frame_type() const;
   uint64_t reason_phrase_length() const;
   const char *reason_phrase() const;
@@ -369,7 +369,7 @@ private:
   size_t _get_reason_phrase_length_field_length() const;
   size_t _get_reason_phrase_field_offset() const;
 
-  QUICTransErrorCode _error_code;
+  uint16_t _error_code;
   QUICFrameType _frame_type      = QUICFrameType::UNKNOWN;
   uint64_t _reason_phrase_length = 0;
   const char *_reason_phrase     = nullptr;
@@ -938,8 +938,7 @@ public:
    * Creates a CONNECTION_CLOSE frame.
    */
   static std::unique_ptr<QUICConnectionCloseFrame, QUICFrameDeleterFunc> create_connection_close_frame(
-    QUICTransErrorCode error_code, QUICFrameType frame_type, uint16_t reason_phrase_length = 0,
-    const char *reason_phrase = nullptr);
+    uint16_t error_code, QUICFrameType frame_type, uint16_t reason_phrase_length = 0, const char *reason_phrase = nullptr);
 
   static std::unique_ptr<QUICConnectionCloseFrame, QUICFrameDeleterFunc> create_connection_close_frame(
     QUICConnectionErrorUPtr error);
diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc
index 564e6b5..f0a1add 100644
--- a/iocore/net/quic/QUICStream.cc
+++ b/iocore/net/quic/QUICStream.cc
@@ -136,11 +136,11 @@ QUICStream::state_stream_open(int event, void *data)
   if (error->cls != QUICErrorClass::NONE) {
     if (error->cls == QUICErrorClass::TRANSPORT) {
       QUICStreamDebug("QUICError: %s (%u), %s (0x%x)", QUICDebugNames::error_class(error->cls),
-                      static_cast<unsigned int>(error->cls), QUICDebugNames::error_code(error->trans_error_code),
-                      static_cast<unsigned int>(error->trans_error_code));
+                      static_cast<unsigned int>(error->cls), QUICDebugNames::error_code(error->code),
+                      static_cast<unsigned int>(error->code));
     } else {
       QUICStreamDebug("QUICError: %s (%u), APPLICATION ERROR (0x%x)", QUICDebugNames::error_class(error->cls),
-                      static_cast<unsigned int>(error->cls), static_cast<unsigned int>(error->app_error_code));
+                      static_cast<unsigned int>(error->cls), static_cast<unsigned int>(error->code));
     }
     if (dynamic_cast<QUICStreamError *>(error.get()) != nullptr) {
       // Stream Error
diff --git a/iocore/net/quic/QUICTypes.cc b/iocore/net/quic/QUICTypes.cc
index 4698823..535e495 100644
--- a/iocore/net/quic/QUICTypes.cc
+++ b/iocore/net/quic/QUICTypes.cc
@@ -182,10 +182,10 @@ QUICTypeUtil::read_QUICOffset(const uint8_t *buf)
   return static_cast<QUICOffset>(QUICIntUtil::read_QUICVariableInt(buf));
 }
 
-QUICTransErrorCode
+uint16_t
 QUICTypeUtil::read_QUICTransErrorCode(const uint8_t *buf)
 {
-  return static_cast<QUICTransErrorCode>(QUICIntUtil::read_nbytes_as_uint(buf, 2));
+  return QUICIntUtil::read_nbytes_as_uint(buf, 2);
 }
 
 QUICAppErrorCode
@@ -242,7 +242,7 @@ QUICTypeUtil::write_QUICOffset(QUICOffset offset, uint8_t *buf, size_t *len)
 }
 
 void
-QUICTypeUtil::write_QUICTransErrorCode(QUICTransErrorCode error_code, uint8_t *buf, size_t *len)
+QUICTypeUtil::write_QUICTransErrorCode(uint16_t error_code, uint8_t *buf, size_t *len)
 {
   QUICIntUtil::write_uint_as_nbytes(static_cast<uint64_t>(error_code), 2, buf, len);
 }
@@ -274,12 +274,6 @@ QUICStatelessResetToken::_gen_token(uint64_t data)
   QUICIntUtil::write_uint_as_nbytes(_hash.u64[1], 8, _token + 8, &dummy);
 }
 
-uint16_t
-QUICError::code()
-{
-  return static_cast<uint16_t>(this->trans_error_code);
-}
-
 QUICFrameType
 QUICConnectionError::frame_type() const
 {
diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h
index 1089619..5e7a01e 100644
--- a/iocore/net/quic/QUICTypes.h
+++ b/iocore/net/quic/QUICTypes.h
@@ -169,21 +169,17 @@ class QUICError
 {
 public:
   virtual ~QUICError() {}
-  uint16_t code();
 
   QUICErrorClass cls = QUICErrorClass::NONE;
-  union {
-    QUICTransErrorCode trans_error_code = QUICTransErrorCode::NO_ERROR;
-    QUICAppErrorCode app_error_code;
-  };
-  const char *msg = nullptr;
+  uint16_t code      = 0;
+  const char *msg    = nullptr;
 
 protected:
   QUICError(){};
-  QUICError(const QUICTransErrorCode error_code, const char *error_msg = nullptr)
-    : cls(QUICErrorClass::TRANSPORT), trans_error_code(error_code), msg(error_msg){};
-  QUICError(const QUICAppErrorCode error_code, const char *error_msg = nullptr)
-    : cls(QUICErrorClass::APPLICATION), app_error_code(error_code), msg(error_msg){};
+  QUICError(QUICErrorClass error_class, uint16_t error_code, const char *error_msg = nullptr)
+    : cls(error_class), code(error_code), msg(error_msg)
+  {
+  }
 };
 
 class QUICNoError : public QUICError
@@ -196,10 +192,12 @@ class QUICConnectionError : public QUICError
 {
 public:
   QUICConnectionError() : QUICError() {}
-  QUICConnectionError(const QUICTransErrorCode error_code, const char *error_msg = nullptr,
+  QUICConnectionError(QUICTransErrorCode error_code, const char *error_msg = nullptr,
+                      QUICFrameType frame_type = QUICFrameType::UNKNOWN)
+    : QUICError(QUICErrorClass::TRANSPORT, static_cast<uint16_t>(error_code), error_msg), _frame_type(frame_type){};
+  QUICConnectionError(QUICErrorClass error_class, uint16_t error_code, const char *error_msg = nullptr,
                       QUICFrameType frame_type = QUICFrameType::UNKNOWN)
-    : QUICError(error_code, error_msg), _frame_type(frame_type){};
-  QUICConnectionError(const QUICAppErrorCode error_code, const char *error_msg = nullptr) : QUICError(error_code, error_msg){};
+    : QUICError(error_class, error_code, error_msg), _frame_type(frame_type){};
 
   QUICFrameType frame_type() const;
 
@@ -214,9 +212,9 @@ class QUICStreamError : public QUICError
 public:
   QUICStreamError() : QUICError() {}
   QUICStreamError(const QUICStream *s, const QUICTransErrorCode error_code, const char *error_msg = nullptr)
-    : QUICError(error_code, error_msg), stream(s){};
+    : QUICError(QUICErrorClass::TRANSPORT, static_cast<uint16_t>(error_code), error_msg), stream(s){};
   QUICStreamError(const QUICStream *s, const QUICAppErrorCode error_code, const char *error_msg = nullptr)
-    : QUICError(error_code, error_msg), stream(s){};
+    : QUICError(QUICErrorClass::APPLICATION, static_cast<uint16_t>(error_code), error_msg), stream(s){};
 
   const QUICStream *stream;
 };
@@ -349,7 +347,7 @@ public:
   static QUICVersion read_QUICVersion(const uint8_t *buf);
   static QUICStreamId read_QUICStreamId(const uint8_t *buf);
   static QUICOffset read_QUICOffset(const uint8_t *buf);
-  static QUICTransErrorCode read_QUICTransErrorCode(const uint8_t *buf);
+  static uint16_t read_QUICTransErrorCode(const uint8_t *buf);
   static QUICAppErrorCode read_QUICAppErrorCode(const uint8_t *buf);
   static uint64_t read_QUICMaxData(const uint8_t *buf);
 
@@ -358,7 +356,7 @@ public:
   static void write_QUICVersion(QUICVersion version, uint8_t *buf, size_t *len);
   static void write_QUICStreamId(QUICStreamId stream_id, uint8_t *buf, size_t *len);
   static void write_QUICOffset(QUICOffset offset, uint8_t *buf, size_t *len);
-  static void write_QUICTransErrorCode(QUICTransErrorCode error_code, uint8_t *buf, size_t *len);
+  static void write_QUICTransErrorCode(uint16_t error_code, uint8_t *buf, size_t *len);
   static void write_QUICAppErrorCode(QUICAppErrorCode error_code, uint8_t *buf, size_t *len);
   static void write_QUICMaxData(uint64_t max_data, uint8_t *buf, size_t *len);
 
diff --git a/iocore/net/quic/test/test_QUICFrame.cc b/iocore/net/quic/test/test_QUICFrame.cc
index d7dc8f9..d488a2a 100644
--- a/iocore/net/quic/test/test_QUICFrame.cc
+++ b/iocore/net/quic/test/test_QUICFrame.cc
@@ -647,7 +647,7 @@ TEST_CASE("ConnectionClose Frame", "[quic]")
     std::shared_ptr<const QUICConnectionCloseFrame> conn_close_frame =
       std::dynamic_pointer_cast<const QUICConnectionCloseFrame>(frame);
     CHECK(conn_close_frame != nullptr);
-    CHECK(conn_close_frame->error_code() == QUICTransErrorCode::PROTOCOL_VIOLATION);
+    CHECK(conn_close_frame->error_code() == static_cast<uint16_t>(QUICTransErrorCode::PROTOCOL_VIOLATION));
     CHECK(conn_close_frame->frame_type() == QUICFrameType::UNKNOWN);
     CHECK(conn_close_frame->reason_phrase_length() == reason_phrase_len);
     CHECK(memcmp(conn_close_frame->reason_phrase(), reason_phrase, reason_phrase_len) == 0);
@@ -668,7 +668,7 @@ TEST_CASE("ConnectionClose Frame", "[quic]")
     std::shared_ptr<const QUICConnectionCloseFrame> conn_close_frame =
       std::dynamic_pointer_cast<const QUICConnectionCloseFrame>(frame);
     CHECK(conn_close_frame != nullptr);
-    CHECK(conn_close_frame->error_code() == QUICTransErrorCode::PROTOCOL_VIOLATION);
+    CHECK(conn_close_frame->error_code() == static_cast<uint16_t>(QUICTransErrorCode::PROTOCOL_VIOLATION));
     CHECK(conn_close_frame->frame_type() == QUICFrameType::RST_STREAM);
     CHECK(conn_close_frame->reason_phrase_length() == 0);
   }
@@ -685,7 +685,8 @@ TEST_CASE("ConnectionClose Frame", "[quic]")
       0x05,                        // Reason Phrase Length
       0x41, 0x42, 0x43, 0x44, 0x45 // Reason Phrase ("ABCDE");
     };
-    QUICConnectionCloseFrame connection_close_frame(QUICTransErrorCode::PROTOCOL_VIOLATION, QUICFrameType::STREAM, 5, "ABCDE");
+    QUICConnectionCloseFrame connection_close_frame(static_cast<uint16_t>(QUICTransErrorCode::PROTOCOL_VIOLATION),
+                                                    QUICFrameType::STREAM, 5, "ABCDE");
     CHECK(connection_close_frame.size() == sizeof(expected));
 
     connection_close_frame.store(buf, &len, 32);
@@ -704,7 +705,8 @@ TEST_CASE("ConnectionClose Frame", "[quic]")
       0x00,       // Frame Type
       0x00,       // Reason Phrase Length
     };
-    QUICConnectionCloseFrame connection_close_frame(QUICTransErrorCode::PROTOCOL_VIOLATION, QUICFrameType::UNKNOWN, 0, nullptr);
+    QUICConnectionCloseFrame connection_close_frame(static_cast<uint16_t>(QUICTransErrorCode::PROTOCOL_VIOLATION),
+                                                    QUICFrameType::UNKNOWN, 0, nullptr);
     connection_close_frame.store(buf, &len, 32);
     CHECK(len == sizeof(expected));
     CHECK(memcmp(buf, expected, len) == 0);
@@ -1238,14 +1240,14 @@ TEST_CASE("QUICFrameFactory Create CONNECTION_CLOSE with a QUICConnectionError",
     std::unique_ptr<QUICConnectionError>(new QUICConnectionError(QUICTransErrorCode::INTERNAL_ERROR));
   std::unique_ptr<QUICConnectionCloseFrame, QUICFrameDeleterFunc> connection_close_frame1 =
     QUICFrameFactory::create_connection_close_frame(std::move(error));
-  CHECK(connection_close_frame1->error_code() == QUICTransErrorCode::INTERNAL_ERROR);
+  CHECK(connection_close_frame1->error_code() == static_cast<uint16_t>(QUICTransErrorCode::INTERNAL_ERROR));
   CHECK(connection_close_frame1->reason_phrase_length() == 0);
   CHECK(connection_close_frame1->reason_phrase() == nullptr);
 
   error = std::unique_ptr<QUICConnectionError>(new QUICConnectionError(QUICTransErrorCode::INTERNAL_ERROR, "test"));
   std::unique_ptr<QUICConnectionCloseFrame, QUICFrameDeleterFunc> connection_close_frame2 =
     QUICFrameFactory::create_connection_close_frame(std::move(error));
-  CHECK(connection_close_frame2->error_code() == QUICTransErrorCode::INTERNAL_ERROR);
+  CHECK(connection_close_frame2->error_code() == static_cast<uint16_t>(QUICTransErrorCode::INTERNAL_ERROR));
   CHECK(connection_close_frame2->reason_phrase_length() == 4);
   CHECK(memcmp(connection_close_frame2->reason_phrase(), "test", 4) == 0);
 }
diff --git a/iocore/net/quic/test/test_QUICIncomingFrameBuffer.cc b/iocore/net/quic/test/test_QUICIncomingFrameBuffer.cc
index e8c1049..1ee7add 100644
--- a/iocore/net/quic/test/test_QUICIncomingFrameBuffer.cc
+++ b/iocore/net/quic/test/test_QUICIncomingFrameBuffer.cc
@@ -40,7 +40,8 @@ TEST_CASE("QUICIncomingStreamFrameBuffer_fin_offset", "[quic]")
     std::shared_ptr<QUICStreamFrame> stream1_frame_0_r = QUICFrameFactory::create_stream_frame(data, 1024, 1, 0, true);
 
     err = buffer.insert(*stream1_frame_0_r);
-    CHECK(err->trans_error_code != QUICTransErrorCode::FINAL_OFFSET_ERROR);
+    CHECK(err->cls == QUICErrorClass::NONE);
+    CHECK(err->code != static_cast<uint16_t>(QUICTransErrorCode::FINAL_OFFSET_ERROR));
   }
 
   SECTION("multiple frames")
@@ -55,7 +56,8 @@ TEST_CASE("QUICIncomingStreamFrameBuffer_fin_offset", "[quic]")
     buffer.insert(*stream1_frame_1_r);
     buffer.insert(*stream1_frame_2_r);
     err = buffer.insert(*stream1_frame_3_r);
-    CHECK(err->trans_error_code == QUICTransErrorCode::FINAL_OFFSET_ERROR);
+    CHECK(err->cls == QUICErrorClass::TRANSPORT);
+    CHECK(err->code == static_cast<uint16_t>(QUICTransErrorCode::FINAL_OFFSET_ERROR));
 
     QUICIncomingStreamFrameBuffer buffer2(stream);
 
@@ -63,13 +65,15 @@ TEST_CASE("QUICIncomingStreamFrameBuffer_fin_offset", "[quic]")
     buffer2.insert(*stream1_frame_0_r);
     buffer2.insert(*stream1_frame_1_r);
     err = buffer2.insert(*stream1_frame_2_r);
-    CHECK(err->trans_error_code == QUICTransErrorCode::FINAL_OFFSET_ERROR);
+    CHECK(err->cls == QUICErrorClass::TRANSPORT);
+    CHECK(err->code == static_cast<uint16_t>(QUICTransErrorCode::FINAL_OFFSET_ERROR));
 
     QUICIncomingStreamFrameBuffer buffer3(stream);
 
     buffer3.insert(*stream1_frame_4_r);
     err = buffer3.insert(*stream1_frame_3_r);
-    CHECK(err->trans_error_code == QUICTransErrorCode::FINAL_OFFSET_ERROR);
+    CHECK(err->cls == QUICErrorClass::TRANSPORT);
+    CHECK(err->code == static_cast<uint16_t>(QUICTransErrorCode::FINAL_OFFSET_ERROR));
   }
 
   SECTION("Pure FIN")
diff --git a/iocore/net/quic/test/test_QUICStream.cc b/iocore/net/quic/test/test_QUICStream.cc
index f178279..e7a791c 100644
--- a/iocore/net/quic/test/test_QUICStream.cc
+++ b/iocore/net/quic/test/test_QUICStream.cc
@@ -175,7 +175,7 @@ TEST_CASE("QUICStream", "[quic]")
     // this should exceed the limit
     error = stream->recv(*std::make_shared<QUICStreamFrame>(ats_unique_malloc(1024), 1024, stream_id, 8192));
     CHECK(error->cls == QUICErrorClass::TRANSPORT);
-    CHECK(error->trans_error_code == QUICTransErrorCode::FLOW_CONTROL_ERROR);
+    CHECK(error->code == static_cast<uint16_t>(QUICTransErrorCode::FLOW_CONTROL_ERROR));
   }
 
   SECTION("QUICStream_flow_control_remote", "[quic]")