This accomplishes the security benefit of preventing caching
of the real password while offering most of the advantages
of password caching, i.e. not forcing the user to re-enter
credentials for every TLS renegotiation or network hiccup.
auth-token does two things:
1. if password caching is enabled, the token replaces the
previous password, and
2. if the management interface is active, the token is output
to it:
>PASSWORD:Auth-Token:<token>
Also made a minor change to HALT/RESTART processing when password
caching is enabled. When client receives a HALT or RESTART message,
and if the message text contains a flags block (i.e. [FFF]:message),
if flag 'P' (preserve auth) is present in flags, don't purge the Auth
password. Otherwise do purge the Auth password.
Version 2.1.3o
git-svn-id: http://svn.openvpn.net/projects/openvpn/branches/BETA21/openvpn@7088 e7ae566f-a301-0410-adde-c780ea21d3b5
... | ... |
@@ -232,8 +232,8 @@ bool |
232 | 232 |
send_control_channel_string (struct context *c, const char *str, int msglevel) |
233 | 233 |
{ |
234 | 234 |
#if defined(USE_CRYPTO) && defined(USE_SSL) |
235 |
- |
|
236 | 235 |
if (c->c2.tls_multi) { |
236 |
+ struct gc_arena gc = gc_new (); |
|
237 | 237 |
bool stat; |
238 | 238 |
|
239 | 239 |
/* buffered cleartext write onto TLS control channel */ |
... | ... |
@@ -250,9 +250,10 @@ send_control_channel_string (struct context *c, const char *str, int msglevel) |
250 | 250 |
|
251 | 251 |
msg (msglevel, "SENT CONTROL [%s]: '%s' (status=%d)", |
252 | 252 |
tls_common_name (c->c2.tls_multi, false), |
253 |
- str, |
|
253 |
+ sanitize_control_message (str, &gc), |
|
254 | 254 |
(int) stat); |
255 | 255 |
|
256 |
+ gc_free (&gc); |
|
256 | 257 |
return stat; |
257 | 258 |
} |
258 | 259 |
#endif |
... | ... |
@@ -1929,7 +1929,7 @@ do_init_crypto_tls_c1 (struct context *c) |
1929 | 1929 |
msg (M_FATAL, "Error: private key password verification failed"); |
1930 | 1930 |
break; |
1931 | 1931 |
case AR_INTERACT: |
1932 |
- ssl_purge_auth (); |
|
1932 |
+ ssl_purge_auth (false); |
|
1933 | 1933 |
case AR_NOINTERACT: |
1934 | 1934 |
c->sig->signal_received = SIGUSR1; /* SOFT-SIGUSR1 -- Password failure error */ |
1935 | 1935 |
break; |
... | ... |
@@ -698,7 +698,7 @@ static void |
698 | 698 |
man_forget_passwords (struct management *man) |
699 | 699 |
{ |
700 | 700 |
#if defined(USE_CRYPTO) && defined(USE_SSL) |
701 |
- ssl_purge_auth (); |
|
701 |
+ ssl_purge_auth (false); |
|
702 | 702 |
msg (M_CLIENT, "SUCCESS: Passwords were forgotten"); |
703 | 703 |
#endif |
704 | 704 |
} |
... | ... |
@@ -1682,7 +1682,7 @@ man_reset_client_socket (struct management *man, const bool exiting) |
1682 | 1682 |
{ |
1683 | 1683 |
#if defined(USE_CRYPTO) && defined(USE_SSL) |
1684 | 1684 |
if (man->settings.flags & MF_FORGET_DISCONNECT) |
1685 |
- ssl_purge_auth (); |
|
1685 |
+ ssl_purge_auth (false); |
|
1686 | 1686 |
#endif |
1687 | 1687 |
if (man->settings.flags & MF_SIGNAL) { |
1688 | 1688 |
int mysig = man_mod_signal (man, SIGUSR1); |
... | ... |
@@ -2515,6 +2515,12 @@ management_auth_failure (struct management *man, const char *type, const char *r |
2515 | 2515 |
msg (M_CLIENT, ">PASSWORD:Verification Failed: '%s'", type); |
2516 | 2516 |
} |
2517 | 2517 |
|
2518 |
+void |
|
2519 |
+management_auth_token (struct management *man, const char *token) |
|
2520 |
+{ |
|
2521 |
+ msg (M_CLIENT, ">PASSWORD:Auth-Token:%s", token); |
|
2522 |
+} |
|
2523 |
+ |
|
2518 | 2524 |
static inline bool |
2519 | 2525 |
man_persist_state (unsigned int *persistent, const int n) |
2520 | 2526 |
{ |
... | ... |
@@ -472,6 +472,11 @@ void management_echo (struct management *man, const char *string, const bool pul |
472 | 472 |
void management_auth_failure (struct management *man, const char *type, const char *reason); |
473 | 473 |
|
474 | 474 |
/* |
475 |
+ * Echo an authentication token to management interface |
|
476 |
+ */ |
|
477 |
+void management_auth_token (struct management *man, const char *token); |
|
478 |
+ |
|
479 |
+/* |
|
475 | 480 |
* These functions drive the bytecount in/out counters. |
476 | 481 |
*/ |
477 | 482 |
|
... | ... |
@@ -1695,6 +1695,16 @@ purge_user_pass (struct user_pass *up, const bool force) |
1695 | 1695 |
} |
1696 | 1696 |
} |
1697 | 1697 |
|
1698 |
+void |
|
1699 |
+set_auth_token (struct user_pass *up, const char *token) |
|
1700 |
+{ |
|
1701 |
+ if (token && strlen(token) && up && up->defined && !up->nocache) |
|
1702 |
+ { |
|
1703 |
+ CLEAR (up->password); |
|
1704 |
+ strncpynt (up->password, token, USER_PASS_LEN); |
|
1705 |
+ } |
|
1706 |
+} |
|
1707 |
+ |
|
1698 | 1708 |
/* |
1699 | 1709 |
* Process string received by untrusted peer before |
1700 | 1710 |
* printing to console or log file. |
... | ... |
@@ -2363,3 +2373,37 @@ openvpn_basename (const char *path) |
2363 | 2363 |
} |
2364 | 2364 |
return NULL; |
2365 | 2365 |
} |
2366 |
+ |
|
2367 |
+/* |
|
2368 |
+ * Remove SESS_ID_x strings (i.e. auth tokens) from control message |
|
2369 |
+ * strings so that they will not be output to log file. |
|
2370 |
+ */ |
|
2371 |
+const char * |
|
2372 |
+sanitize_control_message(const char *str, struct gc_arena *gc) |
|
2373 |
+{ |
|
2374 |
+ char *ret = gc_malloc (strlen(str)+1, false, gc); |
|
2375 |
+ char *cp = ret; |
|
2376 |
+ bool redact = false; |
|
2377 |
+ |
|
2378 |
+ strcpy(ret, str); |
|
2379 |
+ for (;;) |
|
2380 |
+ { |
|
2381 |
+ const char c = *cp; |
|
2382 |
+ if (c == '\0') |
|
2383 |
+ break; |
|
2384 |
+ if (c == 'S' && !strncmp(cp, "SESS_ID_", 8)) |
|
2385 |
+ { |
|
2386 |
+ cp += 7; |
|
2387 |
+ redact = true; |
|
2388 |
+ } |
|
2389 |
+ else |
|
2390 |
+ { |
|
2391 |
+ if (c == ',') /* end of session id? */ |
|
2392 |
+ redact = false; |
|
2393 |
+ if (redact) |
|
2394 |
+ *cp = '_'; |
|
2395 |
+ } |
|
2396 |
+ ++cp; |
|
2397 |
+ } |
|
2398 |
+ return ret; |
|
2399 |
+} |
... | ... |
@@ -306,6 +306,8 @@ void fail_user_pass (const char *prefix, |
306 | 306 |
|
307 | 307 |
void purge_user_pass (struct user_pass *up, const bool force); |
308 | 308 |
|
309 |
+void set_auth_token (struct user_pass *up, const char *token); |
|
310 |
+ |
|
309 | 311 |
/* |
310 | 312 |
* Process string received by untrusted peer before |
311 | 313 |
* printing to console or log file. |
... | ... |
@@ -327,6 +329,8 @@ void openvpn_sleep (const int n); |
327 | 327 |
|
328 | 328 |
void configure_path (void); |
329 | 329 |
|
330 |
+const char *sanitize_control_message(const char *str, struct gc_arena *gc); |
|
331 |
+ |
|
330 | 332 |
#if AUTO_USERID |
331 | 333 |
void get_user_pass_auto_userid (struct user_pass *up, const char *tag); |
332 | 334 |
#endif |
... | ... |
@@ -5802,6 +5802,15 @@ add_option (struct options *options, |
5802 | 5802 |
VERIFY_PERMISSION (OPT_P_GENERAL); |
5803 | 5803 |
ssl_set_auth_nocache (); |
5804 | 5804 |
} |
5805 |
+ else if (streq (p[0], "auth-token") && p[1]) |
|
5806 |
+ { |
|
5807 |
+ VERIFY_PERMISSION (OPT_P_ECHO); |
|
5808 |
+ ssl_set_auth_token(p[1]); |
|
5809 |
+#ifdef ENABLE_MANAGEMENT |
|
5810 |
+ if (management) |
|
5811 |
+ management_auth_token (management, p[1]); |
|
5812 |
+#endif |
|
5813 |
+ } |
|
5805 | 5814 |
else if (streq (p[0], "single-session")) |
5806 | 5815 |
{ |
5807 | 5816 |
VERIFY_PERMISSION (OPT_P_GENERAL); |
... | ... |
@@ -52,7 +52,7 @@ receive_auth_failed (struct context *c, const struct buffer *buffer) |
52 | 52 |
c->sig->signal_received = SIGTERM; /* SOFT-SIGTERM -- Auth failure error */ |
53 | 53 |
break; |
54 | 54 |
case AR_INTERACT: |
55 |
- ssl_purge_auth (); |
|
55 |
+ ssl_purge_auth (false); |
|
56 | 56 |
case AR_NOINTERACT: |
57 | 57 |
c->sig->signal_received = SIGUSR1; /* SOFT-SIGUSR1 -- Auth failure error */ |
58 | 58 |
break; |
... | ... |
@@ -95,6 +95,24 @@ server_pushed_signal (struct context *c, const struct buffer *buffer, const bool |
95 | 95 |
const char *m = ""; |
96 | 96 |
if (buf_advance (&buf, adv) && buf_read_u8 (&buf) == ',' && BLEN (&buf)) |
97 | 97 |
m = BSTR (&buf); |
98 |
+ |
|
99 |
+ /* preserve cached passwords? */ |
|
100 |
+ { |
|
101 |
+ bool purge = true; |
|
102 |
+ |
|
103 |
+ if (m[0] == '[') |
|
104 |
+ { |
|
105 |
+ int i; |
|
106 |
+ for (i = 1; m[i] != '\0' && m[i] != ']'; ++i) |
|
107 |
+ { |
|
108 |
+ if (m[i] == 'P') |
|
109 |
+ purge = false; |
|
110 |
+ } |
|
111 |
+ } |
|
112 |
+ if (purge) |
|
113 |
+ ssl_purge_auth (true); |
|
114 |
+ } |
|
115 |
+ |
|
98 | 116 |
if (restart) |
99 | 117 |
{ |
100 | 118 |
msg (D_STREAM_ERRORS, "Connection reset command was pushed by server ('%s')", m); |
... | ... |
@@ -166,7 +184,7 @@ incoming_push_message (struct context *c, const struct buffer *buffer) |
166 | 166 |
unsigned int option_types_found = 0; |
167 | 167 |
int status; |
168 | 168 |
|
169 |
- msg (D_PUSH, "PUSH: Received control message: '%s'", BSTR (buffer)); |
|
169 |
+ msg (D_PUSH, "PUSH: Received control message: '%s'", sanitize_control_message(BSTR(buffer), &gc)); |
|
170 | 170 |
|
171 | 171 |
status = process_incoming_push_msg (c, |
172 | 172 |
buffer, |
... | ... |
@@ -175,7 +193,7 @@ incoming_push_message (struct context *c, const struct buffer *buffer) |
175 | 175 |
&option_types_found); |
176 | 176 |
|
177 | 177 |
if (status == PUSH_MSG_ERROR) |
178 |
- msg (D_PUSH_ERRORS, "WARNING: Received bad push/pull message: %s", BSTR (buffer)); |
|
178 |
+ msg (D_PUSH_ERRORS, "WARNING: Received bad push/pull message: %s", sanitize_control_message(BSTR(buffer), &gc)); |
|
179 | 179 |
else if (status == PUSH_MSG_REPLY || status == PUSH_MSG_CONTINUATION) |
180 | 180 |
{ |
181 | 181 |
if (status == PUSH_MSG_REPLY) |
... | ... |
@@ -318,15 +318,27 @@ ssl_set_auth_nocache (void) |
318 | 318 |
} |
319 | 319 |
|
320 | 320 |
/* |
321 |
+ * Set an authentication token |
|
322 |
+ */ |
|
323 |
+void |
|
324 |
+ssl_set_auth_token (const char *token) |
|
325 |
+{ |
|
326 |
+ set_auth_token (&auth_user_pass, token); |
|
327 |
+} |
|
328 |
+ |
|
329 |
+/* |
|
321 | 330 |
* Forget private key password AND auth-user-pass username/password. |
322 | 331 |
*/ |
323 | 332 |
void |
324 |
-ssl_purge_auth (void) |
|
333 |
+ssl_purge_auth (const bool auth_user_pass_only) |
|
325 | 334 |
{ |
335 |
+ if (!auth_user_pass_only) |
|
336 |
+ { |
|
326 | 337 |
#ifdef USE_PKCS11 |
327 |
- pkcs11_logout (); |
|
338 |
+ pkcs11_logout (); |
|
328 | 339 |
#endif |
329 |
- purge_user_pass (&passbuf, true); |
|
340 |
+ purge_user_pass (&passbuf, true); |
|
341 |
+ } |
|
330 | 342 |
purge_user_pass (&auth_user_pass, true); |
331 | 343 |
#ifdef ENABLE_CLIENT_CR |
332 | 344 |
ssl_purge_auth_challenge(); |
... | ... |
@@ -722,7 +722,8 @@ void pem_password_setup (const char *auth_file); |
722 | 722 |
int pem_password_callback (char *buf, int size, int rwflag, void *u); |
723 | 723 |
void auth_user_pass_setup (const char *auth_file); |
724 | 724 |
void ssl_set_auth_nocache (void); |
725 |
-void ssl_purge_auth (void); |
|
725 |
+void ssl_set_auth_token (const char *token); |
|
726 |
+void ssl_purge_auth (const bool auth_user_pass_only); |
|
726 | 727 |
|
727 | 728 |
|
728 | 729 |
#ifdef ENABLE_CLIENT_CR |