1 /* 2 * Copyright 2016-2022 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 "helpers/ssltestlib.h" 12 #include "testutil.h" 13 14 static int docorrupt = 0; 15 16 static void copy_flags(BIO *bio) 17 { 18 int flags; 19 BIO *next = BIO_next(bio); 20 21 flags = BIO_test_flags(next, BIO_FLAGS_SHOULD_RETRY | BIO_FLAGS_RWS); 22 BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY | BIO_FLAGS_RWS); 23 BIO_set_flags(bio, flags); 24 } 25 26 static int tls_corrupt_read(BIO *bio, char *out, int outl) 27 { 28 int ret; 29 BIO *next = BIO_next(bio); 30 31 ret = BIO_read(next, out, outl); 32 copy_flags(bio); 33 34 return ret; 35 } 36 37 static int tls_corrupt_write(BIO *bio, const char *in, int inl) 38 { 39 int ret; 40 BIO *next = BIO_next(bio); 41 char *copy; 42 43 if (docorrupt) { 44 if (!TEST_ptr(copy = OPENSSL_memdup(in, inl))) 45 return 0; 46 /* corrupt last bit of application data */ 47 copy[inl-1] ^= 1; 48 ret = BIO_write(next, copy, inl); 49 OPENSSL_free(copy); 50 } else { 51 ret = BIO_write(next, in, inl); 52 } 53 copy_flags(bio); 54 55 return ret; 56 } 57 58 static long tls_corrupt_ctrl(BIO *bio, int cmd, long num, void *ptr) 59 { 60 long ret; 61 BIO *next = BIO_next(bio); 62 63 if (next == NULL) 64 return 0; 65 66 switch (cmd) { 67 case BIO_CTRL_DUP: 68 ret = 0L; 69 break; 70 default: 71 ret = BIO_ctrl(next, cmd, num, ptr); 72 break; 73 } 74 return ret; 75 } 76 77 static int tls_corrupt_gets(BIO *bio, char *buf, int size) 78 { 79 /* We don't support this - not needed anyway */ 80 return -1; 81 } 82 83 static int tls_corrupt_puts(BIO *bio, const char *str) 84 { 85 /* We don't support this - not needed anyway */ 86 return -1; 87 } 88 89 static int tls_corrupt_new(BIO *bio) 90 { 91 BIO_set_init(bio, 1); 92 93 return 1; 94 } 95 96 static int tls_corrupt_free(BIO *bio) 97 { 98 BIO_set_init(bio, 0); 99 100 return 1; 101 } 102 103 #define BIO_TYPE_CUSTOM_FILTER (0x80 | BIO_TYPE_FILTER) 104 105 static BIO_METHOD *method_tls_corrupt = NULL; 106 107 /* Note: Not thread safe! */ 108 static const BIO_METHOD *bio_f_tls_corrupt_filter(void) 109 { 110 if (method_tls_corrupt == NULL) { 111 method_tls_corrupt = BIO_meth_new(BIO_TYPE_CUSTOM_FILTER, 112 "TLS corrupt filter"); 113 if ( method_tls_corrupt == NULL 114 || !BIO_meth_set_write(method_tls_corrupt, tls_corrupt_write) 115 || !BIO_meth_set_read(method_tls_corrupt, tls_corrupt_read) 116 || !BIO_meth_set_puts(method_tls_corrupt, tls_corrupt_puts) 117 || !BIO_meth_set_gets(method_tls_corrupt, tls_corrupt_gets) 118 || !BIO_meth_set_ctrl(method_tls_corrupt, tls_corrupt_ctrl) 119 || !BIO_meth_set_create(method_tls_corrupt, tls_corrupt_new) 120 || !BIO_meth_set_destroy(method_tls_corrupt, tls_corrupt_free)) 121 return NULL; 122 } 123 return method_tls_corrupt; 124 } 125 126 static void bio_f_tls_corrupt_filter_free(void) 127 { 128 BIO_meth_free(method_tls_corrupt); 129 } 130 131 /* 132 * The test is supposed to be executed with RSA key, customarily 133 * with apps/server.pem used even in other tests. For this reason 134 * |cipher_list| is initialized with RSA ciphers' names. This 135 * naturally means that if test is to be re-purposed for other 136 * type of key, then NID_auth_* filter below would need adjustment. 137 */ 138 static const char **cipher_list = NULL; 139 140 static int setup_cipher_list(void) 141 { 142 SSL_CTX *ctx = NULL; 143 SSL *ssl = NULL; 144 STACK_OF(SSL_CIPHER) *sk_ciphers = NULL; 145 int i, j, numciphers = 0; 146 147 if (!TEST_ptr(ctx = SSL_CTX_new(TLS_server_method())) 148 || !TEST_ptr(ssl = SSL_new(ctx)) 149 || !TEST_ptr(sk_ciphers = SSL_get1_supported_ciphers(ssl))) 150 goto err; 151 152 /* 153 * The |cipher_list| will be filled only with names of RSA ciphers, 154 * so that some of the allocated space will be wasted, but the loss 155 * is deemed acceptable... 156 */ 157 cipher_list = OPENSSL_malloc(sk_SSL_CIPHER_num(sk_ciphers) * 158 sizeof(cipher_list[0])); 159 if (!TEST_ptr(cipher_list)) 160 goto err; 161 162 for (j = 0, i = 0; i < sk_SSL_CIPHER_num(sk_ciphers); i++) { 163 const SSL_CIPHER *cipher = sk_SSL_CIPHER_value(sk_ciphers, i); 164 165 if (SSL_CIPHER_get_auth_nid(cipher) == NID_auth_rsa) 166 cipher_list[j++] = SSL_CIPHER_get_name(cipher); 167 } 168 if (TEST_int_ne(j, 0)) 169 numciphers = j; 170 171 err: 172 sk_SSL_CIPHER_free(sk_ciphers); 173 SSL_free(ssl); 174 SSL_CTX_free(ctx); 175 176 return numciphers; 177 } 178 179 static char *cert = NULL; 180 static char *privkey = NULL; 181 182 static int test_ssl_corrupt(int testidx) 183 { 184 static unsigned char junk[16000] = { 0 }; 185 SSL_CTX *sctx = NULL, *cctx = NULL; 186 SSL *server = NULL, *client = NULL; 187 BIO *c_to_s_fbio; 188 int testresult = 0; 189 STACK_OF(SSL_CIPHER) *ciphers; 190 const SSL_CIPHER *currcipher; 191 int err; 192 193 docorrupt = 0; 194 195 TEST_info("Starting #%d, %s", testidx, cipher_list[testidx]); 196 197 if (!TEST_true(create_ssl_ctx_pair(NULL, TLS_server_method(), 198 TLS_client_method(), 199 TLS1_VERSION, 0, 200 &sctx, &cctx, cert, privkey))) 201 return 0; 202 203 if (!TEST_true(SSL_CTX_set_dh_auto(sctx, 1)) 204 || !TEST_true(SSL_CTX_set_cipher_list(cctx, cipher_list[testidx])) 205 || !TEST_true(SSL_CTX_set_ciphersuites(cctx, "")) 206 || !TEST_ptr(ciphers = SSL_CTX_get_ciphers(cctx)) 207 || !TEST_int_eq(sk_SSL_CIPHER_num(ciphers), 1) 208 || !TEST_ptr(currcipher = sk_SSL_CIPHER_value(ciphers, 0))) 209 goto end; 210 211 /* 212 * No ciphers we are using are TLSv1.3 compatible so we should not attempt 213 * to negotiate TLSv1.3 214 */ 215 if (!TEST_true(SSL_CTX_set_max_proto_version(cctx, TLS1_2_VERSION))) 216 goto end; 217 218 if (!TEST_ptr(c_to_s_fbio = BIO_new(bio_f_tls_corrupt_filter()))) 219 goto end; 220 221 /* BIO is freed by create_ssl_connection on error */ 222 if (!TEST_true(create_ssl_objects(sctx, cctx, &server, &client, NULL, 223 c_to_s_fbio))) 224 goto end; 225 226 if (!TEST_true(create_ssl_connection(server, client, SSL_ERROR_NONE))) 227 goto end; 228 229 docorrupt = 1; 230 231 if (!TEST_int_ge(SSL_write(client, junk, sizeof(junk)), 0)) 232 goto end; 233 234 if (!TEST_int_lt(SSL_read(server, junk, sizeof(junk)), 0)) 235 goto end; 236 237 do { 238 err = ERR_get_error(); 239 240 if (err == 0) { 241 TEST_error("Decryption failed or bad record MAC not seen"); 242 goto end; 243 } 244 } while (ERR_GET_REASON(err) != SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC); 245 246 testresult = 1; 247 end: 248 SSL_free(server); 249 SSL_free(client); 250 SSL_CTX_free(sctx); 251 SSL_CTX_free(cctx); 252 return testresult; 253 } 254 255 OPT_TEST_DECLARE_USAGE("certfile privkeyfile\n") 256 257 int setup_tests(void) 258 { 259 int n; 260 261 if (!test_skip_common_options()) { 262 TEST_error("Error parsing test options\n"); 263 return 0; 264 } 265 266 if (!TEST_ptr(cert = test_get_argument(0)) 267 || !TEST_ptr(privkey = test_get_argument(1))) 268 return 0; 269 270 n = setup_cipher_list(); 271 if (n > 0) 272 ADD_ALL_TESTS(test_ssl_corrupt, n); 273 return 1; 274 } 275 276 void cleanup_tests(void) 277 { 278 bio_f_tls_corrupt_filter_free(); 279 OPENSSL_free(cipher_list); 280 } 281