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