OpenVPN
test_auth_token.c
Go to the documentation of this file.
1/*
2 * OpenVPN -- An application to securely tunnel IP networks
3 * over a single UDP port, with support for SSL/TLS-based
4 * session authentication and key exchange,
5 * packet encryption, packet authentication, and
6 * packet compression.
7 *
8 * Copyright (C) 2016-2021 Fox Crypto B.V. <openvpn@foxcrypto.com>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2
12 * as published by the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 */
23
24#ifdef HAVE_CONFIG_H
25#include "config.h"
26#endif
27
28#include "syshead.h"
29
30#include <stdio.h>
31#include <stdlib.h>
32#include <stdarg.h>
33#include <string.h>
34#include <setjmp.h>
35#include <cmocka.h>
36
37#include "auth_token.c"
38#include "test_common.h"
39
42 struct key_type kt;
43 struct user_pass up;
45};
46
47/* Dummy functions that do nothing to mock the functionality */
48void
52
53void
54auth_set_client_reason(struct tls_multi *multi, const char *reason)
55{
56
57}
58
59static const char *now0key0 = "SESS_ID_AT_0123456789abcdefAAAAAAAAAAAAAAAAAAAAAE5JsQJOVfo8jnI3RL3tBaR5NkE4yPfcylFUHmHSc5Bu";
60
61static const char *zeroinline = "-----BEGIN OpenVPN auth-token server key-----\n"
62 "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
63 "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
64 "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\n"
65 "-----END OpenVPN auth-token server key-----";
66
67static const char *allx01inline = "-----BEGIN OpenVPN auth-token server key-----\n"
68 "AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEB\n"
69 "AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEB\n"
70 "AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQE=\n"
71 "-----END OpenVPN auth-token server key-----";
72
73static const char *random_key = "-----BEGIN OpenVPN auth-token server key-----\n"
74 "+mmmf7IQ5cymtMVjKYTWk8IOcYanRlpQmV9Tb3EjkHYxueBVDg3yqRgzeBlVGzNLD//rAPiOVhau\n"
75 "3NDBjNOQB8951bfs7Cc2mYfay92Bh2gRJ5XEM/DMfzCWN+7uU6NWoTTHr4FuojnIQtjtqVAj/JS9\n"
76 "w+dTSp/vYHl+c7uHd19uVRu/qLqV85+rm4tUGIjO7FfYuwyPqwmhuIsi3hs9QkSimh888FmBpoKY\n"
77 "/tbKVTJZmSERKti9KEwtV2eVAR0znN5KW7lCB3mHVAhN7bUpcoDjfCzYIFARxwswTFu9gFkwqUMY\n"
78 "I1KUOgIsVNs4llACioeXplYekWETR+YkJwDc/A==\n"
79 "-----END OpenVPN auth-token server key-----";
80
81static const char *random_token = "SESS_ID_AT_ThhRItzOKNKrh3dfAAAAAFwzHpwAAAAAXDMenDdrq0RoH3dkA1f7O3wO+7kZcx2DusVZrRmFlWQM9HOb";
82
83
84static int
85setup(void **state)
86{
87 struct test_context *ctx = calloc(1, sizeof(*ctx));
88 *state = ctx;
89
90 struct key_parameters key = { 0 };
91 key.hmac_size = MAX_HMAC_KEY_LENGTH; /* 64 byte of 0 */
92
93 ctx->kt = auth_token_kt();
94 if (!ctx->kt.digest)
95 {
96 return 0;
97 }
98 ctx->multi.opt.auth_token_generate = true;
99 ctx->multi.opt.auth_token_lifetime = 3000;
100 ctx->session = &ctx->multi.session[TM_ACTIVE];
101
102 ctx->session->opt = calloc(1, sizeof(struct tls_options));
103 ctx->session->opt->renegotiate_seconds = 240;
104 ctx->session->opt->auth_token_renewal = 120;
105 ctx->session->opt->auth_token_lifetime = 3000;
106
107 strcpy(ctx->up.username, "test user name");
108 strcpy(ctx->up.password, "ignored");
109
110 init_key_ctx(&ctx->multi.opt.auth_token_key, &key, &ctx->kt, false, "TEST");
111
112 now = 0;
113 return 0;
114}
115
116static int
117teardown(void **state)
118{
119 struct test_context *ctx = (struct test_context *) *state;
120
122 wipe_auth_token(&ctx->multi);
123
124 free(ctx->session->opt);
125 free(ctx);
126
127 return 0;
128}
129
130static void
132{
133 struct test_context *ctx = (struct test_context *) *state;
134
135 generate_auth_token(&ctx->up, &ctx->multi);
136 strcpy(ctx->up.password, ctx->multi.auth_token);
137 assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session),
139}
140
141static void
143{
144 struct test_context *ctx = (struct test_context *) *state;
145
146 generate_auth_token(&ctx->up, &ctx->multi);
147 strcpy(ctx->up.password, ctx->multi.auth_token);
148 assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session),
150
151 /* Change auth-token key */
152 struct key_parameters key;
153 memset(key.hmac, '1', sizeof(key.hmac));
154 key.hmac_size = MAX_HMAC_KEY_LENGTH;
155
157 init_key_ctx(&ctx->multi.opt.auth_token_key, &key, &ctx->kt, false, "TEST");
158
159 assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session), 0);
160
161 /* Load original test key again */
162 memset(&key.hmac, 0, sizeof(key.hmac));
164 init_key_ctx(&ctx->multi.opt.auth_token_key, &key, &ctx->kt, false, "TEST");
165 assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session),
167
168}
169
170static void
172{
173 struct test_context *ctx = (struct test_context *) *state;
174
175 now = 100000;
176 generate_auth_token(&ctx->up, &ctx->multi);
177
178 strcpy(ctx->up.password, ctx->multi.auth_token);
179 free(ctx->multi.auth_token_initial);
180 ctx->multi.auth_token_initial = NULL;
181
182 /* No time has passed */
183 assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session),
185
186 /* Token before validity, should be rejected */
187 now = 100000 - 100;
188 assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session),
190
191 /* Token no valid for renegotiate_seconds but still for renewal_time */
192 now = 100000 + 2*ctx->session->opt->renegotiate_seconds - 20;
193 assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session),
195
196
197 now = 100000 + 2*ctx->session->opt->auth_token_renewal - 20;
198 assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session),
200
201 /* Token past validity, should be rejected */
202 now = 100000 + 2*ctx->session->opt->renegotiate_seconds + 20;
203 assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session),
205
206 /* But not when we reached our timeout */
207 now = 100000 + ctx->session->opt->auth_token_lifetime + 1;
208 assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session),
210
211 free(ctx->multi.auth_token_initial);
212 ctx->multi.auth_token_initial = NULL;
213
214 /* regenerate the token util it hits the expiry */
215 now = 100000;
216 while (now < 100000 + ctx->session->opt->auth_token_lifetime + 1)
217 {
218 assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session),
220 generate_auth_token(&ctx->up, &ctx->multi);
221 strcpy(ctx->up.password, ctx->multi.auth_token);
223 }
224
225
226 assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session),
229
230 /* Non expiring token should be fine */
231 assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session),
233}
234
235static void
236zerohmac(char *token)
237{
238 char *hmacstart = token + AUTH_TOKEN_SESSION_ID_LEN
239 + strlen(SESSION_ID_PREFIX) + 2*sizeof(uint64_t);
240 memset(hmacstart, 0x8d, strlen(hmacstart));
241}
242
243static void
245{
246 struct test_context *ctx = (struct test_context *) *state;
247
248 now = 0;
249 /* Preload the session id so the same session id is used here */
250 ctx->multi.auth_token_initial = strdup(now0key0);
251 assert_non_null(ctx->multi.auth_token_initial);
252
253 /* Zero the hmac part to ensure we have a newly generated token */
255
256 generate_auth_token(&ctx->up, &ctx->multi);
257
258 assert_string_equal(now0key0, ctx->multi.auth_token);
259
260 strcpy(ctx->up.password, ctx->multi.auth_token);
261 assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session),
263}
264
265static const char *lastsesion_statevalue;
266void
267setenv_str(struct env_set *es, const char *name, const char *value)
268{
269 if (streq(name, "session_state"))
270 {
271 lastsesion_statevalue = value;
272 }
273}
274
275void
277{
278 struct test_context *ctx = (struct test_context *) *state;
279
280 /* Generate first auth token and check it is correct */
281 generate_auth_token(&ctx->up, &ctx->multi);
282 strcpy(ctx->up.password, ctx->multi.auth_token);
283 assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session),
285
286 char *token_sessiona = strdup(ctx->multi.auth_token);
287
288 /* Generate second token */
289 wipe_auth_token(&ctx->multi);
290
291 generate_auth_token(&ctx->up, &ctx->multi);
292 strcpy(ctx->up.password, ctx->multi.auth_token);
293 assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session),
295
296 assert_int_not_equal(0, memcmp(ctx->multi.auth_token_initial + strlen(SESSION_ID_PREFIX),
297 token_sessiona + strlen(SESSION_ID_PREFIX),
299
300 /* The first token is valid but should trigger the invalid response since
301 * the session id is not the same */
302 strcpy(ctx->up.password, token_sessiona);
303 assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session), 0);
304 free(token_sessiona);
305}
306
307static void
309{
310 struct test_context *ctx = (struct test_context *) *state;
311
312 CLEAR(ctx->up.username);
313 now = 0;
314
315 generate_auth_token(&ctx->up, &ctx->multi);
316 strcpy(ctx->up.password, ctx->multi.auth_token);
317 assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session),
319
320 now = 100000;
321 assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session),
323 strcpy(ctx->up.username, "test user name");
324
325 now = 0;
326 assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session),
328
329 strcpy(ctx->up.username, "test user name");
330 now = 100000;
331 assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session),
333
334 zerohmac(ctx->up.password);
335 assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session),
336 0);
337}
338
339static void
341{
342 struct test_context *ctx = (struct test_context *) *state;
343
344 struct key_state *ks = &ctx->multi.session[TM_ACTIVE].key[KS_PRIMARY];
345
347 ctx->multi.auth_token = NULL;
348 add_session_token_env(ctx->session, &ctx->multi, &ctx->up);
349 assert_string_equal(lastsesion_statevalue, "Initial");
350
352 strcpy(ctx->up.password, now0key0);
353 add_session_token_env(ctx->session, &ctx->multi, &ctx->up);
354 assert_string_equal(lastsesion_statevalue, "Invalid");
355
357 add_session_token_env(ctx->session, &ctx->multi, &ctx->up);
358 assert_string_equal(lastsesion_statevalue, "Authenticated");
359
361 add_session_token_env(ctx->session, &ctx->multi, &ctx->up);
362 assert_string_equal(lastsesion_statevalue, "Expired");
363
365 add_session_token_env(ctx->session, &ctx->multi, &ctx->up);
366 assert_string_equal(lastsesion_statevalue, "AuthenticatedEmptyUser");
367
369 add_session_token_env(ctx->session, &ctx->multi, &ctx->up);
370 assert_string_equal(lastsesion_statevalue, "ExpiredEmptyUser");
371}
372
373static void
375{
376 struct test_context *ctx = (struct test_context *) *state;
377
378 now = 0x5c331e9c;
379 /* Preload the session id so the same session id is used here */
381 assert_non_null(ctx->multi.auth_token_initial);
382
385
386 /* Zero the hmac part to ensure we have a newly generated token */
388
389 generate_auth_token(&ctx->up, &ctx->multi);
390
391 assert_string_equal(random_token, ctx->multi.auth_token);
392
393 strcpy(ctx->up.password, ctx->multi.auth_token);
394 assert_true(verify_auth_token(&ctx->up, &ctx->multi, ctx->session));
395}
396
397
398static void
400{
401 struct test_context *ctx = (struct test_context *) *state;
402
405 strcpy(ctx->up.password, now0key0);
406 assert_true(verify_auth_token(&ctx->up, &ctx->multi, ctx->session));
407
410 assert_false(verify_auth_token(&ctx->up, &ctx->multi, ctx->session));
411}
412
413int
414main(void)
415{
417 const struct CMUnitTest tests[] = {
418 cmocka_unit_test_setup_teardown(auth_token_basic_test, setup, teardown),
419 cmocka_unit_test_setup_teardown(auth_token_fail_invalid_key, setup, teardown),
420 cmocka_unit_test_setup_teardown(auth_token_test_known_keys, setup, teardown),
421 cmocka_unit_test_setup_teardown(auth_token_test_empty_user, setup, teardown),
422 cmocka_unit_test_setup_teardown(auth_token_test_env, setup, teardown),
423 cmocka_unit_test_setup_teardown(auth_token_test_random_keys, setup, teardown),
424 cmocka_unit_test_setup_teardown(auth_token_test_key_load, setup, teardown),
425 cmocka_unit_test_setup_teardown(auth_token_test_timeout, setup, teardown),
426 cmocka_unit_test_setup_teardown(auth_token_test_session_mismatch, setup, teardown)
427 };
428
429#if defined(ENABLE_CRYPTO_OPENSSL)
430 OpenSSL_add_all_algorithms();
431#endif
432
433 int ret = cmocka_run_group_tests_name("auth-token tests", tests, NULL, NULL);
434
435 return ret;
436}
void auth_token_init_secret(struct key_ctx *key_ctx, const char *key_file, bool key_inline)
Loads an HMAC secret from a file or if no file is present generates a epheremal secret for the run ti...
Definition auth_token.c:124
void generate_auth_token(const struct user_pass *up, struct tls_multi *multi)
Generate an auth token based on username and timestamp.
Definition auth_token.c:164
#define AUTH_TOKEN_SESSION_ID_LEN
Definition auth_token.c:21
unsigned int verify_auth_token(struct user_pass *up, struct tls_multi *multi, struct tls_session *session)
Verifies the auth token to be in the format that generate_auth_token create and checks if the token i...
Definition auth_token.c:294
static struct key_type auth_token_kt(void)
Definition auth_token.c:32
#define AUTH_TOKEN_SESSION_ID_BASE64_LEN
Definition auth_token.c:22
void add_session_token_env(struct tls_session *session, struct tls_multi *multi, const struct user_pass *up)
Put the session id, and auth token status into the environment if auth-token is enabled.
Definition auth_token.c:38
void wipe_auth_token(struct tls_multi *multi)
Wipes the authentication token out of the memory, frees and cleans up related buffers and flags.
Definition auth_token.c:401
#define SESSION_ID_PREFIX
The prefix given to auth tokens start with, this prefix is special cased to not show up in log files ...
Definition auth_token.h:115
void init_key_ctx(struct key_ctx *ctx, const struct key_parameters *key, const struct key_type *kt, int enc, const char *prefix)
Definition crypto.c:1015
void free_key_ctx(struct key_ctx *ctx)
Definition crypto.c:1106
#define MAX_HMAC_KEY_LENGTH
#define KS_PRIMARY
Primary key state index.
Definition ssl_common.h:456
#define TM_ACTIVE
Active tls_session.
Definition ssl_common.h:535
#define CLEAR(x)
Definition basic.h:33
#define streq(x, y)
Definition options.h:725
time_t now
Definition otime.c:34
#define AUTH_TOKEN_HMAC_OK
Auth-token sent from client has valid hmac.
Definition ssl_common.h:658
#define AUTH_TOKEN_EXPIRED
Auth-token sent from client has expired.
Definition ssl_common.h:660
#define AUTH_TOKEN_VALID_EMPTYUSER
Auth-token is only valid for an empty username and not the username actually supplied from the client...
Definition ssl_common.h:662
internal structure similar to struct key that holds key information but is not represented on wire an...
Definition crypto.h:162
Security parameter state of one TLS and data channel key session.
Definition ssl_common.h:200
unsigned int auth_token_state_flags
The state of the auth-token sent from the client.
Definition ssl_common.h:203
const char * digest
Message digest static parameters.
Definition crypto.h:143
Container for unidirectional cipher and HMAC key material.
Definition crypto.h:152
uint8_t hmac[MAX_HMAC_KEY_LENGTH]
Key material for HMAC operations.
Definition crypto.h:155
struct user_pass up
struct tls_multi multi
struct tls_session * session
struct key_type kt
Security parameter state for a single VPN tunnel.
Definition ssl_common.h:597
char * auth_token_initial
The first auth-token we sent to a client.
Definition ssl_common.h:654
struct tls_options opt
Definition ssl_common.h:602
struct tls_session session[TM_SIZE]
Array of tls_session objects representing control channel sessions with the remote peer.
Definition ssl_common.h:681
char * auth_token
If server sends a generated auth-token, this is the token to use for future user/pass authentications...
Definition ssl_common.h:650
struct key_ctx auth_token_key
Definition ssl_common.h:399
unsigned int auth_token_renewal
Definition ssl_common.h:397
unsigned int auth_token_lifetime
Definition ssl_common.h:396
interval_t renegotiate_seconds
Definition ssl_common.h:339
bool auth_token_generate
Generate auth-tokens on successful user/pass auth,seet via options->auth_token_generate.
Definition ssl_common.h:392
Security parameter state of a single session within a VPN tunnel.
Definition ssl_common.h:480
struct key_state key[KS_SIZE]
Definition ssl_common.h:515
struct tls_options * opt
Definition ssl_common.h:482
char password[USER_PASS_LEN]
Definition misc.h:73
char username[USER_PASS_LEN]
Definition misc.h:72
static void auth_token_test_env(void **state)
static int teardown(void **state)
void auth_set_client_reason(struct tls_multi *multi, const char *reason)
Sets the reason why authentication of a client failed.
static void auth_token_test_known_keys(void **state)
static const char * zeroinline
static void auth_token_test_key_load(void **state)
static const char * random_token
static const char * now0key0
static void auth_token_test_timeout(void **state)
static void auth_token_test_random_keys(void **state)
void auth_token_test_session_mismatch(void **state)
static void auth_token_test_empty_user(void **state)
int main(void)
void setenv_str(struct env_set *es, const char *name, const char *value)
static void auth_token_fail_invalid_key(void **state)
static const char * random_key
static int setup(void **state)
static const char * lastsesion_statevalue
static void auth_token_basic_test(void **state)
static const char * allx01inline
static void zerohmac(char *token)
void send_push_reply_auth_token(struct tls_multi *multi)
Sends a push reply message only containin the auth-token to update the auth-token on the client.
static void openvpn_unit_test_setup(void)
Sets up the environment for unit tests like making both stderr and stdout non-buffered to avoid messa...
Definition test_common.h:36
struct env_set * es