1 1.1 christos /* 2 1.1 christos * Copyright 2016-2025 The OpenSSL Project Authors. All Rights Reserved. 3 1.1 christos * 4 1.1 christos * Licensed under the Apache License 2.0 (the "License"). You may not use 5 1.1 christos * this file except in compliance with the License. You can obtain a copy 6 1.1 christos * in the file LICENSE in the source distribution or at 7 1.1 christos * https://www.openssl.org/source/license.html 8 1.1 christos */ 9 1.1 christos 10 1.1 christos #include <stdio.h> 11 1.1 christos #include <string.h> 12 1.1 christos 13 1.1 christos #include <openssl/dtls1.h> 14 1.1 christos #include <openssl/ssl.h> 15 1.1 christos #include <openssl/err.h> 16 1.1 christos 17 1.1 christos #include "helpers/ssltestlib.h" 18 1.1 christos #include "testutil.h" 19 1.1 christos 20 1.1 christos /* for SSL_READ_ETM() */ 21 1.1 christos #include "../ssl/ssl_local.h" 22 1.1 christos #include "internal/ssl_unwrap.h" 23 1.1 christos 24 1.1 christos static int debug = 0; 25 1.1 christos 26 1.1 christos static unsigned int clnt_psk_callback(SSL *ssl, const char *hint, 27 1.1.1.2 christos char *ident, unsigned int max_ident_len, 28 1.1.1.2 christos unsigned char *psk, 29 1.1.1.2 christos unsigned int max_psk_len) 30 1.1 christos { 31 1.1 christos BIO_snprintf(ident, max_ident_len, "psk"); 32 1.1 christos 33 1.1 christos if (max_psk_len > 20) 34 1.1 christos max_psk_len = 20; 35 1.1 christos memset(psk, 0x5a, max_psk_len); 36 1.1 christos 37 1.1 christos return max_psk_len; 38 1.1 christos } 39 1.1 christos 40 1.1 christos static unsigned int srvr_psk_callback(SSL *ssl, const char *identity, 41 1.1.1.2 christos unsigned char *psk, 42 1.1.1.2 christos unsigned int max_psk_len) 43 1.1 christos { 44 1.1 christos if (max_psk_len > 20) 45 1.1 christos max_psk_len = 20; 46 1.1 christos memset(psk, 0x5a, max_psk_len); 47 1.1 christos return max_psk_len; 48 1.1 christos } 49 1.1 christos 50 1.1 christos static int mtu_test(SSL_CTX *ctx, const char *cs, int no_etm) 51 1.1 christos { 52 1.1 christos SSL *srvr_ssl = NULL, *clnt_ssl = NULL; 53 1.1 christos BIO *sc_bio = NULL; 54 1.1 christos int i; 55 1.1 christos size_t s; 56 1.1 christos size_t mtus[30]; 57 1.1 christos unsigned char buf[600]; 58 1.1 christos int rv = 0; 59 1.1 christos SSL_CONNECTION *clnt_sc; 60 1.1 christos 61 1.1 christos memset(buf, 0x5a, sizeof(buf)); 62 1.1 christos 63 1.1 christos if (!TEST_true(create_ssl_objects(ctx, ctx, &srvr_ssl, &clnt_ssl, 64 1.1.1.2 christos NULL, NULL))) 65 1.1 christos goto end; 66 1.1 christos 67 1.1 christos if (no_etm) 68 1.1 christos SSL_set_options(srvr_ssl, SSL_OP_NO_ENCRYPT_THEN_MAC); 69 1.1 christos 70 1.1 christos if (!TEST_true(SSL_set_cipher_list(srvr_ssl, cs)) 71 1.1.1.2 christos || !TEST_true(SSL_set_cipher_list(clnt_ssl, cs)) 72 1.1.1.2 christos || !TEST_ptr(sc_bio = SSL_get_rbio(srvr_ssl)) 73 1.1.1.2 christos || !TEST_true(create_ssl_connection(clnt_ssl, srvr_ssl, 74 1.1.1.2 christos SSL_ERROR_NONE))) 75 1.1 christos goto end; 76 1.1 christos 77 1.1 christos if (debug) 78 1.1 christos TEST_info("Channel established"); 79 1.1 christos 80 1.1 christos /* For record MTU values between 500 and 539, call DTLS_get_data_mtu() 81 1.1 christos * to query the payload MTU which will fit. */ 82 1.1 christos for (i = 0; i < 30; i++) { 83 1.1 christos SSL_set_mtu(clnt_ssl, 500 + i); 84 1.1 christos mtus[i] = DTLS_get_data_mtu(clnt_ssl); 85 1.1 christos if (debug) 86 1.1 christos TEST_info("%s%s MTU for record mtu %d = %lu", 87 1.1.1.2 christos cs, no_etm ? "-noEtM" : "", 88 1.1.1.2 christos 500 + i, (unsigned long)mtus[i]); 89 1.1 christos if (!TEST_size_t_ne(mtus[i], 0)) { 90 1.1 christos TEST_info("Cipher %s MTU %d", cs, 500 + i); 91 1.1 christos goto end; 92 1.1 christos } 93 1.1 christos } 94 1.1 christos 95 1.1 christos /* Now get out of the way */ 96 1.1 christos SSL_set_mtu(clnt_ssl, 1000); 97 1.1 christos 98 1.1 christos /* 99 1.1 christos * Now for all values in the range of payload MTUs, send a payload of 100 1.1 christos * that size and see what actual record size we end up with. 101 1.1 christos */ 102 1.1 christos for (s = mtus[0]; s <= mtus[29]; s++) { 103 1.1 christos size_t reclen; 104 1.1 christos 105 1.1 christos if (!TEST_int_eq(SSL_write(clnt_ssl, buf, s), (int)s)) 106 1.1 christos goto end; 107 1.1 christos reclen = BIO_read(sc_bio, buf, sizeof(buf)); 108 1.1 christos if (debug) 109 1.1 christos TEST_info("record %zu for payload %zu", reclen, s); 110 1.1 christos 111 1.1 christos for (i = 0; i < 30; i++) { 112 1.1 christos /* DTLS_get_data_mtu() with record MTU 500+i returned mtus[i] ... */ 113 1.1 christos 114 1.1 christos if (!TEST_false(s <= mtus[i] && reclen > (size_t)(500 + i))) { 115 1.1 christos /* 116 1.1 christos * We sent a packet smaller than or equal to mtus[j] and 117 1.1 christos * that made a record *larger* than the record MTU 500+j! 118 1.1 christos */ 119 1.1 christos TEST_error("%s: s=%lu, mtus[i]=%lu, reclen=%lu, i=%d", 120 1.1.1.2 christos cs, (unsigned long)s, (unsigned long)mtus[i], 121 1.1.1.2 christos (unsigned long)reclen, 500 + i); 122 1.1 christos goto end; 123 1.1 christos } 124 1.1 christos if (!TEST_false(s > mtus[i] && reclen <= (size_t)(500 + i))) { 125 1.1 christos /* 126 1.1 christos * We sent a *larger* packet than mtus[i] and that *still* 127 1.1 christos * fits within the record MTU 500+i, so DTLS_get_data_mtu() 128 1.1 christos * was overly pessimistic. 129 1.1 christos */ 130 1.1 christos TEST_error("%s: s=%lu, mtus[i]=%lu, reclen=%lu, i=%d", 131 1.1.1.2 christos cs, (unsigned long)s, (unsigned long)mtus[i], 132 1.1.1.2 christos (unsigned long)reclen, 500 + i); 133 1.1 christos goto end; 134 1.1 christos } 135 1.1 christos } 136 1.1 christos } 137 1.1 christos if (!TEST_ptr(clnt_sc = SSL_CONNECTION_FROM_SSL_ONLY(clnt_ssl))) 138 1.1 christos goto end; 139 1.1 christos rv = 1; 140 1.1 christos if (SSL_READ_ETM(clnt_sc)) 141 1.1 christos rv = 2; 142 1.1.1.2 christos end: 143 1.1 christos SSL_free(clnt_ssl); 144 1.1 christos SSL_free(srvr_ssl); 145 1.1 christos return rv; 146 1.1 christos } 147 1.1 christos 148 1.1 christos static int run_mtu_tests(void) 149 1.1 christos { 150 1.1 christos SSL_CTX *ctx = NULL; 151 1.1 christos STACK_OF(SSL_CIPHER) *ciphers; 152 1.1 christos int i, ret = 0; 153 1.1 christos 154 1.1 christos if (!TEST_ptr(ctx = SSL_CTX_new(DTLS_method()))) 155 1.1 christos goto end; 156 1.1 christos 157 1.1 christos SSL_CTX_set_psk_server_callback(ctx, srvr_psk_callback); 158 1.1 christos SSL_CTX_set_psk_client_callback(ctx, clnt_psk_callback); 159 1.1 christos SSL_CTX_set_security_level(ctx, 0); 160 1.1 christos 161 1.1 christos /* 162 1.1 christos * We only care about iterating over each enc/mac; we don't want to 163 1.1 christos * repeat the test for each auth/kx variant. So keep life simple and 164 1.1 christos * only do (non-DH) PSK. 165 1.1 christos */ 166 1.1 christos if (!TEST_true(SSL_CTX_set_cipher_list(ctx, "PSK"))) 167 1.1 christos goto end; 168 1.1 christos 169 1.1 christos ciphers = SSL_CTX_get_ciphers(ctx); 170 1.1 christos for (i = 0; i < sk_SSL_CIPHER_num(ciphers); i++) { 171 1.1 christos const SSL_CIPHER *cipher = sk_SSL_CIPHER_value(ciphers, i); 172 1.1 christos const char *cipher_name = SSL_CIPHER_get_name(cipher); 173 1.1 christos 174 1.1 christos /* As noted above, only one test for each enc/mac variant. */ 175 1.1 christos if (!HAS_PREFIX(cipher_name, "PSK-")) 176 1.1 christos continue; 177 1.1 christos 178 1.1 christos if (!TEST_int_gt(ret = mtu_test(ctx, cipher_name, 0), 0)) 179 1.1 christos break; 180 1.1 christos TEST_info("%s OK", cipher_name); 181 1.1 christos if (ret == 1) 182 1.1 christos continue; 183 1.1 christos 184 1.1 christos /* mtu_test() returns 2 if it used Encrypt-then-MAC */ 185 1.1 christos if (!TEST_int_gt(ret = mtu_test(ctx, cipher_name, 1), 0)) 186 1.1 christos break; 187 1.1 christos TEST_info("%s without EtM OK", cipher_name); 188 1.1 christos } 189 1.1 christos 190 1.1.1.2 christos end: 191 1.1 christos SSL_CTX_free(ctx); 192 1.1 christos return ret; 193 1.1 christos } 194 1.1 christos 195 1.1 christos static int test_server_mtu_larger_than_max_fragment_length(void) 196 1.1 christos { 197 1.1 christos SSL_CTX *ctx = NULL; 198 1.1 christos SSL *srvr_ssl = NULL, *clnt_ssl = NULL; 199 1.1 christos int rv = 0; 200 1.1 christos 201 1.1 christos if (!TEST_ptr(ctx = SSL_CTX_new(DTLS_method()))) 202 1.1 christos goto end; 203 1.1 christos 204 1.1 christos SSL_CTX_set_psk_server_callback(ctx, srvr_psk_callback); 205 1.1 christos SSL_CTX_set_psk_client_callback(ctx, clnt_psk_callback); 206 1.1 christos 207 1.1 christos #ifndef OPENSSL_NO_DH 208 1.1 christos if (!TEST_true(SSL_CTX_set_dh_auto(ctx, 1))) 209 1.1 christos goto end; 210 1.1 christos #endif 211 1.1 christos 212 1.1 christos if (!TEST_true(create_ssl_objects(ctx, ctx, &srvr_ssl, &clnt_ssl, 213 1.1.1.2 christos NULL, NULL))) 214 1.1 christos goto end; 215 1.1 christos 216 1.1 christos SSL_set_options(srvr_ssl, SSL_OP_NO_QUERY_MTU); 217 1.1 christos if (!TEST_true(DTLS_set_link_mtu(srvr_ssl, 1500))) 218 1.1 christos goto end; 219 1.1 christos 220 1.1 christos SSL_set_tlsext_max_fragment_length(clnt_ssl, 221 1.1.1.2 christos TLSEXT_max_fragment_length_512); 222 1.1 christos 223 1.1 christos if (!TEST_true(create_ssl_connection(srvr_ssl, clnt_ssl, 224 1.1.1.2 christos SSL_ERROR_NONE))) 225 1.1 christos goto end; 226 1.1 christos 227 1.1 christos rv = 1; 228 1.1 christos 229 1.1.1.2 christos end: 230 1.1 christos SSL_free(clnt_ssl); 231 1.1 christos SSL_free(srvr_ssl); 232 1.1 christos SSL_CTX_free(ctx); 233 1.1 christos return rv; 234 1.1 christos } 235 1.1 christos 236 1.1 christos int setup_tests(void) 237 1.1 christos { 238 1.1 christos ADD_TEST(run_mtu_tests); 239 1.1 christos ADD_TEST(test_server_mtu_larger_than_max_fragment_length); 240 1.1 christos return 1; 241 1.1 christos } 242 1.1 christos 243 1.1 christos void cleanup_tests(void) 244 1.1 christos { 245 1.1 christos bio_s_mempacket_test_free(); 246 1.1 christos } 247