]> git.ipfire.org Git - thirdparty/openssl.git/commitdiff
Implement the QUIC Fault injector support for plaintext packets
authorMatt Caswell <matt@openssl.org>
Wed, 30 Nov 2022 16:41:31 +0000 (16:41 +0000)
committerHugo Landau <hlandau@openssl.org>
Wed, 22 Feb 2023 05:33:24 +0000 (05:33 +0000)
Provider helper functions to listen for plaintext packets being sent, as
well as the ability to change the contents of those packets as well as
resizing them.

Reviewed-by: Hugo Landau <hlandau@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/20030)

test/helpers/quictestlib.c
test/helpers/quictestlib.h

index 1c4fa8d9b33846db5d26e3913b2c9f83f8457701..3886014c3c5d0ee848e2b698558d70cd419aac00 100644 (file)
@@ -7,11 +7,26 @@
  * https://www.openssl.org/source/license.html
  */
 
+#include <assert.h>
 #include "quictestlib.h"
 #include "../testutil.h"
+#include "internal/quic_wire_pkt.h"
+#include "internal/quic_record_tx.h"
+
+#define GROWTH_ALLOWANCE 1024
 
 struct ossl_quic_fault {
     QUIC_TSERVER *qtserv;
+
+    /* Plain packet mutations */
+    /* Header for the plaintext packet */
+    QUIC_PKT_HDR pplainhdr;
+    /* iovec for the plaintext packet data buffer */
+    OSSL_QTX_IOVEC pplainio;
+    /* Allocted size of the plaintext packet data buffer */
+    size_t pplainbuf_alloc;
+    ossl_quic_fault_on_packet_plain_cb pplaincb;
+    void *pplaincbarg;
 };
 
 int qtest_create_quic_objects(SSL_CTX *clientctx, char *certfile, char *keyfile,
@@ -147,3 +162,116 @@ int qtest_create_quic_connection(QUIC_TSERVER *qtserv, SSL *clientssl)
  err:
     return ret;
 }
+
+void ossl_quic_fault_free(OSSL_QUIC_FAULT *fault)
+{
+    if (fault == NULL)
+        return;
+
+    OPENSSL_free(fault);
+}
+
+static int packet_plain_mutate(const QUIC_PKT_HDR *hdrin,
+                               const OSSL_QTX_IOVEC *iovecin, size_t numin,
+                               QUIC_PKT_HDR **hdrout,
+                               const OSSL_QTX_IOVEC **iovecout,
+                               size_t *numout,
+                               void *arg)
+{
+    OSSL_QUIC_FAULT *fault = arg;
+    size_t i, bufsz = 0;
+    unsigned char *cur;
+
+    /* Coalesce our data into a single buffer */
+
+    /* First calculate required buffer size */
+    for (i = 0; i < numin; i++)
+        bufsz += iovecin[i].buf_len;
+
+    fault->pplainio.buf_len = bufsz;
+
+    /* Add an allowance for possible growth */
+    bufsz += GROWTH_ALLOWANCE;
+
+    fault->pplainio.buf = cur = OPENSSL_malloc(bufsz);
+    if (cur == NULL) {
+        fault->pplainio.buf_len = 0;
+        return 0;
+    }
+
+    fault->pplainbuf_alloc = bufsz;
+
+    /* Copy in the data from the input buffers */
+    for (i = 0; i < numin; i++) {
+        memcpy(cur, iovecin[i].buf, iovecin[i].buf_len);
+        cur += iovecin[i].buf_len;
+    }
+
+    fault->pplainhdr = *hdrin;
+
+    /* Cast below is safe because we allocated the buffer */
+    if (fault->pplaincb != NULL
+            && !fault->pplaincb(fault, &fault->pplainhdr,
+                                (unsigned char *)fault->pplainio.buf,
+                                fault->pplainio.buf_len, fault->pplaincbarg))
+        return 0;
+
+    *hdrout = &fault->pplainhdr;
+    *iovecout = &fault->pplainio;
+    *numout = 1;
+
+    return 1;
+}
+
+static void packet_plain_finish(void *arg)
+{
+    OSSL_QUIC_FAULT *fault = arg;
+
+    /* Cast below is safe because we allocated the buffer */
+    OPENSSL_free((unsigned char *)fault->pplainio.buf);
+    fault->pplainio.buf_len = 0;
+    fault->pplainbuf_alloc = 0;
+}
+
+int ossl_quic_fault_set_packet_plain_listener(OSSL_QUIC_FAULT *fault,
+                                              ossl_quic_fault_on_packet_plain_cb pplaincb,
+                                              void *pplaincbarg)
+{
+    fault->pplaincb = pplaincb;
+    fault->pplaincbarg = pplaincbarg;
+
+    return ossl_quic_tserver_set_mutator(fault->qtserv, packet_plain_mutate,
+                                         packet_plain_finish, fault);
+}
+
+/* To be called from a packet_plain_listener callback */
+int ossl_quic_fault_resize_plain_packet(OSSL_QUIC_FAULT *fault, size_t newlen)
+{
+    unsigned char *buf;
+    size_t oldlen = fault->pplainio.buf_len;
+
+    /*
+     * Alloc'd size should always be non-zero, so if this fails we've been
+     * incorrectly called
+     */
+    if (fault->pplainbuf_alloc == 0)
+        return 0;
+
+    if (newlen > fault->pplainbuf_alloc) {
+        /* This exceeds our growth allowance. Fail */
+        return 0;
+    }
+
+    /* Cast below is safe because we allocated the buffer */
+    buf = (unsigned char *)fault->pplainio.buf;
+
+    if (newlen > oldlen) {
+        /* Extend packet with 0 bytes */
+        memset(buf + oldlen, 0, newlen - oldlen);
+    } /* else we're truncating or staying the same */
+
+    fault->pplainio.buf_len = newlen;
+    fault->pplainhdr.len = newlen;
+
+    return 1;
+}
index 3afea60e558999a8e23638e06ec274e5090f79a3..24295e50b834ac01409ba3e944f4f634fe2d0840 100644 (file)
@@ -16,3 +16,18 @@ int qtest_create_quic_objects(SSL_CTX *clientctx, char *certfile, char *keyfile,
                               QUIC_TSERVER **qtserv, SSL **cssl,
                               OSSL_QUIC_FAULT **fault);
 int qtest_create_quic_connection(QUIC_TSERVER *qtserv, SSL *clientssl);
+
+void ossl_quic_fault_free(OSSL_QUIC_FAULT *fault);
+
+typedef int (*ossl_quic_fault_on_packet_plain_cb)(OSSL_QUIC_FAULT *fault,
+                                                  QUIC_PKT_HDR *hdr,
+                                                  unsigned char *buf,
+                                                  size_t len,
+                                                  void *cbarg);
+
+int ossl_quic_fault_set_packet_plain_listener(OSSL_QUIC_FAULT *fault,
+                                              ossl_quic_fault_on_packet_plain_cb pplaincb,
+                                              void *pplaincbarg);
+
+/* To be called from a packet_plain_listener callback */
+int ossl_quic_fault_resize_plain_packet(OSSL_QUIC_FAULT *fault, size_t newlen);