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