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-2018 Fox Crypto B.V. <openvpn@fox-it.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 <unistd.h>
34 #include <stdlib.h>
35 #include <stdarg.h>
36 #include <string.h>
37 #include <setjmp.h>
38 #include <cmocka.h>
39 
40 #include "auth_token.c"
41 
42 #include "mock_msg.h"
43 
44 struct test_context {
45  struct tls_multi multi;
46  struct key_type kt;
47  struct user_pass up;
49 };
50 
51 /* Dummy functions that do nothing to mock the functionality */
52 void
54 {
55 }
56 
57 void
58 auth_set_client_reason(struct tls_multi *multi, const char *reason)
59 {
60 
61 }
62 
63 static const char *now0key0 = "SESS_ID_AT_0123456789abcdefAAAAAAAAAAAAAAAAAAAAAE5JsQJOVfo8jnI3RL3tBaR5NkE4yPfcylFUHmHSc5Bu";
64 
65 static const char *zeroinline = "-----BEGIN OpenVPN auth-token server key-----\n"
66  "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
67  "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
68  "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\n"
69  "-----END OpenVPN auth-token server key-----";
70 
71 static const char *allx01inline = "-----BEGIN OpenVPN auth-token server key-----\n"
72  "AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEB\n"
73  "AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEB\n"
74  "AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQE=\n"
75  "-----END OpenVPN auth-token server key-----";
76 
77 static const char *random_key = "-----BEGIN OpenVPN auth-token server key-----\n"
78  "+mmmf7IQ5cymtMVjKYTWk8IOcYanRlpQmV9Tb3EjkHYxueBVDg3yqRgzeBlVGzNLD//rAPiOVhau\n"
79  "3NDBjNOQB8951bfs7Cc2mYfay92Bh2gRJ5XEM/DMfzCWN+7uU6NWoTTHr4FuojnIQtjtqVAj/JS9\n"
80  "w+dTSp/vYHl+c7uHd19uVRu/qLqV85+rm4tUGIjO7FfYuwyPqwmhuIsi3hs9QkSimh888FmBpoKY\n"
81  "/tbKVTJZmSERKti9KEwtV2eVAR0znN5KW7lCB3mHVAhN7bUpcoDjfCzYIFARxwswTFu9gFkwqUMY\n"
82  "I1KUOgIsVNs4llACioeXplYekWETR+YkJwDc/A==\n"
83  "-----END OpenVPN auth-token server key-----";
84 
85 static const char *random_token = "SESS_ID_AT_ThhRItzOKNKrh3dfAAAAAFwzHpwAAAAAXDMenDdrq0RoH3dkA1f7O3wO+7kZcx2DusVZrRmFlWQM9HOb";
86 
87 
88 static int
89 setup(void **state)
90 {
91  struct test_context *ctx = calloc(1, sizeof(*ctx));
92  *state = ctx;
93 
94  struct key key = { 0 };
95 
96  ctx->kt = auth_token_kt();
97  if (!ctx->kt.digest)
98  {
99  return 0;
100  }
101  ctx->multi.opt.auth_token_generate = true;
102  ctx->multi.opt.auth_token_lifetime = 3000;
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  strcpy(ctx->up.password, ctx->multi.auth_token);
177 
178  /* No time has passed */
179  assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, &ctx->session),
181 
182  /* Token before validity, should be rejected */
183  now = 100000 - 100;
184  assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, &ctx->session),
186 
187  /* Token still in validity, should be accepted */
188  now = 100000 + 2*ctx->session.opt->renegotiate_seconds - 20;
189  assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, &ctx->session),
191 
192  /* Token past validity, should be rejected */
193  now = 100000 + 2*ctx->session.opt->renegotiate_seconds + 20;
194  assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, &ctx->session),
196 
197  /* Check if the mode for a client that never updates its token works */
198  ctx->multi.auth_token_initial = strdup(ctx->up.password);
199  assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, &ctx->session),
201 
202  /* But not when we reached our timeout */
203  now = 100000 + ctx->session.opt->auth_token_lifetime + 1;
204  assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, &ctx->session),
206 
208  ctx->multi.auth_token_initial = NULL;
209 
210  /* regenerate the token util it hits the expiry */
211  now = 100000;
212  while (now < 100000 + ctx->session.opt->auth_token_lifetime + 1)
213  {
214  assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, &ctx->session),
216  generate_auth_token(&ctx->up, &ctx->multi);
217  strcpy(ctx->up.password, ctx->multi.auth_token);
219  }
220 
221 
222  assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, &ctx->session),
224  ctx->multi.opt.auth_token_lifetime = 0;
225 
226  /* Non expiring token should be fine */
227  assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, &ctx->session),
229 }
230 
231 static void
232 zerohmac(char *token)
233 {
234  char *hmacstart = token + AUTH_TOKEN_SESSION_ID_LEN
235  + strlen(SESSION_ID_PREFIX) + 2*sizeof(uint64_t);
236  memset(hmacstart, 0x8d, strlen(hmacstart));
237 }
238 
239 static void
241 {
242  struct test_context *ctx = (struct test_context *) *state;
243 
244  now = 0;
245  /* Preload the session id so the same session id is used here */
246  ctx->multi.auth_token = strdup(now0key0);
247 
248  /* Zero the hmac part to ensure we have a newly generated token */
249  zerohmac(ctx->multi.auth_token);
250 
251  generate_auth_token(&ctx->up, &ctx->multi);
252 
254 
255  strcpy(ctx->up.password, ctx->multi.auth_token);
256  assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, &ctx->session),
258 }
259 
260 static const char *lastsesion_statevalue;
261 void
262 setenv_str(struct env_set *es, const char *name, const char *value)
263 {
264  if (streq(name, "session_state"))
265  {
266  lastsesion_statevalue = value;
267  }
268 }
269 
270 static void
272 {
273  struct test_context *ctx = (struct test_context *) *state;
274 
275  CLEAR(ctx->up.username);
276  now = 0;
277 
278  generate_auth_token(&ctx->up, &ctx->multi);
279  strcpy(ctx->up.password, ctx->multi.auth_token);
280  assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, &ctx->session),
282 
283  now = 100000;
284  assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, &ctx->session),
286  strcpy(ctx->up.username, "test user name");
287 
288  now = 0;
289  assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, &ctx->session),
291 
292  strcpy(ctx->up.username, "test user name");
293  now = 100000;
294  assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, &ctx->session),
296 
297  zerohmac(ctx->up.password);
298  assert_int_equal(verify_auth_token(&ctx->up, &ctx->multi, &ctx->session),
299  0);
300 }
301 
302 static void
303 auth_token_test_env(void **state)
304 {
305  struct test_context *ctx = (struct test_context *) *state;
306 
307  ctx->multi.auth_token_state_flags = 0;
308  ctx->multi.auth_token = NULL;
309  add_session_token_env(&ctx->session, &ctx->multi, &ctx->up);
311 
312  ctx->multi.auth_token_state_flags = 0;
313  strcpy(ctx->up.password, now0key0);
314  add_session_token_env(&ctx->session, &ctx->multi, &ctx->up);
316 
318  add_session_token_env(&ctx->session, &ctx->multi, &ctx->up);
319  assert_string_equal(lastsesion_statevalue, "Authenticated");
320 
322  add_session_token_env(&ctx->session, &ctx->multi, &ctx->up);
324 
326  add_session_token_env(&ctx->session, &ctx->multi, &ctx->up);
327  assert_string_equal(lastsesion_statevalue, "AuthenticatedEmptyUser");
328 
330  add_session_token_env(&ctx->session, &ctx->multi, &ctx->up);
331  assert_string_equal(lastsesion_statevalue, "ExpiredEmptyUser");
332 }
333 
334 static void
336 {
337  struct test_context *ctx = (struct test_context *) *state;
338 
339  now = 0x5c331e9c;
340  /* Preload the session id so the same session id is used here */
341  ctx->multi.auth_token = strdup(random_token);
342 
345 
346  /* Zero the hmac part to ensure we have a newly generated token */
347  zerohmac(ctx->multi.auth_token);
348 
349  generate_auth_token(&ctx->up, &ctx->multi);
350 
352 
353  strcpy(ctx->up.password, ctx->multi.auth_token);
354  assert_true(verify_auth_token(&ctx->up, &ctx->multi, &ctx->session));
355 }
356 
357 
358 static void
360 {
361  struct test_context *ctx = (struct test_context *) *state;
362 
365  strcpy(ctx->up.password, now0key0);
366  assert_true(verify_auth_token(&ctx->up, &ctx->multi, &ctx->session));
367 
370  assert_false(verify_auth_token(&ctx->up, &ctx->multi, &ctx->session));
371 }
372 
373 int
374 main(void)
375 {
376  const struct CMUnitTest tests[] = {
385  };
386 
387 #if defined(ENABLE_CRYPTO_OPENSSL)
388  OpenSSL_add_all_algorithms();
389 #endif
390 
391  int ret = cmocka_run_group_tests_name("auth-token tests", tests, NULL, NULL);
392 
393  return ret;
394 }
#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:52
int auth_token_state_flags
The state of the auth-token sent from the client last time.
Definition: ssl_common.h:580
void free_key_ctx(struct key_ctx *ctx)
Definition: crypto.c:891
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:174
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:823
unsigned int auth_token_lifetime
Definition: ssl_common.h:336
#define streq(x, y)
Definition: options.h:656
static void auth_token_fail_invalid_key(void **state)
#define AUTH_TOKEN_EXPIRED
Auth-token sent from client has expired.
Definition: ssl_common.h:570
struct tls_options * opt
Definition: ssl_common.h:419
#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
char * auth_token_initial
The first auth-token we sent to a client, for clients that do not update their auth-token (older Open...
Definition: ssl_common.h:564
Security parameter state for a single VPN tunnel.
Definition: ssl_common.h:511
static void auth_token_test_key_load(void **state)
int main(void)
static void zerohmac(char *token)
struct tls_session session
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:332
void auth_set_client_reason(struct tls_multi *multi, const char *reason)
Sets the reason why authentication of a client failed.
char username[USER_PASS_LEN]
Definition: misc.h:74
static struct key_type auth_token_kt(void)
Definition: auth_token.c:32
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:568
#define cmocka_run_group_tests_name(group_name, group_tests, group_setup, group_teardown)
Definition: cmocka.h:1818
#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:283
#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:572
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:390
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:299
static void auth_token_test_random_keys(void **state)
struct tls_options opt
Definition: ssl_common.h:517
static void auth_token_test_env(void **state)
static const char * zeroinline
unsigned __int64 uint64_t
Definition: config-msvc.h:156
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:137
#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:338
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:560
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:416
Definition: misc.h:63
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:75
#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 assert_int_equal(a, b)
Definition: cmocka.h:1174
Container for unidirectional cipher and HMAC key material.
Definition: crypto.h:151