From bfec8198f2a4f1a9229f5118bb0c344cec2b7ed1 Mon Sep 17 00:00:00 2001
From: Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com>
Date: Tue, 4 Feb 2020 00:18:08 +0900
Subject: [PATCH] Add API to remember the TLS error

---
 crypto/openssl/openssl.c     |  2 ++
 examples/client.cc           |  3 +++
 examples/server.cc           |  3 +++
 lib/includes/ngtcp2/ngtcp2.h | 21 +++++++++++++++++++++
 lib/ngtcp2_conn.c            |  8 ++++++++
 lib/ngtcp2_conn.h            |  2 ++
 lib/ngtcp2_err.c             |  1 +
 7 files changed, 40 insertions(+)

diff --git a/crypto/openssl/openssl.c b/crypto/openssl/openssl.c
index 17320ae9..5e6a8493 100644
--- a/crypto/openssl/openssl.c
+++ b/crypto/openssl/openssl.c
@@ -381,11 +381,13 @@ int ngtcp2_crypto_set_remote_transport_params(ngtcp2_conn *conn, void *tls,
 
   rv = ngtcp2_decode_transport_params(&params, exttype, tp, tplen);
   if (rv != 0) {
+    ngtcp2_conn_set_tls_error(conn, rv);
     return -1;
   }
 
   rv = ngtcp2_conn_set_remote_transport_params(conn, &params);
   if (rv != 0) {
+    ngtcp2_conn_set_tls_error(conn, rv);
     return -1;
   }
 
diff --git a/examples/client.cc b/examples/client.cc
index 84253fe1..d25c54db 100644
--- a/examples/client.cc
+++ b/examples/client.cc
@@ -475,6 +475,9 @@ int recv_crypto_data(ngtcp2_conn *conn, ngtcp2_crypto_level crypto_level,
   auto c = static_cast<Client *>(user_data);
 
   if (c->recv_crypto_data(crypto_level, data, datalen) != 0) {
+    if (auto err = ngtcp2_conn_get_tls_error(conn); err) {
+      return err;
+    }
     return NGTCP2_ERR_CRYPTO;
   }
 
diff --git a/examples/server.cc b/examples/server.cc
index 427a3d29..8797fe1c 100644
--- a/examples/server.cc
+++ b/examples/server.cc
@@ -772,6 +772,9 @@ int recv_crypto_data(ngtcp2_conn *conn, ngtcp2_crypto_level crypto_level,
   auto h = static_cast<Handler *>(user_data);
 
   if (h->recv_crypto_data(crypto_level, data, datalen) != 0) {
+    if (auto err = ngtcp2_conn_get_tls_error(conn); err) {
+      return err;
+    }
     return NGTCP2_ERR_CRYPTO;
   }
 
diff --git a/lib/includes/ngtcp2/ngtcp2.h b/lib/includes/ngtcp2/ngtcp2.h
index 917cbb6f..936b876e 100644
--- a/lib/includes/ngtcp2/ngtcp2.h
+++ b/lib/includes/ngtcp2/ngtcp2.h
@@ -1932,6 +1932,27 @@ NGTCP2_EXTERN int ngtcp2_conn_install_key(
 NGTCP2_EXTERN int ngtcp2_conn_initiate_key_update(ngtcp2_conn *conn,
                                                   ngtcp2_tstamp ts);
 
+/**
+ * @function
+ *
+ * `ngtcp2_conn_set_tls_error` sets the TLS related error in |conn|.
+ * In general, error code should be propagated via return value, but
+ * sometimes ngtcp2 API is called inside callback function of TLS
+ * stack and it does not allow to return ngtcp2 error code directly.
+ * In this case, implementation can set the error code (e.g.,
+ * NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM) using this function.
+ */
+NGTCP2_EXTERN void ngtcp2_conn_set_tls_error(ngtcp2_conn *conn, int liberr);
+
+/**
+ * @function
+ *
+ * `ngtcp2_conn_get_tls_error` returns the value set by
+ * `ngtcp2_conn_set_tls_error`.  If no value is set, this function
+ * returns 0.
+ */
+NGTCP2_EXTERN int ngtcp2_conn_get_tls_error(ngtcp2_conn *conn);
+
 /**
  * @function
  *
diff --git a/lib/ngtcp2_conn.c b/lib/ngtcp2_conn.c
index 4daf7914..bda3fde1 100644
--- a/lib/ngtcp2_conn.c
+++ b/lib/ngtcp2_conn.c
@@ -9261,6 +9261,14 @@ void ngtcp2_conn_get_connection_close_error_code(
   *ccec = conn->rx.ccec;
 }
 
+void ngtcp2_conn_set_tls_error(ngtcp2_conn *conn, int liberr) {
+  conn->crypto.tls_error = liberr;
+}
+
+int ngtcp2_conn_get_tls_error(ngtcp2_conn *conn) {
+  return conn->crypto.tls_error;
+}
+
 void ngtcp2_path_challenge_entry_init(ngtcp2_path_challenge_entry *pcent,
                                       const uint8_t *data) {
   memcpy(pcent->data, data, sizeof(pcent->data));
diff --git a/lib/ngtcp2_conn.h b/lib/ngtcp2_conn.h
index ba3a61a8..3b17a3d2 100644
--- a/lib/ngtcp2_conn.h
+++ b/lib/ngtcp2_conn.h
@@ -422,6 +422,8 @@ struct ngtcp2_conn {
     ngtcp2_vec decrypt_buf;
     /* retry_aead is AEAD to verify Retry packet integrity. */
     ngtcp2_crypto_aead retry_aead;
+    /* tls_error is TLS related error. */
+    int tls_error;
   } crypto;
 
   /* pkt contains the packet intermediate construction data to support
diff --git a/lib/ngtcp2_err.c b/lib/ngtcp2_err.c
index 10b6ef81..ae2edb35 100644
--- a/lib/ngtcp2_err.c
+++ b/lib/ngtcp2_err.c
@@ -122,6 +122,7 @@ uint64_t ngtcp2_err_infer_quic_transport_error_code(int liberr) {
     return NGTCP2_FINAL_SIZE_ERROR;
   case NGTCP2_ERR_REQUIRED_TRANSPORT_PARAM:
   case NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM:
+  case NGTCP2_ERR_TRANSPORT_PARAM:
     return NGTCP2_TRANSPORT_PARAMETER_ERROR;
   case NGTCP2_ERR_INVALID_ARGUMENT:
     return NGTCP2_INTERNAL_ERROR;
-- 
GitLab