diff --git a/lib/ngtcp2_conn.c b/lib/ngtcp2_conn.c
index 73e9e6cf275e06cc4339cfe09621a4c01e9a31a6..a0447c1a8ad37609f1762069351e53809dae6ac1 100644
--- a/lib/ngtcp2_conn.c
+++ b/lib/ngtcp2_conn.c
@@ -1144,12 +1144,15 @@ static ssize_t conn_write_handshake_pkt(ngtcp2_conn *conn, uint8_t *dest,
   ngtcp2_ppe ppe;
   ngtcp2_pkt_hd hd;
   ngtcp2_frame_chain *frc = NULL, **pfrc, *frc_head = NULL, *frc_next;
-  ngtcp2_frame *fr, *ackfr, paddingfr;
+  ngtcp2_frame *fr, *ackfr, lfr;
   size_t nwrite;
   ssize_t spktlen;
   ngtcp2_crypto_ctx ctx;
   ngtcp2_rtb_entry *rtbent;
   ngtcp2_acktr_ack_entry *ack_ent = NULL;
+  size_t pclen;
+  int pr_encoded = 0;
+  ngtcp2_path_challenge_entry *pc;
 
   pfrc = &frc_head;
 
@@ -1189,11 +1192,50 @@ static ssize_t conn_write_handshake_pkt(ngtcp2_conn *conn, uint8_t *dest,
 
       ack_ent = ngtcp2_acktr_add_ack(&conn->acktr, hd.pkt_num, &ackfr->ack, ts,
                                      1, 0 /* ack_only */);
+    }
+
+    pclen = ngtcp2_ringbuf_len(&conn->rx_path_challenge);
+    while (ngtcp2_ringbuf_len(&conn->rx_path_challenge)) {
+      pc = ngtcp2_ringbuf_get(&conn->rx_path_challenge, 0);
+
+      lfr.type = NGTCP2_FRAME_PATH_RESPONSE;
+      ngtcp2_cpymem(lfr.path_challenge.data, pc->data,
+                    sizeof(lfr.path_challenge));
 
-      if (ngtcp2_ppe_left(&ppe) < NGTCP2_STREAM_OVERHEAD + 1) {
-        ++conn->last_tx_pkt_num;
-        return ngtcp2_ppe_final(&ppe, NULL);
+      rv = ngtcp2_ppe_encode_frame(&ppe, &lfr);
+      if (rv != 0) {
+        if (rv == NGTCP2_ERR_NOBUF) {
+          break;
+        }
+        return rv;
       }
+
+      ngtcp2_log_tx_fr(&conn->log, &hd, &lfr);
+
+      ngtcp2_ringbuf_pop_front(&conn->rx_path_challenge);
+    }
+
+    pr_encoded = (pclen != ngtcp2_ringbuf_len(&conn->rx_path_challenge));
+
+    if (ngtcp2_ppe_left(&ppe) < NGTCP2_STREAM_OVERHEAD + 1) {
+      spktlen = ngtcp2_ppe_final(&ppe, NULL);
+      if (spktlen < 0) {
+        return (int)spktlen;
+      }
+
+      if (pr_encoded) {
+        rv = ngtcp2_rtb_entry_new(&rtbent, &hd, NULL, ts, (size_t)spktlen,
+                                  NGTCP2_RTB_FLAG_UNPROTECTED, conn->mem);
+        if (rv != 0) {
+          return rv;
+        }
+
+        conn_on_pkt_sent(conn, rtbent);
+      }
+
+      ++conn->last_tx_pkt_num;
+
+      return spktlen;
     }
   }
 
@@ -1237,10 +1279,10 @@ static ssize_t conn_write_handshake_pkt(ngtcp2_conn *conn, uint8_t *dest,
   }
 
   if (type == NGTCP2_PKT_INITIAL) {
-    paddingfr.type = NGTCP2_FRAME_PADDING;
-    paddingfr.padding.len = ngtcp2_ppe_padding(&ppe);
-    if (paddingfr.padding.len > 0) {
-      ngtcp2_log_tx_fr(&conn->log, &hd, &paddingfr);
+    lfr.type = NGTCP2_FRAME_PADDING;
+    lfr.padding.len = ngtcp2_ppe_padding(&ppe);
+    if (lfr.padding.len > 0) {
+      ngtcp2_log_tx_fr(&conn->log, &hd, &lfr);
     }
   } else if (conn->state == NGTCP2_CS_CLIENT_TLS_HANDSHAKE_FAILED ||
              conn->state == NGTCP2_CS_SERVER_TLS_HANDSHAKE_FAILED) {
@@ -1273,7 +1315,7 @@ static ssize_t conn_write_handshake_pkt(ngtcp2_conn *conn, uint8_t *dest,
     goto fail;
   }
 
-  if (frc_head) {
+  if (frc_head || pr_encoded) {
     rv = ngtcp2_rtb_entry_new(&rtbent, &hd, frc_head, ts, (size_t)spktlen,
                               NGTCP2_RTB_FLAG_UNPROTECTED, conn->mem);
     if (rv != 0) {
diff --git a/lib/ngtcp2_ringbuf.c b/lib/ngtcp2_ringbuf.c
index d7ee2eb2af42f58a70b53cf6c184a07e1621c81b..a5754dba95eac8ea2fc77df16ddf751d1465d84b 100644
--- a/lib/ngtcp2_ringbuf.c
+++ b/lib/ngtcp2_ringbuf.c
@@ -61,6 +61,11 @@ void *ngtcp2_ringbuf_push_front(ngtcp2_ringbuf *rb) {
   return (void *)&rb->buf[rb->first * rb->size];
 }
 
+void ngtcp2_ringbuf_pop_front(ngtcp2_ringbuf *rb) {
+  rb->first = (rb->first + 1) & (rb->nmemb - 1);
+  --rb->len;
+}
+
 void ngtcp2_ringbuf_resize(ngtcp2_ringbuf *rb, size_t len) {
   assert(len <= rb->nmemb);
   rb->len = len;
diff --git a/lib/ngtcp2_ringbuf.h b/lib/ngtcp2_ringbuf.h
index 56c53d9f6308eb3b4be6e36c8f0816626fd34ddc..260c5a826632d944bd23185262cfccb0856f44e4 100644
--- a/lib/ngtcp2_ringbuf.h
+++ b/lib/ngtcp2_ringbuf.h
@@ -75,6 +75,11 @@ void ngtcp2_ringbuf_free(ngtcp2_ringbuf *rb);
    element is silently overwritten, and rb->len remains unchanged. */
 void *ngtcp2_ringbuf_push_front(ngtcp2_ringbuf *rb);
 
+/*
+ * ngtcp2_ringbuf_pop_front removes first element in |rb|.
+ */
+void ngtcp2_ringbuf_pop_front(ngtcp2_ringbuf *rb);
+
 /* ngtcp2_ringbuf_resize changes the number of elements stored.  This
    does not change the capacity of the underlying buffer. */
 void ngtcp2_ringbuf_resize(ngtcp2_ringbuf *rb, size_t len);
diff --git a/tests/main.c b/tests/main.c
index 31603ead72ca3a490b66911d469be48665d7f5b9..b172a8432be5e7e3abcf78f631d4b0250feb3b1f 100644
--- a/tests/main.c
+++ b/tests/main.c
@@ -135,6 +135,8 @@ int main() {
       !CU_add_test(pSuite, "idtr_open", test_ngtcp2_idtr_open) ||
       !CU_add_test(pSuite, "ringbuf_push_front",
                    test_ngtcp2_ringbuf_push_front) ||
+      !CU_add_test(pSuite, "ringbuf_pop_front",
+                   test_ngtcp2_ringbuf_pop_front) ||
       !CU_add_test(pSuite, "conn_stream_open_close",
                    test_ngtcp2_conn_stream_open_close) ||
       !CU_add_test(pSuite, "conn_stream_rx_flow_control",
diff --git a/tests/ngtcp2_ringbuf_test.c b/tests/ngtcp2_ringbuf_test.c
index d7f4153573bd865a7958192af3b4fa664838c1c4..6bebb7867316fbe35c274caf88a2e35e230b4b46 100644
--- a/tests/ngtcp2_ringbuf_test.c
+++ b/tests/ngtcp2_ringbuf_test.c
@@ -62,3 +62,30 @@ void test_ngtcp2_ringbuf_push_front(void) {
 
   ngtcp2_ringbuf_free(&rb);
 }
+
+void test_ngtcp2_ringbuf_pop_front(void) {
+  ngtcp2_ringbuf rb;
+  ngtcp2_mem *mem = ngtcp2_mem_default();
+  size_t i;
+
+  ngtcp2_ringbuf_init(&rb, 4, sizeof(ints), mem);
+
+  for (i = 0; i < 5; ++i) {
+    ints *p = ngtcp2_ringbuf_push_front(&rb);
+    p->a = (int32_t)i;
+  }
+
+  CU_ASSERT(4 == ngtcp2_ringbuf_len(&rb));
+
+  for (i = 4; i >= 1; --i) {
+    ints *p = ngtcp2_ringbuf_get(&rb, 0);
+
+    CU_ASSERT((int32_t)i == p->a);
+
+    ngtcp2_ringbuf_pop_front(&rb);
+  }
+
+  CU_ASSERT(0 == ngtcp2_ringbuf_len(&rb));
+
+  ngtcp2_ringbuf_free(&rb);
+}
diff --git a/tests/ngtcp2_ringbuf_test.h b/tests/ngtcp2_ringbuf_test.h
index 6c8a1aef5691e7c1df9dc0f65cf7b5487fdf18b5..8cae526e2b18ebb867c4e40f246aa1b30a588e7e 100644
--- a/tests/ngtcp2_ringbuf_test.h
+++ b/tests/ngtcp2_ringbuf_test.h
@@ -30,5 +30,6 @@
 #endif /* HAVE_CONFIG_H */
 
 void test_ngtcp2_ringbuf_push_front(void);
+void test_ngtcp2_ringbuf_pop_front(void);
 
 #endif /* NGTCP2_RINGBUF_TEST_H */