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 
40 struct test_context {
41  struct tls_multi multi;
42  struct key_type kt;
43  struct user_pass up;
45 };
46 
47 /* Dummy functions that do nothing to mock the functionality */
48 void
50 {
51 }
52 
53 void
54 auth_set_client_reason(struct tls_multi *multi, const char *reason)
55 {
56 
57 }
58 
59 static const char *now0key0 = "SESS_ID_AT_0123456789abcdefAAAAAAAAAAAAAAAAAAAAAE5JsQJOVfo8jnI3RL3tBaR5NkE4yPfcylFUHmHSc5Bu";
60 
61 static 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 
67 static 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 
73 static 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 
81 static const char *random_token = "SESS_ID_AT_ThhRItzOKNKrh3dfAAAAAFwzHpwAAAAAXDMenDdrq0RoH3dkA1f7O3wO+7kZcx2DusVZrRmFlWQM9HOb";
82 
83 
84 static int
85 setup(void **state)
86 {
87  struct test_context *ctx = calloc(1, sizeof(*ctx));
88  *state = ctx;
89 
90  struct key key = { 0 };
91 
92  ctx->kt = auth_token_kt();
93  if (!ctx->kt.digest)
94  {
95  return 0;
96  }
97  ctx->multi.opt.auth_token_generate = true;
98  ctx->multi.opt.auth_token_lifetime = 3000;
99  ctx->session = &ctx->multi.session[TM_ACTIVE];
100 
101  ctx->session->opt = calloc(1, sizeof(struct tls_options));
102  ctx->session->opt->renegotiate_seconds = 240;
103  ctx->session->opt->auth_token_renewal = 120;
104  ctx->session->opt->auth_token_lifetime = 3000;
105 
106  strcpy(ctx->up.username, "test user name");
107  strcpy(ctx->up.password, "ignored");
108 
109  init_key_ctx(&ctx->multi.opt.auth_token_key, &key, &ctx->kt, false, "TEST");
110 
111  now = 0;
112  return 0;
113 }
114 
115 static int
116 teardown(void **state)
117 {
118  struct test_context *ctx = (struct test_context *) *state;
119 
121  wipe_auth_token(&ctx->multi);
122 
123  free(ctx->session->opt);
124  free(ctx);
125 
126  return 0;
127 }
128 
129 static void
131 {
132  struct test_context *ctx = (struct test_context *) *state;
133 
134  generate_auth_token(&ctx->up, &ctx->multi);
135  strcpy(ctx->up.password, ctx->multi.auth_token);
136  assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session),
138 }
139 
140 static void
142 {
143  struct test_context *ctx = (struct test_context *) *state;
144 
145  generate_auth_token(&ctx->up, &ctx->multi);
146  strcpy(ctx->up.password, ctx->multi.auth_token);
147  assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session),
149 
150  /* Change auth-token key */
151  struct key key;
152  memset(&key, '1', sizeof(key));
154  init_key_ctx(&ctx->multi.opt.auth_token_key, &key, &ctx->kt, false, "TEST");
155 
156  assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session), 0);
157 
158  /* Load original test key again */
159  memset(&key, 0, sizeof(key));
161  init_key_ctx(&ctx->multi.opt.auth_token_key, &key, &ctx->kt, false, "TEST");
162  assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session),
164 
165 }
166 
167 static void
169 {
170  struct test_context *ctx = (struct test_context *) *state;
171 
172  now = 100000;
173  generate_auth_token(&ctx->up, &ctx->multi);
174 
175  strcpy(ctx->up.password, ctx->multi.auth_token);
176  free(ctx->multi.auth_token_initial);
177  ctx->multi.auth_token_initial = NULL;
178 
179  /* No time has passed */
180  assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session),
182 
183  /* Token before validity, should be rejected */
184  now = 100000 - 100;
185  assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session),
187 
188  /* Token no valid for renegotiate_seconds but still for renewal_time */
189  now = 100000 + 2*ctx->session->opt->renegotiate_seconds - 20;
190  assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session),
192 
193 
194  now = 100000 + 2*ctx->session->opt->auth_token_renewal - 20;
195  assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session),
197 
198  /* Token past validity, should be rejected */
199  now = 100000 + 2*ctx->session->opt->renegotiate_seconds + 20;
200  assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session),
202 
203  /* But not when we reached our timeout */
204  now = 100000 + ctx->session->opt->auth_token_lifetime + 1;
205  assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session),
207 
208  free(ctx->multi.auth_token_initial);
209  ctx->multi.auth_token_initial = NULL;
210 
211  /* regenerate the token util it hits the expiry */
212  now = 100000;
213  while (now < 100000 + ctx->session->opt->auth_token_lifetime + 1)
214  {
215  assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session),
217  generate_auth_token(&ctx->up, &ctx->multi);
218  strcpy(ctx->up.password, ctx->multi.auth_token);
219  now += ctx->session->opt->auth_token_renewal;
220  }
221 
222 
223  assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session),
225  ctx->multi.opt.auth_token_lifetime = 0;
226 
227  /* Non expiring token should be fine */
228  assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session),
230 }
231 
232 static void
233 zerohmac(char *token)
234 {
235  char *hmacstart = token + AUTH_TOKEN_SESSION_ID_LEN
236  + strlen(SESSION_ID_PREFIX) + 2*sizeof(uint64_t);
237  memset(hmacstart, 0x8d, strlen(hmacstart));
238 }
239 
240 static void
242 {
243  struct test_context *ctx = (struct test_context *) *state;
244 
245  now = 0;
246  /* Preload the session id so the same session id is used here */
247  ctx->multi.auth_token_initial = strdup(now0key0);
248 
249  /* Zero the hmac part to ensure we have a newly generated token */
251 
252  generate_auth_token(&ctx->up, &ctx->multi);
253 
254  assert_string_equal(now0key0, ctx->multi.auth_token);
255 
256  strcpy(ctx->up.password, ctx->multi.auth_token);
257  assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session),
259 }
260 
261 static const char *lastsesion_statevalue;
262 void
263 setenv_str(struct env_set *es, const char *name, const char *value)
264 {
265  if (streq(name, "session_state"))
266  {
267  lastsesion_statevalue = value;
268  }
269 }
270 
271 void
273 {
274  struct test_context *ctx = (struct test_context *) *state;
275 
276  /* Generate first auth token and check it is correct */
277  generate_auth_token(&ctx->up, &ctx->multi);
278  strcpy(ctx->up.password, ctx->multi.auth_token);
279  assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session),
281 
282  char *token_sessiona = strdup(ctx->multi.auth_token);
283 
284  /* Generate second token */
285  wipe_auth_token(&ctx->multi);
286 
287  generate_auth_token(&ctx->up, &ctx->multi);
288  strcpy(ctx->up.password, ctx->multi.auth_token);
289  assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session),
291 
292  assert_int_not_equal(0, memcmp(ctx->multi.auth_token_initial + strlen(SESSION_ID_PREFIX),
293  token_sessiona + strlen(SESSION_ID_PREFIX),
295 
296  /* The first token is valid but should trigger the invalid response since
297  * the session id is not the same */
298  strcpy(ctx->up.password, token_sessiona);
299  assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session), 0);
300  free(token_sessiona);
301 }
302 
303 static void
305 {
306  struct test_context *ctx = (struct test_context *) *state;
307 
308  CLEAR(ctx->up.username);
309  now = 0;
310 
311  generate_auth_token(&ctx->up, &ctx->multi);
312  strcpy(ctx->up.password, ctx->multi.auth_token);
313  assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session),
315 
316  now = 100000;
317  assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session),
319  strcpy(ctx->up.username, "test user name");
320 
321  now = 0;
322  assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session),
324 
325  strcpy(ctx->up.username, "test user name");
326  now = 100000;
327  assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session),
329 
330  zerohmac(ctx->up.password);
331  assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session),
332  0);
333 }
334 
335 static void
336 auth_token_test_env(void **state)
337 {
338  struct test_context *ctx = (struct test_context *) *state;
339 
340  struct key_state *ks = &ctx->multi.session[TM_ACTIVE].key[KS_PRIMARY];
341 
342  ks->auth_token_state_flags = 0;
343  ctx->multi.auth_token = NULL;
344  add_session_token_env(ctx->session, &ctx->multi, &ctx->up);
345  assert_string_equal(lastsesion_statevalue, "Initial");
346 
347  ks->auth_token_state_flags = 0;
348  strcpy(ctx->up.password, now0key0);
349  add_session_token_env(ctx->session, &ctx->multi, &ctx->up);
350  assert_string_equal(lastsesion_statevalue, "Invalid");
351 
353  add_session_token_env(ctx->session, &ctx->multi, &ctx->up);
354  assert_string_equal(lastsesion_statevalue, "Authenticated");
355 
357  add_session_token_env(ctx->session, &ctx->multi, &ctx->up);
358  assert_string_equal(lastsesion_statevalue, "Expired");
359 
361  add_session_token_env(ctx->session, &ctx->multi, &ctx->up);
362  assert_string_equal(lastsesion_statevalue, "AuthenticatedEmptyUser");
363 
365  add_session_token_env(ctx->session, &ctx->multi, &ctx->up);
366  assert_string_equal(lastsesion_statevalue, "ExpiredEmptyUser");
367 }
368 
369 static void
371 {
372  struct test_context *ctx = (struct test_context *) *state;
373 
374  now = 0x5c331e9c;
375  /* Preload the session id so the same session id is used here */
376  ctx->multi.auth_token_initial = strdup(random_token);
377 
380 
381  /* Zero the hmac part to ensure we have a newly generated token */
383 
384  generate_auth_token(&ctx->up, &ctx->multi);
385 
386  assert_string_equal(random_token, ctx->multi.auth_token);
387 
388  strcpy(ctx->up.password, ctx->multi.auth_token);
389  assert_true(verify_auth_token(&ctx->up, &ctx->multi, ctx->session));
390 }
391 
392 
393 static void
395 {
396  struct test_context *ctx = (struct test_context *) *state;
397 
400  strcpy(ctx->up.password, now0key0);
401  assert_true(verify_auth_token(&ctx->up, &ctx->multi, ctx->session));
402 
405  assert_false(verify_auth_token(&ctx->up, &ctx->multi, ctx->session));
406 }
407 
408 int
409 main(void)
410 {
412  const struct CMUnitTest tests[] = {
413  cmocka_unit_test_setup_teardown(auth_token_basic_test, setup, teardown),
414  cmocka_unit_test_setup_teardown(auth_token_fail_invalid_key, setup, teardown),
415  cmocka_unit_test_setup_teardown(auth_token_test_known_keys, setup, teardown),
416  cmocka_unit_test_setup_teardown(auth_token_test_empty_user, setup, teardown),
417  cmocka_unit_test_setup_teardown(auth_token_test_env, setup, teardown),
418  cmocka_unit_test_setup_teardown(auth_token_test_random_keys, setup, teardown),
419  cmocka_unit_test_setup_teardown(auth_token_test_key_load, setup, teardown),
420  cmocka_unit_test_setup_teardown(auth_token_test_timeout, setup, teardown),
421  cmocka_unit_test_setup_teardown(auth_token_test_session_mismatch, setup, teardown)
422  };
423 
424 #if defined(ENABLE_CRYPTO_OPENSSL)
425  OpenSSL_add_all_algorithms();
426 #endif
427 
428  int ret = cmocka_run_group_tests_name("auth-token tests", tests, NULL, NULL);
429 
430  return ret;
431 }
SESSION_ID_PREFIX
#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
random_token
static const char * random_token
Definition: test_auth_token.c:81
tls_multi::auth_token
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:641
key_state::auth_token_state_flags
unsigned int auth_token_state_flags
The state of the auth-token sent from the client.
Definition: ssl_common.h:199
tls_session::opt
struct tls_options * opt
Definition: ssl_common.h:471
verify_auth_token
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:297
openvpn_unit_test_setup
static void openvpn_unit_test_setup()
Sets up the environment for unit tests like making both stderr and stdout non-buffered to avoid messa...
Definition: test_common.h:36
streq
#define streq(x, y)
Definition: options.h:708
KS_PRIMARY
#define KS_PRIMARY
Primary key state index.
Definition: ssl_common.h:445
test_context::up
struct user_pass up
Definition: test_auth_token.c:43
es
struct env_set * es
Definition: test_pkcs11.c:133
random_key
static const char * random_key
Definition: test_auth_token.c:73
test_common.h
tls_multi::session
struct tls_session session[TM_SIZE]
Array of tls_session objects representing control channel sessions with the remote peer.
Definition: ssl_common.h:672
add_session_token_env
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
tls_options::auth_token_key
struct key_ctx auth_token_key
Definition: ssl_common.h:388
user_pass::username
char username[USER_PASS_LEN]
Definition: misc.h:71
auth_token.c
test_context
Definition: test_auth_token.c:40
auth_token_test_empty_user
static void auth_token_test_empty_user(void **state)
Definition: test_auth_token.c:304
setup
static int setup(void **state)
Definition: test_auth_token.c:85
tls_options::renegotiate_seconds
interval_t renegotiate_seconds
Definition: ssl_common.h:333
tls_multi
Security parameter state for a single VPN tunnel.
Definition: ssl_common.h:587
auth_token_test_env
static void auth_token_test_env(void **state)
Definition: test_auth_token.c:336
key_state
Security parameter state of one TLS and data channel key session.
Definition: ssl_common.h:195
key
Container for unidirectional cipher and HMAC key material.
Definition: crypto.h:149
tls_options::auth_token_renewal
unsigned int auth_token_renewal
Definition: ssl_common.h:386
auth_token_test_key_load
static void auth_token_test_key_load(void **state)
Definition: test_auth_token.c:394
tls_options::auth_token_generate
bool auth_token_generate
Generate auth-tokens on successful user/pass auth,seet via options->auth_token_generate.
Definition: ssl_common.h:381
CLEAR
#define CLEAR(x)
Definition: basic.h:33
AUTH_TOKEN_VALID_EMPTYUSER
#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:653
main
int main(void)
Definition: test_auth_token.c:409
TM_ACTIVE
#define TM_ACTIVE
Active tls_session.
Definition: ssl_common.h:526
AUTH_TOKEN_SESSION_ID_LEN
#define AUTH_TOKEN_SESSION_ID_LEN
Definition: auth_token.c:21
allx01inline
static const char * allx01inline
Definition: test_auth_token.c:67
tls_options
Definition: ssl_common.h:293
auth_token_test_known_keys
static void auth_token_test_known_keys(void **state)
Definition: test_auth_token.c:241
key_type::digest
const char * digest
Message digest static parameters.
Definition: crypto.h:142
auth_token_test_session_mismatch
void auth_token_test_session_mismatch(void **state)
Definition: test_auth_token.c:272
tls_session::key
struct key_state key[KS_SIZE]
Definition: ssl_common.h:506
tls_multi::opt
struct tls_options opt
Definition: ssl_common.h:593
init_key_ctx
void init_key_ctx(struct key_ctx *ctx, const struct key *key, const struct key_type *kt, int enc, const char *prefix)
Definition: crypto.c:824
now0key0
static const char * now0key0
Definition: test_auth_token.c:59
AUTH_TOKEN_SESSION_ID_BASE64_LEN
#define AUTH_TOKEN_SESSION_ID_BASE64_LEN
Definition: auth_token.c:22
setenv_str
void setenv_str(struct env_set *es, const char *name, const char *value)
Definition: test_auth_token.c:263
auth_token_init_secret
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
auth_token_kt
static struct key_type auth_token_kt(void)
Definition: auth_token.c:32
key_type
Definition: crypto.h:139
tls_session
Security parameter state of a single session within a VPN tunnel.
Definition: ssl_common.h:468
key_state::state
int state
Definition: ssl_common.h:197
generate_auth_token
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:161
auth_token_test_random_keys
static void auth_token_test_random_keys(void **state)
Definition: test_auth_token.c:370
auth_set_client_reason
void auth_set_client_reason(struct tls_multi *multi, const char *reason)
Sets the reason why authentication of a client failed.
Definition: test_auth_token.c:54
syshead.h
zeroinline
static const char * zeroinline
Definition: test_auth_token.c:61
env_set
Definition: env_set.h:42
tls_options::auth_token_lifetime
unsigned int auth_token_lifetime
Definition: ssl_common.h:385
zerohmac
static void zerohmac(char *token)
Definition: test_auth_token.c:233
free_key_ctx
void free_key_ctx(struct key_ctx *ctx)
Definition: crypto.c:889
AUTH_TOKEN_HMAC_OK
#define AUTH_TOKEN_HMAC_OK
Auth-token sent from client has valid hmac.
Definition: ssl_common.h:649
auth_token_test_timeout
static void auth_token_test_timeout(void **state)
Definition: test_auth_token.c:168
AUTH_TOKEN_EXPIRED
#define AUTH_TOKEN_EXPIRED
Auth-token sent from client has expired.
Definition: ssl_common.h:651
teardown
static int teardown(void **state)
Definition: test_auth_token.c:116
test_context::kt
struct key_type kt
Definition: test_auth_token.c:42
auth_token_basic_test
static void auth_token_basic_test(void **state)
Definition: test_auth_token.c:130
auth_token_fail_invalid_key
static void auth_token_fail_invalid_key(void **state)
Definition: test_auth_token.c:141
now
time_t now
Definition: otime.c:34
wipe_auth_token
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:403
test_context::multi
struct tls_multi multi
Definition: test_auth_token.c:41
config.h
user_pass::password
char password[USER_PASS_LEN]
Definition: misc.h:72
session
Definition: keyingmaterialexporter.c:56
test_context::session
struct tls_session * session
Definition: test_auth_token.c:44
tls_multi::auth_token_initial
char * auth_token_initial
The first auth-token we sent to a client.
Definition: ssl_common.h:645
send_push_reply_auth_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.
Definition: test_auth_token.c:49
user_pass
Definition: misc.h:56
lastsesion_statevalue
static const char * lastsesion_statevalue
Definition: test_auth_token.c:261