doc: update FIPS provider version information
[openssl.git] / test / quic_client_test.c
1 /*
2  * Copyright 2023 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 #include <stdio.h>
10 #include <openssl/ssl.h>
11 #include <openssl/quic.h>
12 #include <openssl/bio.h>
13 #include "internal/common.h"
14 #include "internal/sockets.h"
15 #include "internal/time.h"
16 #include "testutil.h"
17
18 static const char msg1[] = "GET LICENSE.txt\r\n";
19 static char msg2[16000];
20
21 static int is_want(SSL *s, int ret)
22 {
23     int ec = SSL_get_error(s, ret);
24
25     return ec == SSL_ERROR_WANT_READ || ec == SSL_ERROR_WANT_WRITE;
26 }
27
28 static int test_quic_client(void)
29 {
30     int testresult = 0, ret;
31     int c_fd = INVALID_SOCKET;
32     BIO *c_net_bio = NULL, *c_net_bio_own = NULL;
33     BIO_ADDR *s_addr_ = NULL;
34     struct in_addr ina = {0};
35     SSL_CTX *c_ctx = NULL;
36     SSL *c_ssl = NULL;
37     short port = 4433;
38     int c_connected = 0, c_write_done = 0, c_shutdown = 0;
39     size_t l = 0, c_total_read = 0;
40     OSSL_TIME start_time;
41     unsigned char alpn[] = { 8, 'h', 't', 't', 'p', '/', '0', '.', '9' };
42
43     ina.s_addr = htonl(0x7f000001UL);
44
45     /* Setup test client. */
46     c_fd = BIO_socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP, 0);
47     if (!TEST_int_ne(c_fd, INVALID_SOCKET))
48         goto err;
49
50     if (!TEST_true(BIO_socket_nbio(c_fd, 1)))
51         goto err;
52
53     if (!TEST_ptr(s_addr_ = BIO_ADDR_new()))
54         goto err;
55
56     if (!TEST_true(BIO_ADDR_rawmake(s_addr_, AF_INET, &ina, sizeof(ina),
57                                     htons(port))))
58         goto err;
59
60     if (!TEST_ptr(c_net_bio = c_net_bio_own = BIO_new_dgram(c_fd, 0)))
61         goto err;
62
63     if (!BIO_dgram_set_peer(c_net_bio, s_addr_))
64         goto err;
65
66     if (!TEST_ptr(c_ctx = SSL_CTX_new(OSSL_QUIC_client_method())))
67         goto err;
68
69     if (!TEST_ptr(c_ssl = SSL_new(c_ctx)))
70         goto err;
71
72     /* 0 is a success for SSL_set_alpn_protos() */
73     if (!TEST_false(SSL_set_alpn_protos(c_ssl, alpn, sizeof(alpn))))
74         goto err;
75
76     /* Takes ownership of our reference to the BIO. */
77     SSL_set0_rbio(c_ssl, c_net_bio);
78
79     /* Get another reference to be transferred in the SSL_set0_wbio call. */
80     if (!TEST_true(BIO_up_ref(c_net_bio))) {
81         c_net_bio_own = NULL; /* SSL_free will free the first reference. */
82         goto err;
83     }
84
85     SSL_set0_wbio(c_ssl, c_net_bio);
86     c_net_bio_own = NULL;
87
88     if (!TEST_true(SSL_set_blocking_mode(c_ssl, 0)))
89         goto err;
90
91     start_time = ossl_time_now();
92
93     for (;;) {
94         if (ossl_time_compare(ossl_time_subtract(ossl_time_now(), start_time),
95                               ossl_ms2time(3000)) >= 0) {
96             TEST_error("timeout while attempting QUIC client test");
97             goto err;
98         }
99
100         if (!c_connected) {
101             ret = SSL_connect(c_ssl);
102             if (!TEST_true(ret == 1 || is_want(c_ssl, ret)))
103                 goto err;
104
105             if (ret == 1) {
106                 c_connected = 1;
107                 TEST_info("Connected!");
108             }
109         }
110
111         if (c_connected && !c_write_done) {
112             if (!TEST_int_eq(SSL_write(c_ssl, msg1, sizeof(msg1) - 1),
113                              (int)sizeof(msg1) - 1))
114                 goto err;
115
116             if (!TEST_true(SSL_stream_conclude(c_ssl, 0)))
117                 goto err;
118
119             c_write_done = 1;
120         }
121
122         if (c_write_done && !c_shutdown && c_total_read < sizeof(msg2) - 1) {
123             ret = SSL_read_ex(c_ssl, msg2 + c_total_read,
124                               sizeof(msg2) - 1 - c_total_read, &l);
125             if (ret != 1) {
126                 if (SSL_get_error(c_ssl, ret) == SSL_ERROR_ZERO_RETURN) {
127                     c_shutdown = 1;
128                     TEST_info("Message: \n%s\n", msg2);
129                 } else if (!TEST_true(is_want(c_ssl, ret))) {
130                     goto err;
131                 }
132             } else {
133                 c_total_read += l;
134
135                 if (!TEST_size_t_lt(c_total_read, sizeof(msg2) - 1))
136                     goto err;
137             }
138         }
139
140         if (c_shutdown) {
141             ret = SSL_shutdown(c_ssl);
142             if (ret == 1)
143                 break;
144         }
145
146         /*
147          * This is inefficient because we spin until things work without
148          * blocking but this is just a test.
149          */
150         OSSL_sleep(0);
151         SSL_handle_events(c_ssl);
152     }
153
154     testresult = 1;
155 err:
156     SSL_free(c_ssl);
157     SSL_CTX_free(c_ctx);
158     BIO_ADDR_free(s_addr_);
159     BIO_free(c_net_bio_own);
160     if (c_fd != INVALID_SOCKET)
161         BIO_closesocket(c_fd);
162     return testresult;
163 }
164
165 OPT_TEST_DECLARE_USAGE("certfile privkeyfile\n")
166
167 int setup_tests(void)
168 {
169     if (!test_skip_common_options()) {
170         TEST_error("Error parsing test options\n");
171         return 0;
172     }
173
174     ADD_TEST(test_quic_client);
175     return 1;
176 }