@@ -1052,7 +1052,7 @@ The ">CLIENT:" notification is enabled by the --management-client-auth
OpenVPN configuration directive that gives the management interface client
the responsibility to authenticate OpenVPN clients after their client
certificate has been verified. CLIENT notifications may be multi-line, and
-the sequentiality of a given CLIENT notification, its associated environmental
+the sequentially of a given CLIENT notification, its associated environmental
variables, and the terminating ">CLIENT:ENV,END" line are guaranteed to be
atomic.
@@ -1094,6 +1094,34 @@ CLIENT notification types:
>CLIENT:ADDRESS,{CID},{ADDR},{PRI}
+(5) Text based challenge/Response
+
+ >CLIENT:CR_RESPONSE,{CID},{KID},{response_base64}
+ >CLIENT:ENV,name1=val1
+ >CLIENT:ENV,name2=val2
+ >CLIENT:ENV,...
+ >CLIENT:ENV,END
+
+ Using the cr-response command on the client side will trigger this
+ message on the server side.
+
+ CR_RESPONSE notification. The >CR_RESPONSE fulfils the same purpose as the
+ CRV1 response in the traditional challenge/response. See that section
+ below for more details. Since this still uses the same cid as the original
+ response, we do not use the username and opaque session data in this
+ response but only contains the actual response.
+
+ It is important to note that OpenVPN2 merely passes the authentication
+ information and does not do any further checks. (E.g. if a CR was issued
+ before or if multiple CR responses were sent from the client or if
+ data has a valid base64 encoding)
+
+ This interface should be be sufficient for almost all challenge/response
+ system that can be implemented with a single round and base64 encoding the
+ response. Mechanisms that need multiple rounds or more complex answers
+ should implement a different response type than CR_RESPONSE.
+
+
Variables:
CID -- Client ID, numerical ID for each connecting client, sequence = 0,1,2,...
@@ -403,6 +403,10 @@ check_incoming_control_channel_dowork(struct context *c)
{
server_pushed_info(c, &buf, 4);
}
+ else if (buf_string_match_head_str(&buf, "CR_RESPONSE"))
+ {
+ receive_cr_response(c, &buf);
+ }
else
{
msg(D_PUSH_ERRORS, "WARNING: Received unknown control message: %s", BSTR(&buf));
@@ -2908,7 +2908,7 @@ management_notify_generic(struct management *man, const char *str)
#ifdef MANAGEMENT_DEF_AUTH
static void
-man_output_peer_info_env(struct management *man, struct man_def_auth_context *mdac)
+man_output_peer_info_env(struct management *man, const struct man_def_auth_context *mdac)
{
char line[256];
if (man->persist.callback.get_peer_info)
@@ -2958,6 +2958,32 @@ management_notify_client_needing_auth(struct management *management,
}
}
+void
+management_notify_client_cr_response(unsigned mda_key_id,
+ const struct man_def_auth_context *mdac,
+ const struct env_set *es,
+ const char *response)
+{
+ struct gc_arena gc;
+ if (management)
+ {
+ gc = gc_new();
+
+ struct buffer out = alloc_buf_gc(256, &gc);
+ msg(M_CLIENT, ">CLIENT:CR_RESPONSE,%lu,%u,%s",
+ mdac->cid, mda_key_id, response);
+ man_output_extra_env(management, "CLIENT");
+ if (management->connection.env_filter_level>0)
+ {
+ man_output_peer_info_env(management, mdac);
+ }
+ man_output_env(es, true, management->connection.env_filter_level, "CLIENT");
+ management_notify_generic(management, BSTR(&out));
+
+ gc_free(&gc);
+ }
+}
+
void
management_connection_established(struct management *management,
struct man_def_auth_context *mdac,
@@ -434,6 +434,11 @@ void management_learn_addr(struct management *management,
const struct mroute_addr *addr,
const bool primary);
+void management_notify_client_cr_response(unsigned mda_key_id,
+ const struct man_def_auth_context *mdac,
+ const struct env_set *es,
+ const char *response);
+
#endif
char *management_query_pk_sig(struct management *man, const char *b64_data,
@@ -209,6 +209,28 @@ server_pushed_info(struct context *c, const struct buffer *buffer,
msg(D_PUSH, "Info command was pushed by server ('%s')", m);
}
+void
+receive_cr_response(struct context *c, const struct buffer *buffer)
+{
+ struct buffer buf = *buffer;
+ const char *m = "";
+
+ if (buf_advance(&buf, 11) && buf_read_u8(&buf) == ',' && BLEN(&buf))
+ {
+ m = BSTR(&buf);
+ }
+#ifdef MANAGEMENT_DEF_AUTH
+ struct tls_session *session = &c->c2.tls_multi->session[TM_ACTIVE];
+ struct man_def_auth_context *mda = session->opt->mda_context;
+ struct env_set *es = session->opt->es;
+ int key_id = session->key[KS_PRIMARY].key_id;
+
+
+ management_notify_client_cr_response(key_id, mda, es, m);
+#endif
+ msg(D_PUSH, "CR response was sent by client ('%s')", m);
+}
+
/**
* Add an option to the given push list by providing a format string.
*
@@ -53,6 +53,8 @@ void server_pushed_signal(struct context *c, const struct buffer *buffer, const
void server_pushed_info(struct context *c, const struct buffer *buffer,
const int adv);
+void receive_cr_response(struct context *c, const struct buffer *buffer);
+
void incoming_push_message(struct context *c, const struct buffer *buffer);
void clone_push_list(struct options *o);
When signalling the client that it should do Challenge response without reconnecting (IV_SSO=crtext/INFOPRE=CR_TEXT), the server needs forward the response via the management console. Signed-off-by: Arne Schwabe <arne@rfc2549.org> --- doc/management-notes.txt | 30 +++++++++++++++++++++++++++++- src/openvpn/forward.c | 4 ++++ src/openvpn/manage.c | 28 +++++++++++++++++++++++++++- src/openvpn/manage.h | 5 +++++ src/openvpn/push.c | 22 ++++++++++++++++++++++ src/openvpn/push.h | 2 ++ 6 files changed, 89 insertions(+), 2 deletions(-)