1 /* 2 * Copyright 2016-2020 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) * sizeof(cipher_list[0])); 158 if (!TEST_ptr(cipher_list)) 159 goto err; 160 161 for (j = 0, i = 0; i < sk_SSL_CIPHER_num(sk_ciphers); i++) { 162 const SSL_CIPHER *cipher = sk_SSL_CIPHER_value(sk_ciphers, i); 163 164 if (SSL_CIPHER_get_auth_nid(cipher) == NID_auth_rsa) 165 cipher_list[j++] = SSL_CIPHER_get_name(cipher); 166 } 167 if (TEST_int_ne(j, 0)) 168 numciphers = j; 169 170 err: 171 sk_SSL_CIPHER_free(sk_ciphers); 172 SSL_free(ssl); 173 SSL_CTX_free(ctx); 174 175 return numciphers; 176 } 177 178 static char *cert = NULL; 179 static char *privkey = NULL; 180 181 static int test_ssl_corrupt(int testidx) 182 { 183 static unsigned char junk[16000] = { 0 }; 184 SSL_CTX *sctx = NULL, *cctx = NULL; 185 SSL *server = NULL, *client = NULL; 186 BIO *c_to_s_fbio; 187 int testresult = 0; 188 STACK_OF(SSL_CIPHER) *ciphers; 189 const SSL_CIPHER *currcipher; 190 int err; 191 192 docorrupt = 0; 193 194 TEST_info("Starting #%d, %s", testidx, cipher_list[testidx]); 195 196 if (!TEST_true(create_ssl_ctx_pair(NULL, TLS_server_method(), 197 TLS_client_method(), 198 TLS1_VERSION, 0, 199 &sctx, &cctx, cert, privkey))) 200 return 0; 201 202 if (!TEST_true(SSL_CTX_set_dh_auto(sctx, 1)) 203 || !TEST_true(SSL_CTX_set_cipher_list(cctx, cipher_list[testidx])) 204 || !TEST_true(SSL_CTX_set_ciphersuites(cctx, "")) 205 || !TEST_ptr(ciphers = SSL_CTX_get_ciphers(cctx)) 206 || !TEST_int_eq(sk_SSL_CIPHER_num(ciphers), 1) 207 || !TEST_ptr(currcipher = sk_SSL_CIPHER_value(ciphers, 0))) 208 goto end; 209 210 /* 211 * No ciphers we are using are TLSv1.3 compatible so we should not attempt 212 * to negotiate TLSv1.3 213 */ 214 if (!TEST_true(SSL_CTX_set_max_proto_version(cctx, TLS1_2_VERSION))) 215 goto end; 216 217 if (!TEST_ptr(c_to_s_fbio = BIO_new(bio_f_tls_corrupt_filter()))) 218 goto end; 219 220 /* BIO is freed by create_ssl_connection on error */ 221 if (!TEST_true(create_ssl_objects(sctx, cctx, &server, &client, NULL, 222 c_to_s_fbio))) 223 goto end; 224 225 if (!TEST_true(create_ssl_connection(server, client, SSL_ERROR_NONE))) 226 goto end; 227 228 docorrupt = 1; 229 230 if (!TEST_int_ge(SSL_write(client, junk, sizeof(junk)), 0)) 231 goto end; 232 233 if (!TEST_int_lt(SSL_read(server, junk, sizeof(junk)), 0)) 234 goto end; 235 236 do { 237 err = ERR_get_error(); 238 239 if (err == 0) { 240 TEST_error("Decryption failed or bad record MAC not seen"); 241 goto end; 242 } 243 } while (ERR_GET_REASON(err) != SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC); 244 245 testresult = 1; 246 end: 247 SSL_free(server); 248 SSL_free(client); 249 SSL_CTX_free(sctx); 250 SSL_CTX_free(cctx); 251 return testresult; 252 } 253 254 OPT_TEST_DECLARE_USAGE("certfile privkeyfile\n") 255 256 int setup_tests(void) 257 { 258 int n; 259 260 if (!test_skip_common_options()) { 261 TEST_error("Error parsing test options\n"); 262 return 0; 263 } 264 265 if (!TEST_ptr(cert = test_get_argument(0)) 266 || !TEST_ptr(privkey = test_get_argument(1))) 267 return 0; 268 269 n = setup_cipher_list(); 270 if (n > 0) 271 ADD_ALL_TESTS(test_ssl_corrupt, n); 272 return 1; 273 } 274 275 void cleanup_tests(void) 276 { 277 bio_f_tls_corrupt_filter_free(); 278 OPENSSL_free(cipher_list); 279 } 280