1 /*
2 * Copyright (c) 2023, Emna Rekik
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include "server_internal.h"
8 #include <zephyr/logging/log.h>
9 #include <zephyr/net/http/service.h>
10 #include <zephyr/net/net_core.h>
11 #include <zephyr/net/net_ip.h>
12 #include <zephyr/net/socket.h>
13 #include <zephyr/net/tls_credentials.h>
14 #include <zephyr/sys/util.h>
15 #include <zephyr/ztest.h>
16
17 LOG_MODULE_REGISTER(net_test, CONFIG_NET_SOCKETS_LOG_LEVEL);
18
19 /** @brief Stack size for the server thread */
20 #define STACK_SIZE 8192
21
22 #define MY_IPV4_ADDR "127.0.0.1"
23
24 /** @brief arbitrary timeout value in ms */
25 #define TIMEOUT 1000
26
27 #define BUFFER_SIZE 256
28 #define SERVER_PORT 8000
29
30 enum tls_tag {
31 /** The Certificate Authority public key */
32 CA_CERTIFICATE_TAG,
33 /** Used for both the public and private server keys */
34 SERVER_CERTIFICATE_TAG,
35 /** Used for both the public and private client keys */
36 CLIENT_CERTIFICATE_TAG,
37 };
38
39 static const sec_tag_t server_tag_list_verify[] = {
40 CA_CERTIFICATE_TAG,
41 SERVER_CERTIFICATE_TAG,
42 };
43
44 static uint16_t test_http_service_port = SERVER_PORT;
45 HTTPS_SERVICE_DEFINE(test_http_service, MY_IPV4_ADDR, &test_http_service_port,
46 1, 10, NULL, server_tag_list_verify,
47 sizeof(server_tag_list_verify));
48
49 static const unsigned char ca[] = {
50 #include "ca.inc"
51 };
52
53 /**
54 * @brief The Server Certificate
55 *
56 * This is the public key of the server.
57 */
58 static const unsigned char server[] = {
59 #include "server.inc"
60 };
61
62 /**
63 * @brief The Server Private Key
64 *
65 * This is the private key of the server.
66 */
67 static const unsigned char server_privkey[] = {
68 #include "server_privkey.inc"
69 };
70
71 /**
72 * @brief The Client Certificate
73 *
74 * This is the public key of the client.
75 */
76 static const unsigned char client[] = {
77 #include "client.inc"
78 };
79
80 /**
81 * @brief The Client Private Key
82 *
83 * This is the private key of the client.
84 */
85 static const unsigned char client_privkey[] = {
86 #include "client_privkey.inc"
87 };
88
89 static const unsigned char index_html_gz[] = {
90 #include "index.html.gz.inc"
91 };
92
93 static const unsigned char compressed_inc_file[] = {
94 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
95 0x02, 0xff, 0x35, 0x8e, 0xc1, 0x0a, 0xc2, 0x30,
96 0x0c, 0x86, 0xef, 0x7d, 0x8a, 0xec, 0x05, 0x2c,
97 0xbb, 0x87, 0x5c, 0x54, 0xf0, 0xe0, 0x50, 0x58,
98 0x41, 0x3c, 0x4e, 0x17, 0x69, 0x21, 0xa5, 0x65,
99 0x2d, 0x42, 0xdf, 0xde, 0xba, 0x6e, 0x21, 0x10,
100 0xf8, 0xf9, 0xbe, 0x9f, 0x60, 0x77, 0xba, 0x1d,
101 0xcd, 0xf3, 0x7e, 0x06, 0x9b, 0xbd, 0x90, 0xc2,
102 0xfd, 0xf0, 0x34, 0x93, 0x82, 0x3a, 0x98, 0x5d,
103 0x16, 0xa6, 0xa1, 0xc0, 0xe8, 0x7c, 0x14, 0x86,
104 0x91, 0x97, 0x2f, 0x2f, 0xa8, 0x5b, 0xae, 0x50,
105 0x37, 0x16, 0x5f, 0x61, 0x2e, 0x9b, 0x62, 0x7b,
106 0x7a, 0xb0, 0xbc, 0x83, 0x67, 0xc8, 0x01, 0x7c,
107 0x81, 0xd4, 0xd4, 0xb4, 0xaa, 0x5d, 0x55, 0xfa,
108 0x8d, 0x8c, 0x64, 0xac, 0x4b, 0x50, 0x77, 0xda,
109 0xa1, 0x8b, 0x19, 0xae, 0xf0, 0x71, 0xc2, 0x07,
110 0xd4, 0xf1, 0xdf, 0xdf, 0x8a, 0xab, 0xb4, 0xbe,
111 0xf6, 0x03, 0xea, 0x2d, 0x11, 0x5c, 0xb2, 0x00,
112 0x00, 0x00,
113 };
114
115 struct http_resource_detail_static index_html_gz_resource_detail = {
116 .common = {
117 .type = HTTP_RESOURCE_TYPE_STATIC,
118 .bitmask_of_supported_http_methods = BIT(HTTP_GET),
119 },
120 .static_data = index_html_gz,
121 .static_data_len = sizeof(index_html_gz),
122 };
123
124 HTTP_RESOURCE_DEFINE(index_html_gz_resource, test_http_service, "/",
125 &index_html_gz_resource_detail);
126
test_tls(void)127 static void test_tls(void)
128 {
129 int ret, recv_len;
130 int client_fd;
131 int proto = IPPROTO_TCP;
132 size_t len;
133 char *ptr;
134 const char *data;
135 struct sockaddr_in sa;
136 static unsigned char buf[512];
137 char http1_request[] =
138 "GET / HTTP/1.1\r\n"
139 "Host: 127.0.0.1:8080\r\n"
140 "Accept: */*\r\n"
141 "Accept-Encoding: deflate, gzip, br\r\n"
142 "\r\n";
143
144 /* set the common protocol for both client and server */
145 if (IS_ENABLED(CONFIG_NET_SOCKETS_SOCKOPT_TLS)) {
146 proto = IPPROTO_TLS_1_2;
147 }
148
149 zassert_ok(http_server_start(), "Failed to start the server");
150
151 ret = zsock_socket(AF_INET, SOCK_STREAM, proto);
152 zassert_not_equal(ret, -1, "failed to create client socket (%d)", errno);
153 client_fd = ret;
154
155 if (IS_ENABLED(CONFIG_TLS_CREDENTIALS) &&
156 IS_ENABLED(CONFIG_NET_SOCKETS_SOCKOPT_TLS)) {
157 static const sec_tag_t sec_tag_list_verify_none[] = {
158 CA_CERTIFICATE_TAG,
159 };
160 const sec_tag_t *sec_tag_list;
161 size_t sec_tag_list_size;
162
163 sec_tag_list_size = sizeof(sec_tag_list);
164 sec_tag_list = sec_tag_list_verify_none;
165
166 ret = zsock_setsockopt(client_fd, SOL_TLS, TLS_SEC_TAG_LIST,
167 sec_tag_list, sec_tag_list_size);
168 zassert_not_equal(ret, -1, "failed to set TLS_SEC_TAG_LIST (%d)", errno);
169
170 ret = zsock_setsockopt(client_fd, SOL_TLS, TLS_HOSTNAME, "zephyr.local",
171 sizeof("zephyr.local"));
172 zassert_not_equal(ret, -1, "failed to set TLS_HOSTNAME (%d)", errno);
173 }
174
175 sa.sin_family = AF_INET;
176 sa.sin_port = htons(SERVER_PORT);
177
178 ret = zsock_inet_pton(AF_INET, MY_IPV4_ADDR, &sa.sin_addr.s_addr);
179 zassert_not_equal(-1, ret, "inet_pton() failed (%d)", errno);
180 zassert_not_equal(ret, 0, "%s is not a valid IPv4 address", MY_IPV4_ADDR);
181 zassert_equal(ret, 1, "inet_pton() failed to convert %s", MY_IPV4_ADDR);
182
183 memset(buf, '\0', sizeof(buf));
184 ptr = (char *)zsock_inet_ntop(AF_INET, &sa.sin_addr, buf, sizeof(buf));
185 zassert_not_equal(ptr, NULL, "inet_ntop() failed (%d)", errno);
186
187 ret = zsock_connect(client_fd, (struct sockaddr *)&sa, sizeof(sa));
188 zassert_not_equal(ret, -1, "failed to connect (%d)", errno);
189
190 ret = zsock_send(client_fd, http1_request, sizeof(http1_request) - 1, 0);
191 zassert_not_equal(ret, -1, "send() failed (%d)", errno);
192 zassert_equal(ret, sizeof(http1_request) - 1, "expected: %zu actual: %d",
193 sizeof(http1_request) - 1, ret);
194
195 memset(buf, 0, sizeof(buf));
196 recv_len = zsock_recv(client_fd, buf, sizeof(buf), 0);
197 zassert_not_equal(recv_len, -1, "recv() failed (%d)", errno);
198
199 len = sizeof(index_html_gz);
200
201 while (recv_len < len) {
202 ret = zsock_recv(client_fd, buf + recv_len, sizeof(buf) - recv_len, 0);
203 zassert_not_equal(ret, -1, "recv() failed (%d)", errno);
204
205 recv_len += ret;
206 }
207
208 data = strstr(buf, "\r\n\r\n");
209 zassert_not_null(data, "Header not found");
210
211 data += 4;
212
213 zassert_equal(len, sizeof(compressed_inc_file), "Invalid compressed file size");
214
215 ret = memcmp(data, compressed_inc_file, len);
216 zassert_equal(ret, 0,
217 "inc_file and compressed_inc_file contents are not identical (%d)", ret);
218
219 ret = zsock_close(client_fd);
220 zassert_not_equal(ret, -1, "close() failed on the client fd (%d)", errno);
221
222 zassert_ok(http_server_stop(), "Failed to stop the server");
223 }
224
ZTEST(framework_tests_tls,test_tls)225 ZTEST(framework_tests_tls, test_tls)
226 {
227 test_tls();
228 }
229
setup(void)230 static void *setup(void)
231 {
232 int ret;
233
234 if (IS_ENABLED(CONFIG_TLS_CREDENTIALS)) {
235 NET_DBG("Loading credentials");
236 ret = tls_credential_add(CA_CERTIFICATE_TAG,
237 TLS_CREDENTIAL_CA_CERTIFICATE,
238 ca, sizeof(ca));
239 zassert_equal(ret, 0, "failed to add CA Certificate (%d)", ret);
240
241 ret = tls_credential_add(SERVER_CERTIFICATE_TAG,
242 TLS_CREDENTIAL_SERVER_CERTIFICATE,
243 server, sizeof(server));
244 zassert_equal(ret, 0, "failed to add Server Certificate (%d)", ret);
245
246 ret = tls_credential_add(SERVER_CERTIFICATE_TAG,
247 TLS_CREDENTIAL_PRIVATE_KEY,
248 server_privkey, sizeof(server_privkey));
249 zassert_equal(ret, 0, "failed to add Server Private Key (%d)", ret);
250
251 ret = tls_credential_add(CLIENT_CERTIFICATE_TAG,
252 TLS_CREDENTIAL_SERVER_CERTIFICATE,
253 client, sizeof(client));
254 zassert_equal(ret, 0, "failed to add Client Certificate (%d)", ret);
255
256 ret = tls_credential_add(CLIENT_CERTIFICATE_TAG,
257 TLS_CREDENTIAL_PRIVATE_KEY,
258 client_privkey, sizeof(client_privkey));
259 zassert_equal(ret, 0, "failed to add Client Private Key (%d)", ret);
260 }
261
262 return NULL;
263 }
264
265 ZTEST_SUITE(framework_tests_tls, NULL, setup, NULL, NULL, NULL);
266