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 #elif defined(_MSC_VER)
27 #include "config-msvc.h"
28 #endif
29 
30 #include "syshead.h"
31 
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <stdarg.h>
35 #include <string.h>
36 #include <setjmp.h>
37 #include <cmocka.h>
38 
39 #include "auth_token.c"
40 
41 #include "mock_msg.h"
42 
43 struct test_context {
44  struct tls_multi multi;
45  struct key_type kt;
46  struct user_pass up;
48 };
49 
50 /* Dummy functions that do nothing to mock the functionality */
51 void
53 {
54 }
55 
56 void
57 auth_set_client_reason(struct tls_multi *multi, const char *reason)
58 {
59 
60 }
61 
62 static const char *now0key0 = "SESS_ID_AT_0123456789abcdefAAAAAAAAAAAAAAAAAAAAAE5JsQJOVfo8jnI3RL3tBaR5NkE4yPfcylFUHmHSc5Bu";
63 
64 static const char *zeroinline = "-----BEGIN OpenVPN auth-token server key-----\n"
65  "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
66  "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
67  "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\n"
68  "-----END OpenVPN auth-token server key-----";
69 
70 static const char *allx01inline = "-----BEGIN OpenVPN auth-token server key-----\n"
71  "AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEB\n"
72  "AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEB\n"
73  "AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQE=\n"
74  "-----END OpenVPN auth-token server key-----";
75 
76 static const char *random_key = "-----BEGIN OpenVPN auth-token server key-----\n"
77  "+mmmf7IQ5cymtMVjKYTWk8IOcYanRlpQmV9Tb3EjkHYxueBVDg3yqRgzeBlVGzNLD//rAPiOVhau\n"
78  "3NDBjNOQB8951bfs7Cc2mYfay92Bh2gRJ5XEM/DMfzCWN+7uU6NWoTTHr4FuojnIQtjtqVAj/JS9\n"
79  "w+dTSp/vYHl+c7uHd19uVRu/qLqV85+rm4tUGIjO7FfYuwyPqwmhuIsi3hs9QkSimh888FmBpoKY\n"
80  "/tbKVTJZmSERKti9KEwtV2eVAR0znN5KW7lCB3mHVAhN7bUpcoDjfCzYIFARxwswTFu9gFkwqUMY\n"
81  "I1KUOgIsVNs4llACioeXplYekWETR+YkJwDc/A==\n"
82  "-----END OpenVPN auth-token server key-----";
83 
84 static const char *random_token = "SESS_ID_AT_ThhRItzOKNKrh3dfAAAAAFwzHpwAAAAAXDMenDdrq0RoH3dkA1f7O3wO+7kZcx2DusVZrRmFlWQM9HOb";
85 
86 
87 static int
88 setup(void **state)
89 {
90  struct test_context *ctx = calloc(1, sizeof(*ctx));
91  *state = ctx;
92 
93  struct key key = { 0 };
94 
95  ctx->kt = auth_token_kt();
96  if (!ctx->kt.digest)
97  {
98  return 0;
99  }
100  ctx->multi.opt.auth_token_generate = true;
101  ctx->multi.opt.auth_token_lifetime = 3000;
102  ctx->session = &ctx->multi.session[TM_ACTIVE];
103 
104  ctx->session->opt = calloc(1, sizeof(struct tls_options));
105  ctx->session->opt->renegotiate_seconds = 120;
106  ctx->session->opt->auth_token_lifetime = 3000;
107 
108  strcpy(ctx->up.username, "test user name");
109  strcpy(ctx->up.password, "ignored");
110 
111  init_key_ctx(&ctx->multi.opt.auth_token_key, &key, &ctx->kt, false, "TEST");
112 
113  now = 0;
114  return 0;
115 }
116 
117 static int
118 teardown(void **state)
119 {
120  struct test_context *ctx = (struct test_context *) *state;
121 
123  wipe_auth_token(&ctx->multi);
124 
125  free(ctx->session->opt);
126  free(ctx);
127 
128  return 0;
129 }
130 
131 static void
133 {
134  struct test_context *ctx = (struct test_context *) *state;
135 
136  generate_auth_token(&ctx->up, &ctx->multi);
137  strcpy(ctx->up.password, ctx->multi.auth_token);
138  assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session),
140 }
141 
142 static void
144 {
145  struct test_context *ctx = (struct test_context *) *state;
146 
147  generate_auth_token(&ctx->up, &ctx->multi);
148  strcpy(ctx->up.password, ctx->multi.auth_token);
149  assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session),
151 
152  /* Change auth-token key */
153  struct key key;
154  memset(&key, '1', sizeof(key));
156  init_key_ctx(&ctx->multi.opt.auth_token_key, &key, &ctx->kt, false, "TEST");
157 
158  assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session), 0);
159 
160  /* Load original test key again */
161  memset(&key, 0, sizeof(key));
163  init_key_ctx(&ctx->multi.opt.auth_token_key, &key, &ctx->kt, false, "TEST");
164  assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session),
166 
167 }
168 
169 static void
171 {
172  struct test_context *ctx = (struct test_context *) *state;
173 
174  now = 100000;
175  generate_auth_token(&ctx->up, &ctx->multi);
176 
177  strcpy(ctx->up.password, ctx->multi.auth_token);
179  ctx->multi.auth_token_initial = NULL;
180 
181  /* No time has passed */
182  assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session),
184 
185  /* Token before validity, should be rejected */
186  now = 100000 - 100;
187  assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session),
189 
190  /* Token still in validity, should be accepted */
191  now = 100000 + 2*ctx->session->opt->renegotiate_seconds - 20;
192  assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session),
194 
195  /* Token past validity, should be rejected */
196  now = 100000 + 2*ctx->session->opt->renegotiate_seconds + 20;
197  assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session),
199 
200  /* But not when we reached our timeout */
201  now = 100000 + ctx->session->opt->auth_token_lifetime + 1;
202  assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session),
204 
206  ctx->multi.auth_token_initial = NULL;
207 
208  /* regenerate the token util it hits the expiry */
209  now = 100000;
210  while (now < 100000 + ctx->session->opt->auth_token_lifetime + 1)
211  {
212  assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session),
214  generate_auth_token(&ctx->up, &ctx->multi);
215  strcpy(ctx->up.password, ctx->multi.auth_token);
217  }
218 
219 
220  assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session),
222  ctx->multi.opt.auth_token_lifetime = 0;
223 
224  /* Non expiring token should be fine */
225  assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session),
227 }
228 
229 static void
230 zerohmac(char *token)
231 {
232  char *hmacstart = token + AUTH_TOKEN_SESSION_ID_LEN
233  + strlen(SESSION_ID_PREFIX) + 2*sizeof(uint64_t);
234  memset(hmacstart, 0x8d, strlen(hmacstart));
235 }
236 
237 static void
239 {
240  struct test_context *ctx = (struct test_context *) *state;
241 
242  now = 0;
243  /* Preload the session id so the same session id is used here */
244  ctx->multi.auth_token_initial = strdup(now0key0);
245 
246  /* Zero the hmac part to ensure we have a newly generated token */
248 
249  generate_auth_token(&ctx->up, &ctx->multi);
250 
252 
253  strcpy(ctx->up.password, ctx->multi.auth_token);
254  assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session),
256 }
257 
258 static const char *lastsesion_statevalue;
259 void
260 setenv_str(struct env_set *es, const char *name, const char *value)
261 {
262  if (streq(name, "session_state"))
263  {
264  lastsesion_statevalue = value;
265  }
266 }
267 
268 void
270 {
271  struct test_context *ctx = (struct test_context *) *state;
272 
273  /* Generate first auth token and check it is correct */
274  generate_auth_token(&ctx->up, &ctx->multi);
275  strcpy(ctx->up.password, ctx->multi.auth_token);
276  assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session),
278 
279  char *token_sessiona = strdup(ctx->multi.auth_token);
280 
281  /* Generate second token */
282  wipe_auth_token(&ctx->multi);
283 
284  generate_auth_token(&ctx->up, &ctx->multi);
285  strcpy(ctx->up.password, ctx->multi.auth_token);
286  assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session),
288 
290  token_sessiona + strlen(SESSION_ID_PREFIX),
292 
293  /* The first token is valid but should trigger the invalid response since
294  * the session id is not the same */
295  strcpy(ctx->up.password, token_sessiona);
296  assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session), 0);
297  free(token_sessiona);
298 }
299 
300 static void
302 {
303  struct test_context *ctx = (struct test_context *) *state;
304 
305  CLEAR(ctx->up.username);
306  now = 0;
307 
308  generate_auth_token(&ctx->up, &ctx->multi);
309  strcpy(ctx->up.password, ctx->multi.auth_token);
310  assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session),
312 
313  now = 100000;
314  assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session),
316  strcpy(ctx->up.username, "test user name");
317 
318  now = 0;
319  assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session),
321 
322  strcpy(ctx->up.username, "test user name");
323  now = 100000;
324  assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session),
326 
327  zerohmac(ctx->up.password);
328  assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, ctx->session),
329  0);
330 }
331 
332 static void
333 auth_token_test_env(void **state)
334 {
335  struct test_context *ctx = (struct test_context *) *state;
336 
337  struct key_state *ks = &ctx->multi.session[TM_ACTIVE].key[KS_PRIMARY];
338 
339  ks->auth_token_state_flags = 0;
340  ctx->multi.auth_token = NULL;
341  add_session_token_env(ctx->session, &ctx->multi, &ctx->up);
343 
344  ks->auth_token_state_flags = 0;
345  strcpy(ctx->up.password, now0key0);
346  add_session_token_env(ctx->session, &ctx->multi, &ctx->up);
348 
350  add_session_token_env(ctx->session, &ctx->multi, &ctx->up);
351  assert_string_equal(lastsesion_statevalue, "Authenticated");
352 
354  add_session_token_env(ctx->session, &ctx->multi, &ctx->up);
356 
358  add_session_token_env(ctx->session, &ctx->multi, &ctx->up);
359  assert_string_equal(lastsesion_statevalue, "AuthenticatedEmptyUser");
360 
362  add_session_token_env(ctx->session, &ctx->multi, &ctx->up);
363  assert_string_equal(lastsesion_statevalue, "ExpiredEmptyUser");
364 }
365 
366 static void
368 {
369  struct test_context *ctx = (struct test_context *) *state;
370 
371  now = 0x5c331e9c;
372  /* Preload the session id so the same session id is used here */
373  ctx->multi.auth_token_initial = strdup(random_token);
374 
377 
378  /* Zero the hmac part to ensure we have a newly generated token */
380 
381  generate_auth_token(&ctx->up, &ctx->multi);
382 
384 
385  strcpy(ctx->up.password, ctx->multi.auth_token);
386  assert_true(verify_auth_token(&ctx->up, &ctx->multi, ctx->session));
387 }
388 
389 
390 static void
392 {
393  struct test_context *ctx = (struct test_context *) *state;
394 
397  strcpy(ctx->up.password, now0key0);
398  assert_true(verify_auth_token(&ctx->up, &ctx->multi, ctx->session));
399 
402  assert_false(verify_auth_token(&ctx->up, &ctx->multi, ctx->session));
403 }
404 
405 int
406 main(void)
407 {
408  const struct CMUnitTest tests[] = {
418  };
419 
420 #if defined(ENABLE_CRYPTO_OPENSSL)
421  OpenSSL_add_all_algorithms();
422 #endif
423 
424  int ret = cmocka_run_group_tests_name("auth-token tests", tests, NULL, NULL);
425 
426  return ret;
427 }
void auth_token_test_session_mismatch(void **state)
#define assert_true(c)
Definition: cmocka.h:1045
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:54
#define TM_ACTIVE
Active tls_session.
Definition: ssl_common.h:508
Security parameter state of one TLS and data channel key session.
Definition: ssl_common.h:203
void free_key_ctx(struct key_ctx *ctx)
Definition: crypto.c:887
struct key_state key[KS_SIZE]
Definition: ssl_common.h:488
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:177
static const char * lastsesion_statevalue
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:819
unsigned int auth_token_lifetime
Definition: ssl_common.h:373
#define streq(x, y)
Definition: options.h:667
static void auth_token_fail_invalid_key(void **state)
#define AUTH_TOKEN_EXPIRED
Auth-token sent from client has expired.
Definition: ssl_common.h:630
struct tls_options * opt
Definition: ssl_common.h:457
#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
struct tls_session * session
char * auth_token_initial
The first auth-token we sent to a client.
Definition: ssl_common.h:624
Security parameter state for a single VPN tunnel.
Definition: ssl_common.h:566
static void auth_token_test_key_load(void **state)
int main(void)
static void zerohmac(char *token)
static const char * now0key0
#define AUTH_TOKEN_SESSION_ID_LEN
Definition: auth_token.c:23
static int setup(void **state)
bool auth_token_generate
Generate auth-tokens on successful user/pass auth,seet via options->auth_token_generate.
Definition: ssl_common.h:369
void auth_set_client_reason(struct tls_multi *multi, const char *reason)
Sets the reason why authentication of a client failed.
int auth_token_state_flags
The state of the auth-token sent from the client.
Definition: ssl_common.h:207
struct tls_session session[TM_SIZE]
Array of tls_session objects representing control channel sessions with the remote peer...
Definition: ssl_common.h:651
char username[USER_PASS_LEN]
Definition: misc.h:70
static struct key_type auth_token_kt(void)
Definition: auth_token.c:34
static const char * allx01inline
static void auth_token_basic_test(void **state)
#define CLEAR(x)
Definition: basic.h:33
#define AUTH_TOKEN_HMAC_OK
Auth-token sent from client has valid hmac.
Definition: ssl_common.h:628
#define cmocka_run_group_tests_name(group_name, group_tests, group_setup, group_teardown)
Definition: cmocka.h:1818
#define assert_int_not_equal(a, b)
Definition: cmocka.h:1195
#define assert_string_equal(a, b)
Definition: cmocka.h:1214
void setenv_str(struct env_set *es, const char *name, const char *value)
interval_t renegotiate_seconds
Definition: ssl_common.h:323
#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:632
#define KS_PRIMARY
Primary key state index.
Definition: ssl_common.h:430
time_t now
Definition: otime.c:36
static void auth_token_test_timeout(void **state)
static void auth_token_test_empty_user(void **state)
static const char * random_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:411
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:313
static void auth_token_test_random_keys(void **state)
struct tls_options opt
Definition: ssl_common.h:572
static void auth_token_test_env(void **state)
static const char * zeroinline
static int teardown(void **state)
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:140
#define cmocka_unit_test_setup_teardown(f, setup, teardown)
Initialize an array of CMUnitTest structures with a setup function for a test and a teardown function...
Definition: cmocka.h:1665
struct key_ctx auth_token_key
Definition: ssl_common.h:375
struct tls_multi multi
static void auth_token_test_known_keys(void **state)
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:620
const md_kt_t * digest
Message digest static parameters.
Definition: crypto.h:144
Security parameter state of a single session within a VPN tunnel.
Definition: ssl_common.h:454
Definition: misc.h:56
struct key_type kt
static const char * random_key
#define free
Definition: cmocka.c:1850
struct user_pass up
char password[USER_PASS_LEN]
Definition: misc.h:71
#define assert_false(c)
Definition: cmocka.h:1063
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...
#define AUTH_TOKEN_SESSION_ID_BASE64_LEN
Definition: auth_token.c:24
#define assert_int_equal(a, b)
Definition: cmocka.h:1174
Container for unidirectional cipher and HMAC key material.
Definition: crypto.h:151