Skip to content

Commit 60c4ddd

Browse files
romanmichalvasko
authored andcommitted
tests UPDATE add authkey test
1 parent a9ec336 commit 60c4ddd

File tree

3 files changed

+310
-1
lines changed

3 files changed

+310
-1
lines changed

tests/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ set(tests test_unix_socket test_client_thread test_fd_comm test_init_destroy_cli
1515
if(ENABLE_SSH_TLS)
1616
list(APPEND tests test_auth test_two_channels test_ks_ts test_ec
1717
test_ed25519 test_replace test_endpt_share_clients test_tls test_crl test_ch
18-
test_runtime_changes test_client_ssh test_client_tls)
18+
test_runtime_changes test_client_ssh test_client_tls test_authkeys)
1919

2020
if (LIBPAM_HAVE_CONFDIR)
2121
list(APPEND tests test_pam)

tests/data/authorized_keys

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOr46rptg6BsWhO1JMomuh3cuCYmeuO6JfOUPs/YO35w test@libnetconf2
2+
ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBIY62KY++anyNuwrmQu2jQdyB9pYZMGEGyf5zl15jRJC7OGPq+TGqRgwFOoBylYtuPrFWGlM+zktqUMn19+5qPo= test@libnetconf2

tests/test_authkeys.c

Lines changed: 307 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,307 @@
1+
/**
2+
* @file test_authkeys.c
3+
* @author Roman Janota <[email protected]>
4+
* @brief libnetconf2 SSH authentication using mocked system authorized_keys
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 <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+
33+
struct ly_ctx *ctx;
34+
35+
struct test_state {
36+
pthread_barrier_t barrier;
37+
const char *pubkey_path;
38+
const char *privkey_path;
39+
int expect_ok;
40+
};
41+
42+
static void *
43+
server_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+
ps = nc_ps_new();
52+
assert_non_null(ps);
53+
54+
/* accept a session and add it to the poll session structure */
55+
pthread_barrier_wait(&state->barrier);
56+
msgtype = nc_accept(NC_ACCEPT_TIMEOUT, ctx, &session);
57+
58+
/* only continue if we expect to authenticate successfully */
59+
if (state->expect_ok) {
60+
assert_int_equal(msgtype, NC_MSG_HELLO);
61+
} else {
62+
assert_int_equal(msgtype, NC_MSG_ERROR);
63+
nc_ps_free(ps);
64+
return NULL;
65+
}
66+
67+
ret = nc_ps_add_session(ps, session);
68+
assert_int_equal(ret, 0);
69+
70+
do {
71+
ret = nc_ps_poll(ps, NC_PS_POLL_TIMEOUT, NULL);
72+
assert_int_equal(ret & NC_PSPOLL_RPC, NC_PSPOLL_RPC);
73+
} while (!(ret & NC_PSPOLL_SESSION_TERM));
74+
75+
nc_ps_clear(ps, 1, NULL);
76+
nc_ps_free(ps);
77+
return NULL;
78+
}
79+
80+
static void *
81+
client_thread(void *arg)
82+
{
83+
int ret;
84+
struct nc_session *session = NULL;
85+
struct test_state *state = arg;
86+
87+
/* skip all hostkey and known_hosts checks */
88+
nc_client_ssh_set_knownhosts_mode(NC_SSH_KNOWNHOSTS_SKIP);
89+
90+
/* set directory where to search for modules */
91+
ret = nc_client_set_schema_searchpath(MODULES_DIR);
92+
assert_int_equal(ret, 0);
93+
94+
/* add client's key pair */
95+
ret = nc_client_ssh_add_keypair(state->pubkey_path, state->privkey_path);
96+
assert_int_equal(ret, 0);
97+
98+
/* set ssh username */
99+
ret = nc_client_ssh_set_username("test");
100+
assert_int_equal(ret, 0);
101+
102+
pthread_barrier_wait(&state->barrier);
103+
/* connect */
104+
session = nc_connect_ssh("127.0.0.1", 10009, NULL);
105+
if (state->expect_ok) {
106+
assert_non_null(session);
107+
} else {
108+
assert_null(session);
109+
}
110+
111+
nc_session_free(session, NULL);
112+
return NULL;
113+
}
114+
115+
static void
116+
test_nc_authkey_ok(void **arg)
117+
{
118+
int ret, i;
119+
pthread_t tids[2];
120+
struct test_state *state;
121+
122+
assert_non_null(arg);
123+
124+
state = *(struct test_state **)arg;
125+
126+
/* set the path to the test's authorized_keys file */
127+
ret = nc_server_ssh_set_authkey_path_format(TESTS_DIR "/data/authorized_keys");
128+
assert_int_equal(ret, 0);
129+
130+
/* set pubkey and privkey path, the pubkey matches the one in authorized keys */
131+
state->pubkey_path = TESTS_DIR "/data/id_ed25519.pub";
132+
state->privkey_path = TESTS_DIR "/data/id_ed25519";
133+
134+
/* expect ok result */
135+
state->expect_ok = 1;
136+
137+
/* client */
138+
ret = pthread_create(&tids[0], NULL, client_thread, state);
139+
assert_int_equal(ret, 0);
140+
141+
/* server */
142+
ret = pthread_create(&tids[1], NULL, server_thread, state);
143+
assert_int_equal(ret, 0);
144+
145+
for (i = 0; i < 2; i++) {
146+
pthread_join(tids[i], NULL);
147+
}
148+
}
149+
150+
static void
151+
test_nc_authkey_bad_key(void **arg)
152+
{
153+
int ret, i;
154+
pthread_t tids[2];
155+
struct test_state *state;
156+
157+
assert_non_null(arg);
158+
159+
state = *(struct test_state **)arg;
160+
161+
/* set the path to the test's authorized_keys file */
162+
ret = nc_server_ssh_set_authkey_path_format(TESTS_DIR "/data/authorized_keys");
163+
assert_int_equal(ret, 0);
164+
165+
/* set pubkey and privkey path, the pubkey doesn't match the one in authorized keys */
166+
state->pubkey_path = TESTS_DIR "/data/id_ecdsa521.pub";
167+
state->privkey_path = TESTS_DIR "/data/id_ecdsa521";
168+
169+
/* expect fail */
170+
state->expect_ok = 0;
171+
172+
/* client */
173+
ret = pthread_create(&tids[0], NULL, client_thread, state);
174+
assert_int_equal(ret, 0);
175+
176+
/* server */
177+
ret = pthread_create(&tids[1], NULL, server_thread, state);
178+
assert_int_equal(ret, 0);
179+
180+
for (i = 0; i < 2; i++) {
181+
pthread_join(tids[i], NULL);
182+
}
183+
}
184+
185+
static void
186+
test_nc_authkey_bad_path(void **arg)
187+
{
188+
int ret, i;
189+
pthread_t tids[2];
190+
struct test_state *state;
191+
192+
assert_non_null(arg);
193+
194+
state = *(struct test_state **)arg;
195+
196+
/* set the path to the test's authorized_keys file */
197+
ret = nc_server_ssh_set_authkey_path_format(TESTS_DIR "/some/bad/path");
198+
assert_int_equal(ret, 0);
199+
200+
/* set pubkey and privkey path, the pubkey doesn't match the one in authorized keys */
201+
state->pubkey_path = TESTS_DIR "/data/id_ed25519.pub";
202+
state->privkey_path = TESTS_DIR "/data/id_ed25519";
203+
204+
/* expect fail */
205+
state->expect_ok = 0;
206+
207+
/* client */
208+
ret = pthread_create(&tids[0], NULL, client_thread, state);
209+
assert_int_equal(ret, 0);
210+
211+
/* server */
212+
ret = pthread_create(&tids[1], NULL, server_thread, state);
213+
assert_int_equal(ret, 0);
214+
215+
for (i = 0; i < 2; i++) {
216+
pthread_join(tids[i], NULL);
217+
}
218+
}
219+
220+
static int
221+
setup_f(void **state)
222+
{
223+
int ret;
224+
struct lyd_node *tree = NULL;
225+
struct test_state *test_state;
226+
227+
nc_verbosity(NC_VERB_VERBOSE);
228+
229+
/* init barrier */
230+
test_state = malloc(sizeof *test_state);
231+
assert_non_null(test_state);
232+
233+
ret = pthread_barrier_init(&test_state->barrier, NULL, 2);
234+
assert_int_equal(ret, 0);
235+
236+
*state = test_state;
237+
238+
/* create new context */
239+
ret = ly_ctx_new(MODULES_DIR, 0, &ctx);
240+
assert_int_equal(ret, 0);
241+
242+
/* load default modules into context */
243+
ret = nc_server_init_ctx(&ctx);
244+
assert_int_equal(ret, 0);
245+
246+
/* load ietf-netconf-server module and it's imports into context */
247+
ret = nc_server_config_load_modules(&ctx);
248+
assert_int_equal(ret, 0);
249+
250+
ret = nc_server_config_add_ssh_hostkey(ctx, "endpt", "hostkey", TESTS_DIR "/data/server.key", NULL, &tree);
251+
assert_int_equal(ret, 0);
252+
253+
ret = nc_server_config_add_address_port(ctx, "endpt", NC_TI_LIBSSH, "127.0.0.1", 10009, &tree);
254+
assert_int_equal(ret, 0);
255+
256+
ret = nc_server_config_add_ssh_user_authkey(ctx, "endpt", "test", &tree);
257+
assert_int_equal(ret, 0);
258+
259+
/* configure the server based on the data */
260+
ret = nc_server_config_setup_data(tree);
261+
assert_int_equal(ret, 0);
262+
263+
/* initialize server */
264+
ret = nc_server_init();
265+
assert_int_equal(ret, 0);
266+
267+
/* initialize client */
268+
ret = nc_client_init();
269+
assert_int_equal(ret, 0);
270+
271+
lyd_free_all(tree);
272+
273+
return 0;
274+
}
275+
276+
static int
277+
teardown_f(void **state)
278+
{
279+
int ret = 0;
280+
struct test_state *test_state;
281+
282+
assert_non_null(state);
283+
test_state = *state;
284+
285+
ret = pthread_barrier_destroy(&test_state->barrier);
286+
assert_int_equal(ret, 0);
287+
288+
free(*state);
289+
nc_client_destroy();
290+
nc_server_destroy();
291+
ly_ctx_destroy(ctx);
292+
293+
return 0;
294+
}
295+
296+
int
297+
main(void)
298+
{
299+
const struct CMUnitTest tests[] = {
300+
cmocka_unit_test_setup_teardown(test_nc_authkey_ok, setup_f, teardown_f),
301+
cmocka_unit_test_setup_teardown(test_nc_authkey_bad_key, setup_f, teardown_f),
302+
cmocka_unit_test_setup_teardown(test_nc_authkey_bad_path, setup_f, teardown_f),
303+
};
304+
305+
setenv("CMOCKA_TEST_ABORT", "1", 1);
306+
return cmocka_run_group_tests(tests, NULL, NULL);
307+
}

0 commit comments

Comments
 (0)