blob: 415588d7b5cb414c573a331ee233103b4e9d5f2f [file] [log] [blame]
roman0e8dedb2023-04-14 09:13:57 +02001/**
2 * @file test_ec.c
3 * @author Roman Janota <xjanot04@fit.vutbr.cz>
roman6e5fd702023-04-27 14:30:27 +02004 * @brief libnetconf2 EC keys authentication test
roman0e8dedb2023-04-14 09:13:57 +02005 *
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 <errno.h>
19#include <pthread.h>
20#include <setjmp.h>
21#include <stdarg.h>
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25
26#include <cmocka.h>
27
28#include "tests/config.h"
29
30#define NC_ACCEPT_TIMEOUT 2000
31#define NC_PS_POLL_TIMEOUT 2000
32
33struct ly_ctx *ctx;
34
35struct test_state {
36 pthread_barrier_t barrier;
roman6e5fd702023-04-27 14:30:27 +020037 const char *client_username;
38 const char *client_privkey;
39 const char *client_pubkey;
roman0e8dedb2023-04-14 09:13:57 +020040};
41
roman0e8dedb2023-04-14 09:13:57 +020042static void *
43server_thread(void *arg)
44{
45 int ret;
46 NC_MSG_TYPE msgtype;
47 struct nc_session *session;
48 struct nc_pollsession *ps;
49 struct test_state *state = arg;
50
51 (void) arg;
52
53 ps = nc_ps_new();
54 assert_non_null(ps);
55
56 /* accept a session and add it to the poll session structure */
57 pthread_barrier_wait(&state->barrier);
58 msgtype = nc_accept(NC_ACCEPT_TIMEOUT, ctx, &session);
59 assert_int_equal(msgtype, NC_MSG_HELLO);
60
61 ret = nc_ps_add_session(ps, session);
62 assert_int_equal(ret, 0);
63
64 do {
65 ret = nc_ps_poll(ps, NC_PS_POLL_TIMEOUT, NULL);
66 assert_int_equal(ret & NC_PSPOLL_RPC, NC_PSPOLL_RPC);
67 } while (!(ret & NC_PSPOLL_SESSION_TERM));
68
69 nc_ps_clear(ps, 1, NULL);
70 nc_ps_free(ps);
roman0e8dedb2023-04-14 09:13:57 +020071 return NULL;
72}
73
roman0e8dedb2023-04-14 09:13:57 +020074static void *
75client_thread(void *arg)
76{
77 int ret;
78 struct nc_session *session = NULL;
79 struct test_state *state = arg;
80
roman6e5fd702023-04-27 14:30:27 +020081 /* skip all hostkey and known_hosts checks */
82 nc_client_ssh_set_knownhosts_mode(NC_SSH_KNOWNHOSTS_SKIP);
83
roman0e8dedb2023-04-14 09:13:57 +020084 /* set directory where to search for modules */
85 ret = nc_client_set_schema_searchpath(MODULES_DIR);
86 assert_int_equal(ret, 0);
87
88 /* set ssh username */
roman6e5fd702023-04-27 14:30:27 +020089 ret = nc_client_ssh_set_username(state->client_username);
roman0e8dedb2023-04-14 09:13:57 +020090 assert_int_equal(ret, 0);
91
92 /* add client's key pair */
roman6e5fd702023-04-27 14:30:27 +020093 ret = nc_client_ssh_add_keypair(state->client_pubkey, state->client_privkey);
roman0e8dedb2023-04-14 09:13:57 +020094 assert_int_equal(ret, 0);
95
96 pthread_barrier_wait(&state->barrier);
97 /* connect */
roman6e5fd702023-04-27 14:30:27 +020098 session = nc_connect_ssh("127.0.0.1", 10009, NULL);
roman0e8dedb2023-04-14 09:13:57 +020099 assert_non_null(session);
100
101 nc_session_free(session, NULL);
roman0e8dedb2023-04-14 09:13:57 +0200102 return NULL;
103}
104
105static void
roman6e5fd702023-04-27 14:30:27 +0200106test_nc_ec256(void **state)
roman0e8dedb2023-04-14 09:13:57 +0200107{
108 int ret, i;
109 pthread_t tids[2];
roman6e5fd702023-04-27 14:30:27 +0200110 struct test_state *client;
roman0e8dedb2023-04-14 09:13:57 +0200111
roman6e5fd702023-04-27 14:30:27 +0200112 /* set specific data for the client */
roman0e8dedb2023-04-14 09:13:57 +0200113 assert_non_null(state);
roman6e5fd702023-04-27 14:30:27 +0200114 client = *state;
roman0e8dedb2023-04-14 09:13:57 +0200115
roman6e5fd702023-04-27 14:30:27 +0200116 /* client */
117 client->client_username = "test_ec256";
118 client->client_pubkey = TESTS_DIR "/data/id_ecdsa256.pub";
119 client->client_privkey = TESTS_DIR "/data/id_ecdsa256";
120 ret = pthread_create(&tids[0], NULL, client_thread, client);
roman0e8dedb2023-04-14 09:13:57 +0200121 assert_int_equal(ret, 0);
roman6e5fd702023-04-27 14:30:27 +0200122
123 /* server */
124 ret = pthread_create(&tids[1], NULL, server_thread, *state);
125 assert_int_equal(ret, 0);
126
127 for (i = 0; i < 2; i++) {
128 pthread_join(tids[i], NULL);
129 }
130}
131
132static void
133test_nc_ec384(void **state)
134{
135 int ret, i;
136 pthread_t tids[2];
137 struct test_state *client;
138
139 /* set specific data for the client */
140 assert_non_null(state);
141 client = *state;
142
143 /* client */
144 client->client_username = "test_ec384";
145 client->client_pubkey = TESTS_DIR "/data/id_ecdsa384.pub";
146 client->client_privkey = TESTS_DIR "/data/id_ecdsa384";
147 ret = pthread_create(&tids[0], NULL, client_thread, client);
148 assert_int_equal(ret, 0);
149
150 /* server */
151 ret = pthread_create(&tids[1], NULL, server_thread, *state);
152 assert_int_equal(ret, 0);
153
154 for (i = 0; i < 2; i++) {
155 pthread_join(tids[i], NULL);
156 }
157}
158
159static void
160test_nc_ec521(void **state)
161{
162 int ret, i;
163 pthread_t tids[2];
164 struct test_state *client;
165
166 /* set specific data for the client */
167 assert_non_null(state);
168 client = *state;
169
170 /* client */
171 client->client_username = "test_ec521";
172 client->client_pubkey = TESTS_DIR "/data/id_ecdsa521.pub";
173 client->client_privkey = TESTS_DIR "/data/id_ecdsa521";
174 ret = pthread_create(&tids[0], NULL, client_thread, client);
175 assert_int_equal(ret, 0);
176
177 /* server */
roman0e8dedb2023-04-14 09:13:57 +0200178 ret = pthread_create(&tids[1], NULL, server_thread, *state);
179 assert_int_equal(ret, 0);
180
181 for (i = 0; i < 2; i++) {
182 pthread_join(tids[i], NULL);
183 }
184}
185
186static int
187setup_f(void **state)
188{
189 int ret;
roman6e5fd702023-04-27 14:30:27 +0200190 struct lyd_node *tree = NULL;
roman0e8dedb2023-04-14 09:13:57 +0200191 struct test_state *test_state;
192
193 nc_verbosity(NC_VERB_VERBOSE);
194
195 /* init barrier */
196 test_state = malloc(sizeof *test_state);
197 assert_non_null(test_state);
198
199 ret = pthread_barrier_init(&test_state->barrier, NULL, 2);
200 assert_int_equal(ret, 0);
201
202 *state = test_state;
203
204 /* create new context */
205 ret = ly_ctx_new(MODULES_DIR, 0, &ctx);
206 assert_int_equal(ret, 0);
207
208 /* load default modules into context */
209 ret = nc_server_init_ctx(&ctx);
210 assert_int_equal(ret, 0);
211
212 /* load ietf-netconf-server module and it's imports into context */
213 ret = nc_server_config_load_modules(&ctx);
214 assert_int_equal(ret, 0);
215
Roytakb2794852023-10-18 14:30:22 +0200216 ret = nc_server_config_add_ssh_hostkey(ctx, "endpt", "hostkey", TESTS_DIR "/data/key_ecdsa", NULL, &tree);
roman6e5fd702023-04-27 14:30:27 +0200217 assert_int_equal(ret, 0);
218
Roytakb2794852023-10-18 14:30:22 +0200219 ret = nc_server_config_add_address_port(ctx, "endpt", NC_TI_LIBSSH, "127.0.0.1", 10009, &tree);
roman6e5fd702023-04-27 14:30:27 +0200220 assert_int_equal(ret, 0);
221
Roytakb2794852023-10-18 14:30:22 +0200222 ret = nc_server_config_add_ssh_user_pubkey(ctx, "endpt", "test_ec256", "pubkey", TESTS_DIR "/data/id_ecdsa256.pub", &tree);
roman6e5fd702023-04-27 14:30:27 +0200223 assert_int_equal(ret, 0);
224
Roytakb2794852023-10-18 14:30:22 +0200225 ret = nc_server_config_add_ssh_user_pubkey(ctx, "endpt", "test_ec384", "pubkey", TESTS_DIR "/data/id_ecdsa384.pub", &tree);
roman6e5fd702023-04-27 14:30:27 +0200226 assert_int_equal(ret, 0);
227
Roytakb2794852023-10-18 14:30:22 +0200228 ret = nc_server_config_add_ssh_user_pubkey(ctx, "endpt", "test_ec521", "pubkey", TESTS_DIR "/data/id_ecdsa521.pub", &tree);
roman0e8dedb2023-04-14 09:13:57 +0200229 assert_int_equal(ret, 0);
230
231 /* configure the server based on the data */
roman142718b2023-06-29 09:15:29 +0200232 ret = nc_server_config_setup_data(tree);
roman0e8dedb2023-04-14 09:13:57 +0200233 assert_int_equal(ret, 0);
234
roman0e8dedb2023-04-14 09:13:57 +0200235 /* initialize server */
236 ret = nc_server_init();
237 assert_int_equal(ret, 0);
238
romaneadc4782023-09-14 10:10:08 +0200239 /* initialize client */
240 ret = nc_client_init();
241 assert_int_equal(ret, 0);
242
roman0e8dedb2023-04-14 09:13:57 +0200243 lyd_free_all(tree);
244
245 return 0;
246}
247
248static int
249teardown_f(void **state)
250{
251 int ret = 0;
252 struct test_state *test_state;
253
254 assert_non_null(state);
255 test_state = *state;
256
257 ret = pthread_barrier_destroy(&test_state->barrier);
258 assert_int_equal(ret, 0);
259
260 free(*state);
261 nc_client_destroy();
262 nc_server_destroy();
263 ly_ctx_destroy(ctx);
264
265 return 0;
266}
267
268int
269main(void)
270{
271 const struct CMUnitTest tests[] = {
roman6e5fd702023-04-27 14:30:27 +0200272 cmocka_unit_test_setup_teardown(test_nc_ec256, setup_f, teardown_f),
273 cmocka_unit_test_setup_teardown(test_nc_ec384, setup_f, teardown_f),
274 cmocka_unit_test_setup_teardown(test_nc_ec521, setup_f, teardown_f),
roman0e8dedb2023-04-14 09:13:57 +0200275 };
276
277 setenv("CMOCKA_TEST_ABORT", "1", 1);
278 return cmocka_run_group_tests(tests, NULL, NULL);
279}