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