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