blob: ed0966b1cf6272a5b7046485255ee8b19a3975e9 [file] [log] [blame]
roman3f9b65c2023-06-05 14:26:58 +02001/**
2 * @file test_tls.c
3 * @author Roman Janota <janota@cesnet.cz>
4 * @brief libnetconf2 TLS authentication test
5 *
6 * @copyright
7 * Copyright (c) 2023 CESNET, z.s.p.o.
8 *
9 * This source code is licensed under BSD 3-Clause License (the "License").
10 * You may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
12 *
13 * https://opensource.org/licenses/BSD-3-Clause
14 */
15
16#define _GNU_SOURCE
17
18#include <pthread.h>
19#include <setjmp.h>
20#include <stdio.h>
21#include <stdlib.h>
22#include <string.h>
23
24#include <cmocka.h>
25
26#include "tests/config.h"
27
28#define NC_ACCEPT_TIMEOUT 2000
29#define NC_PS_POLL_TIMEOUT 2000
30
31struct ly_ctx *ctx;
32
33struct test_state {
34 pthread_barrier_t barrier;
35};
36
37static void *
38server_thread(void *arg)
39{
40 int ret;
41 NC_MSG_TYPE msgtype;
42 struct nc_session *session;
43 struct nc_pollsession *ps;
44 struct test_state *state = arg;
45
46 (void) arg;
47
48 ps = nc_ps_new();
49 assert_non_null(ps);
50
51 /* accept a session and add it to the poll session structure */
52 pthread_barrier_wait(&state->barrier);
53 msgtype = nc_accept(NC_ACCEPT_TIMEOUT, ctx, &session);
54 assert_int_equal(msgtype, NC_MSG_HELLO);
55
56 ret = nc_ps_add_session(ps, session);
57 assert_int_equal(ret, 0);
58
59 do {
60 ret = nc_ps_poll(ps, NC_PS_POLL_TIMEOUT, NULL);
61 assert_int_equal(ret & NC_PSPOLL_RPC, NC_PSPOLL_RPC);
62 } while (!(ret & NC_PSPOLL_SESSION_TERM));
63
64 nc_ps_clear(ps, 1, NULL);
65 nc_ps_free(ps);
roman3f9b65c2023-06-05 14:26:58 +020066 return NULL;
67}
68
69static void *
70client_thread(void *arg)
71{
72 int ret;
73 struct nc_session *session = NULL;
74 struct test_state *state = arg;
75
76 ret = nc_client_set_schema_searchpath(MODULES_DIR);
77 assert_int_equal(ret, 0);
78
79 /* set client cert */
80 ret = nc_client_tls_set_cert_key_paths(TESTS_DIR "/data/client.crt", TESTS_DIR "/data/client.key");
81 assert_int_equal(ret, 0);
82
83 /* set client ca */
84 ret = nc_client_tls_set_trusted_ca_paths(NULL, TESTS_DIR "/data");
85 assert_int_equal(ret, 0);
86
87 pthread_barrier_wait(&state->barrier);
88 session = nc_connect_tls("127.0.0.1", 10005, NULL);
89 assert_non_null(session);
90
91 nc_session_free(session, NULL);
roman3f9b65c2023-06-05 14:26:58 +020092 return NULL;
93}
94
95static void
96test_nc_tls(void **state)
97{
98 int ret, i;
99 pthread_t tids[2];
100
101 assert_non_null(state);
102
103 ret = pthread_create(&tids[0], NULL, client_thread, *state);
104 assert_int_equal(ret, 0);
105 ret = pthread_create(&tids[1], NULL, server_thread, *state);
106 assert_int_equal(ret, 0);
107
108 for (i = 0; i < 2; i++) {
109 pthread_join(tids[i], NULL);
110 }
111}
112
113static int
114setup_f(void **state)
115{
116 int ret;
117 struct lyd_node *tree = NULL;
118 struct test_state *test_state;
119
120 nc_verbosity(NC_VERB_VERBOSE);
121
122 /* init barrier */
123 test_state = malloc(sizeof *test_state);
124 assert_non_null(test_state);
125
126 ret = pthread_barrier_init(&test_state->barrier, NULL, 2);
127 assert_int_equal(ret, 0);
128
129 *state = test_state;
130
131 ret = ly_ctx_new(MODULES_DIR, 0, &ctx);
132 assert_int_equal(ret, 0);
133
134 ret = nc_server_init_ctx(&ctx);
135 assert_int_equal(ret, 0);
136
137 ret = nc_server_config_load_modules(&ctx);
138 assert_int_equal(ret, 0);
139
140 /* create new address and port data */
roman142718b2023-06-29 09:15:29 +0200141 ret = nc_server_config_new_address_port(ctx, "endpt", NC_TI_OPENSSL, "127.0.0.1", 10005, &tree);
roman3f9b65c2023-06-05 14:26:58 +0200142 assert_int_equal(ret, 0);
143
144 /* create new server certificate data */
roman6c4efcd2023-08-08 10:18:44 +0200145 ret = nc_server_config_new_tls_server_certificate(ctx, "endpt", TESTS_DIR "/data/server.key", NULL, TESTS_DIR "/data/server.crt", &tree);
roman3f9b65c2023-06-05 14:26:58 +0200146 assert_int_equal(ret, 0);
147
148 /* create new end entity client cert data */
149 ret = nc_server_config_new_tls_client_certificate(ctx, "endpt", "client_cert", TESTS_DIR "/data/client.crt", &tree);
150 assert_int_equal(ret, 0);
151
152 /* create new client ca data */
153 ret = nc_server_config_new_tls_client_ca(ctx, "endpt", "client_ca", TESTS_DIR "/data/serverca.pem", &tree);
154 assert_int_equal(ret, 0);
155
roman12644fe2023-06-08 11:06:42 +0200156 /* create new cert-to-name */
roman3f9b65c2023-06-05 14:26:58 +0200157 ret = nc_server_config_new_tls_ctn(ctx, "endpt", 1,
158 "04:85:6B:75:D1:1A:86:E0:D8:FE:5B:BD:72:F5:73:1D:07:EA:32:BF:09:11:21:6A:6E:23:78:8E:B6:D5:73:C3:2D",
159 NC_TLS_CTN_SPECIFIED, "client", &tree);
160 assert_int_equal(ret, 0);
161
roman12644fe2023-06-08 11:06:42 +0200162 /* limit TLS version to 1.3 */
163 ret = nc_server_config_new_tls_version(ctx, "endpt", NC_TLS_VERSION_13, &tree);
164 assert_int_equal(ret, 0);
165
166 /* set the TLS cipher */
167 ret = nc_server_config_new_tls_ciphers(ctx, "endpt", &tree, 3, "tls-aes-128-ccm-sha256", "tls-aes-128-gcm-sha256", "tls-chacha20-poly1305-sha256");
168 assert_int_equal(ret, 0);
169
roman3f9b65c2023-06-05 14:26:58 +0200170 /* configure the server based on the data */
roman142718b2023-06-29 09:15:29 +0200171 ret = nc_server_config_setup_data(tree);
roman3f9b65c2023-06-05 14:26:58 +0200172 assert_int_equal(ret, 0);
173
roman3f9b65c2023-06-05 14:26:58 +0200174 ret = nc_server_init();
175 assert_int_equal(ret, 0);
176
177 lyd_free_all(tree);
178
179 return 0;
180}
181
182static int
183teardown_f(void **state)
184{
185 int ret = 0;
186 struct test_state *test_state;
187
188 assert_non_null(state);
189 test_state = *state;
190
191 ret = pthread_barrier_destroy(&test_state->barrier);
192 assert_int_equal(ret, 0);
193
194 free(*state);
195 nc_client_destroy();
196 nc_server_destroy();
197 ly_ctx_destroy(ctx);
198
199 return 0;
200}
201
202int
203main(void)
204{
205 const struct CMUnitTest tests[] = {
206 cmocka_unit_test_setup_teardown(test_nc_tls, setup_f, teardown_f),
207 };
208
209 setenv("CMOCKA_TEST_ABORT", "1", 1);
210 return cmocka_run_group_tests(tests, NULL, NULL);
211}