From 612c9279dadebf832b69c97acfc43cf60f2400a7 Mon Sep 17 00:00:00 2001
From: David Sommerseth <davids@openvpn.net>
Date: Thu, 6 Sep 2018 11:57:02 +0200
Subject: [PATCH] pkcs11: Workaround to make PKCS#11 PIN token work with
systemd
Due to an issue in the pkcs11-helper library, the systemd query
mechanism makes OpenVPN go into a halt. This is simply a workaround to
force using the built-in user query mechanism for the PKCS#11 token PIN,
regardless if systemd is used or not.
Signed-off-by: David Sommerseth <davids@openvpn.net>
---
src/openvpn/console.h | 36 +++++++++++++++++++----------------
src/openvpn/console_systemd.c | 2 +-
src/openvpn/misc.c | 20 ++++++++++++++-----
src/openvpn/misc.h | 1 +
src/openvpn/pkcs11.c | 6 ++++--
5 files changed, 41 insertions(+), 24 deletions(-)
diff --git a/src/openvpn/console.h b/src/openvpn/console.h
index 5a70e5fd..b5f1ffaa 100644
a
|
b
|
struct _query_user { |
42 | 42 | #define QUERY_USER_NUMSLOTS 10 |
43 | 43 | extern struct _query_user query_user[]; /**< Global variable, declared in console.c */ |
44 | 44 | |
| 45 | typedef enum { |
| 46 | QUERYUSER_NO_ECHO, /**< hide user input, used for passwords */ |
| 47 | QUERYUSER_FORCE_BUILTIN /**< Force using the builtin query mechanism |
| 48 | (pkcs11-helper workaround) */ |
| 49 | } QueryFlags; |
| 50 | |
45 | 51 | /** |
46 | 52 | * Wipes all data put into all of the query_user structs |
47 | 53 | * |
… |
… |
void query_user_add(char *prompt, size_t prompt_len, |
75 | 81 | bool query_user_exec_builtin(void); |
76 | 82 | |
77 | 83 | |
78 | | #if defined(ENABLE_SYSTEMD) |
79 | 84 | /** |
80 | 85 | * Executes a configured setup, using the compiled method for querying the user |
81 | 86 | * |
… |
… |
bool query_user_exec_builtin(void); |
83 | 88 | * |
84 | 89 | * @return True if executing all the defined steps completed successfully |
85 | 90 | */ |
86 | | bool query_user_exec(void); |
87 | | |
88 | | #else /* ENABLE_SYSTEMD not defined*/ |
89 | | /** |
90 | | * Wrapper function enabling query_user_exec() if no alternative methods have |
91 | | * been enabled |
92 | | * |
93 | | */ |
94 | | static bool |
95 | | query_user_exec(void) |
| 91 | static inline bool |
| 92 | query_user_exec(bool force_builtin) |
96 | 93 | { |
97 | | return query_user_exec_builtin(); |
| 94 | #ifdef ENABLE_SYSTEMD |
| 95 | bool query_user_exec_systemd(void); /* console_systemd.c */ |
| 96 | if (!force_builtin) |
| 97 | { |
| 98 | return query_user_exec_systemd(); |
| 99 | } |
| 100 | #endif |
| 101 | return query_user_exec_builtin(); |
98 | 102 | } |
99 | | #endif /* defined(ENABLE_SYSTEMD) */ |
100 | 103 | |
101 | 104 | |
102 | 105 | /** |
… |
… |
query_user_exec(void) |
109 | 112 | static inline bool |
110 | 113 | query_user_SINGLE(char *prompt, size_t prompt_len, |
111 | 114 | char *resp, size_t resp_len, |
112 | | bool echo) |
| 115 | QueryFlags flags) |
113 | 116 | { |
114 | 117 | query_user_clear(); |
115 | | query_user_add(prompt, prompt_len, resp, resp_len, echo); |
116 | | return query_user_exec(); |
| 118 | query_user_add(prompt, prompt_len, resp, resp_len, |
| 119 | (flags & QUERYUSER_NO_ECHO)); |
| 120 | return query_user_exec(flags & QUERYUSER_FORCE_BUILTIN); |
117 | 121 | } |
118 | 122 | |
119 | 123 | #endif /* ifndef CONSOLE_H */ |
diff --git a/src/openvpn/console_systemd.c b/src/openvpn/console_systemd.c
index e7a72ae3..af15f234 100644
a
|
b
|
get_console_input_systemd(const char *prompt, const bool echo, char *input, cons |
95 | 95 | * |
96 | 96 | */ |
97 | 97 | bool |
98 | | query_user_exec(void) |
| 98 | query_user_exec_systemd(void) |
99 | 99 | { |
100 | 100 | bool ret = true; /* Presume everything goes okay */ |
101 | 101 | int i; |
diff --git a/src/openvpn/misc.c b/src/openvpn/misc.c
index 71fa2135..cd1d0684 100644
a
|
b
|
get_user_pass_cr(struct user_pass *up, |
186 | 186 | |
187 | 187 | buf_printf(&user_prompt, "NEED-OK|%s|%s:", prefix, up->username); |
188 | 188 | if (!query_user_SINGLE(BSTR(&user_prompt), BLEN(&user_prompt), |
189 | | up->password, USER_PASS_LEN, false)) |
| 189 | up->password, USER_PASS_LEN, |
| 190 | QUERYUSER_NO_ECHO)) |
190 | 191 | { |
191 | 192 | msg(M_FATAL, "ERROR: could not read %s ok-confirmation from stdin", prefix); |
192 | 193 | } |
… |
… |
get_user_pass_cr(struct user_pass *up, |
285 | 286 | buf_printf(&challenge, "CHALLENGE: %s", ac->challenge_text); |
286 | 287 | buf_set_write(&packed_resp, (uint8_t *)up->password, USER_PASS_LEN); |
287 | 288 | |
| 289 | QueryFlags qryflag = 0; |
| 290 | if (BOOL_CAST(ac->flags&CR_ECHO)) |
| 291 | { |
| 292 | qryflag |= QUERYUSER_NO_ECHO; |
| 293 | } |
288 | 294 | if (!query_user_SINGLE(BSTR(&challenge), BLEN(&challenge), |
289 | | response, USER_PASS_LEN, BOOL_CAST(ac->flags&CR_ECHO))) |
| 295 | response, USER_PASS_LEN, qryflag)) |
290 | 296 | { |
291 | 297 | msg(M_FATAL, "ERROR: could not read challenge response from stdin"); |
292 | 298 | } |
… |
… |
get_user_pass_cr(struct user_pass *up, |
320 | 326 | up->password, USER_PASS_LEN, false); |
321 | 327 | } |
322 | 328 | |
323 | | if (!query_user_exec() ) |
| 329 | if (!query_user_exec((flags & GET_USER_PASS_FORCE_BUILTIN)) ) |
324 | 330 | { |
325 | 331 | msg(M_FATAL, "ERROR: Failed retrieving username or password"); |
326 | 332 | } |
… |
… |
get_user_pass_cr(struct user_pass *up, |
343 | 349 | challenge = alloc_buf_gc(14+strlen(auth_challenge), &gc); |
344 | 350 | buf_printf(&challenge, "CHALLENGE: %s", auth_challenge); |
345 | 351 | |
| 352 | QueryFlags qryflag = QUERYUSER_NO_ECHO; |
| 353 | if (BOOL_CAST(flags & GET_USER_PASS_STATIC_CHALLENGE_ECHO)) |
| 354 | { |
| 355 | qryflag = 0; |
| 356 | } |
346 | 357 | if (!query_user_SINGLE(BSTR(&challenge), BLEN(&challenge), |
347 | | response, USER_PASS_LEN, |
348 | | BOOL_CAST(flags & GET_USER_PASS_STATIC_CHALLENGE_ECHO))) |
| 358 | response, USER_PASS_LEN, qryflag)) |
349 | 359 | { |
350 | 360 | msg(M_FATAL, "ERROR: could not retrieve static challenge response"); |
351 | 361 | } |
diff --git a/src/openvpn/misc.h b/src/openvpn/misc.h
index 14abb0f3..e08a8739 100644
a
|
b
|
struct static_challenge_info {}; |
126 | 126 | #define GET_USER_PASS_STATIC_CHALLENGE_ECHO (1<<9) /* SCRV1 protocol -- echo response */ |
127 | 127 | |
128 | 128 | #define GET_USER_PASS_INLINE_CREDS (1<<10) /* indicates that auth_file is actually inline creds */ |
| 129 | #define GET_USER_PASS_FORCE_BUILTIN (1<<11) /* force using the built-in query_user function */ |
129 | 130 | |
130 | 131 | bool get_user_pass_cr(struct user_pass *up, |
131 | 132 | const char *auth_file, |
diff --git a/src/openvpn/pkcs11.c b/src/openvpn/pkcs11.c
index 93f8580a..fa64af82 100644
a
|
b
|
_pkcs11_openvpn_pin_prompt( |
257 | 257 | &token_pass, |
258 | 258 | NULL, |
259 | 259 | prompt, |
260 | | GET_USER_PASS_MANAGEMENT|GET_USER_PASS_PASSWORD_ONLY|GET_USER_PASS_NOFATAL |
| 260 | GET_USER_PASS_MANAGEMENT | GET_USER_PASS_PASSWORD_ONLY |
| 261 | | GET_USER_PASS_NOFATAL | GET_USER_PASS_FORCE_BUILTIN |
261 | 262 | ) |
262 | 263 | ) |
263 | 264 | { |
… |
… |
_pkcs11_openvpn_show_pkcs11_ids_pin_prompt( |
814 | 815 | |
815 | 816 | buf_printf(&pass_prompt, "Please enter '%s' token PIN or 'cancel': ", token->display); |
816 | 817 | if (!query_user_SINGLE(BSTR(&pass_prompt), BLEN(&pass_prompt), |
817 | | pin, pin_max, false)) |
| 818 | pin, pin_max, |
| 819 | (QUERYUSER_NO_ECHO | QUERYUSER_FORCE_BUILTIN))) |
818 | 820 | { |
819 | 821 | msg(M_FATAL, "Could not retrieve the PIN"); |
820 | 822 | } |