1 /* 2 * Copyright 2023 The OpenSSL Project Authors. All Rights Reserved. 3 * 4 * Licensed under the Apache License 2.0 (the "License"). You may not use 5 * this file except in compliance with the License. You can obtain a copy 6 * in the file LICENSE in the source distribution or at 7 * https://www.openssl.org/source/license.html 8 */ 9 10 #include <string.h> 11 #include <openssl/ssl.h> 12 #include "helpers/quictestlib.h" 13 #include "internal/quic_error.h" 14 #include "testutil.h" 15 16 static char *cert = NULL; 17 static char *privkey = NULL; 18 19 /* 20 * Inject NEW_CONNECTION_ID frame 21 */ 22 static size_t ncid_injected; 23 static int add_ncid_frame_cb(QTEST_FAULT *fault, QUIC_PKT_HDR *hdr, 24 unsigned char *buf, size_t len, void *cbarg) 25 { 26 /* 27 * We inject NEW_CONNECTION_ID frame to trigger change of the DCID. 28 * The connection id length must be 8, otherwise the tserver won't be 29 * able to receive packets with this new id. 30 */ 31 static unsigned char new_conn_id_frame[] = { 32 0x18, /* Type */ 33 0x01, /* Sequence Number */ 34 0x01, /* Retire Prior To */ 35 0x08, /* Connection ID Length */ 36 0x33, 0x44, 0x55, 0x66, 0xde, 0xad, 0xbe, 0xef, /* Connection ID */ 37 0xab, 0xcd, 0xef, 0x01, 0x12, 0x32, 0x23, 0x45, /* Stateless Reset Token */ 38 0x56, 0x06, 0x08, 0x89, 0xa1, 0xb2, 0xc3, 0xd4 39 }; 40 41 /* We only ever add the unknown frame to one packet */ 42 if (ncid_injected++) 43 return 1; 44 45 return qtest_fault_prepend_frame(fault, new_conn_id_frame, 46 sizeof(new_conn_id_frame)); 47 } 48 49 static int test_ncid_frame(int fail) 50 { 51 int testresult = 0; 52 SSL_CTX *cctx = SSL_CTX_new(OSSL_QUIC_client_method()); 53 QUIC_TSERVER *qtserv = NULL; 54 SSL *cssl = NULL; 55 char *msg = "Hello World!"; 56 size_t msglen = strlen(msg); 57 unsigned char buf[80]; 58 size_t byteswritten; 59 size_t bytesread; 60 QTEST_FAULT *fault = NULL; 61 static const QUIC_CONN_ID conn_id = { 62 0x08, 63 {0x33, 0x44, 0x55, 0x66, 0xde, 0xad, 0xbe, 0xef} 64 }; 65 66 ncid_injected = 0; 67 if (!TEST_ptr(cctx)) 68 goto err; 69 70 if (!TEST_true(qtest_create_quic_objects(NULL, cctx, NULL, cert, privkey, 0, 71 &qtserv, &cssl, &fault, NULL))) 72 goto err; 73 74 if (!TEST_true(qtest_create_quic_connection(qtserv, cssl))) 75 goto err; 76 77 if (!TEST_int_eq(SSL_write(cssl, msg, msglen), msglen)) 78 goto err; 79 80 ossl_quic_tserver_tick(qtserv); 81 if (!TEST_true(ossl_quic_tserver_read(qtserv, 0, buf, sizeof(buf), 82 &bytesread))) 83 goto err; 84 85 /* 86 * We assume the entire message is read from the server in one go. In 87 * theory this could get fragmented but its a small message so we assume 88 * not. 89 */ 90 if (!TEST_mem_eq(msg, msglen, buf, bytesread)) 91 goto err; 92 93 /* 94 * Write a message from the server to the client and add 95 * a NEW_CONNECTION_ID frame. 96 */ 97 if (!TEST_true(qtest_fault_set_packet_plain_listener(fault, 98 add_ncid_frame_cb, 99 NULL))) 100 goto err; 101 if (!fail && !TEST_true(ossl_quic_tserver_set_new_local_cid(qtserv, &conn_id))) 102 goto err; 103 if (!TEST_true(ossl_quic_tserver_write(qtserv, 0, 104 (unsigned char *)msg, msglen, 105 &byteswritten))) 106 goto err; 107 108 if (!TEST_true(ncid_injected)) 109 goto err; 110 111 if (!TEST_size_t_eq(msglen, byteswritten)) 112 goto err; 113 114 ossl_quic_tserver_tick(qtserv); 115 if (!TEST_true(SSL_handle_events(cssl))) 116 goto err; 117 118 if (!TEST_int_eq(SSL_read(cssl, buf, sizeof(buf)), msglen)) 119 goto err; 120 121 if (!TEST_mem_eq(msg, msglen, buf, bytesread)) 122 goto err; 123 124 if (!TEST_int_eq(SSL_write(cssl, msg, msglen), msglen)) 125 goto err; 126 127 ossl_quic_tserver_tick(qtserv); 128 if (!TEST_true(ossl_quic_tserver_read(qtserv, 0, buf, sizeof(buf), 129 &bytesread))) 130 goto err; 131 132 if (fail) { 133 if (!TEST_size_t_eq(bytesread, 0)) 134 goto err; 135 } else { 136 if (!TEST_mem_eq(msg, msglen, buf, bytesread)) 137 goto err; 138 } 139 140 testresult = 1; 141 err: 142 qtest_fault_free(fault); 143 SSL_free(cssl); 144 ossl_quic_tserver_free(qtserv); 145 SSL_CTX_free(cctx); 146 return testresult; 147 } 148 149 OPT_TEST_DECLARE_USAGE("certsdir\n") 150 151 int setup_tests(void) 152 { 153 char *certsdir = NULL; 154 155 if (!test_skip_common_options()) { 156 TEST_error("Error parsing test options\n"); 157 return 0; 158 } 159 160 if (!TEST_ptr(certsdir = test_get_argument(0))) 161 return 0; 162 163 cert = test_mk_file_path(certsdir, "servercert.pem"); 164 if (cert == NULL) 165 goto err; 166 167 privkey = test_mk_file_path(certsdir, "serverkey.pem"); 168 if (privkey == NULL) 169 goto err; 170 171 ADD_ALL_TESTS(test_ncid_frame, 2); 172 173 return 1; 174 175 err: 176 OPENSSL_free(cert); 177 OPENSSL_free(privkey); 178 return 0; 179 } 180 181 void cleanup_tests(void) 182 { 183 OPENSSL_free(cert); 184 OPENSSL_free(privkey); 185 } 186