mirror of
https://github.com/OpenVPN/openvpn.git
synced 2024-09-20 12:02:28 +02:00
Added "management-external-key" option. This option can be used
instead of "key" in client mode, and allows the client to run without the need to load the actual private key. When the SSL protocol needs to perform an RSA sign operation, the data to be signed will be sent to the management interface via a notification as follows: >RSA_SIGN:[BASE64_DATA] The management interface client should then sign BASE64_DATA using the private key and return the signature as follows: rsa-sig [BASE64_SIG_LINE] . . . END This capability is intended to allow the use of arbitrary cryptographic service providers with OpenVPN via the management interface. git-svn-id: http://svn.openvpn.net/projects/openvpn/branches/BETA21/openvpn@6708 e7ae566f-a301-0410-adde-c780ea21d3b5
This commit is contained in:
parent
2d12eb12cf
commit
2a3d17ed18
17
base64.c
17
base64.c
@ -33,7 +33,7 @@
|
|||||||
|
|
||||||
#include "syshead.h"
|
#include "syshead.h"
|
||||||
|
|
||||||
#if defined(ENABLE_HTTP_PROXY) || defined(ENABLE_PKCS11) || defined(ENABLE_CLIENT_CR)
|
#if defined(ENABLE_HTTP_PROXY) || defined(ENABLE_PKCS11) || defined(ENABLE_CLIENT_CR) || defined(MANAGMENT_EXTERNAL_KEY)
|
||||||
|
|
||||||
#include "base64.h"
|
#include "base64.h"
|
||||||
|
|
||||||
@ -115,22 +115,35 @@ token_decode(const char *token)
|
|||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
base64_decode(const char *str, void *data)
|
base64_decode(const char *str, void *data, int size)
|
||||||
{
|
{
|
||||||
const char *p;
|
const char *p;
|
||||||
unsigned char *q;
|
unsigned char *q;
|
||||||
|
unsigned char *e = NULL;
|
||||||
|
|
||||||
q = data;
|
q = data;
|
||||||
|
if (size >= 0)
|
||||||
|
e = q + size;
|
||||||
for (p = str; *p && (*p == '=' || strchr(base64_chars, *p)); p += 4) {
|
for (p = str; *p && (*p == '=' || strchr(base64_chars, *p)); p += 4) {
|
||||||
unsigned int val = token_decode(p);
|
unsigned int val = token_decode(p);
|
||||||
unsigned int marker = (val >> 24) & 0xff;
|
unsigned int marker = (val >> 24) & 0xff;
|
||||||
if (val == DECODE_ERROR)
|
if (val == DECODE_ERROR)
|
||||||
return -1;
|
return -1;
|
||||||
|
if (e && q >= e)
|
||||||
|
return -1;
|
||||||
*q++ = (val >> 16) & 0xff;
|
*q++ = (val >> 16) & 0xff;
|
||||||
if (marker < 2)
|
if (marker < 2)
|
||||||
|
{
|
||||||
|
if (e && q >= e)
|
||||||
|
return -1;
|
||||||
*q++ = (val >> 8) & 0xff;
|
*q++ = (val >> 8) & 0xff;
|
||||||
|
}
|
||||||
if (marker < 1)
|
if (marker < 1)
|
||||||
|
{
|
||||||
|
if (e && q >= e)
|
||||||
|
return -1;
|
||||||
*q++ = val & 0xff;
|
*q++ = val & 0xff;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return q - (unsigned char *) data;
|
return q - (unsigned char *) data;
|
||||||
}
|
}
|
||||||
|
4
base64.h
4
base64.h
@ -34,10 +34,10 @@
|
|||||||
#ifndef _BASE64_H_
|
#ifndef _BASE64_H_
|
||||||
#define _BASE64_H_
|
#define _BASE64_H_
|
||||||
|
|
||||||
#if defined(ENABLE_HTTP_PROXY) || defined(ENABLE_PKCS11) || defined(ENABLE_CLIENT_CR)
|
#if defined(ENABLE_HTTP_PROXY) || defined(ENABLE_PKCS11) || defined(ENABLE_CLIENT_CR) || defined(MANAGMENT_EXTERNAL_KEY)
|
||||||
|
|
||||||
int base64_encode(const void *data, int size, char **str);
|
int base64_encode(const void *data, int size, char **str);
|
||||||
int base64_decode(const char *str, void *data);
|
int base64_decode(const char *str, void *data, int size);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
2
buffer.c
2
buffer.c
@ -906,7 +906,7 @@ buffer_list_free (struct buffer_list *ol)
|
|||||||
bool
|
bool
|
||||||
buffer_list_defined (const struct buffer_list *ol)
|
buffer_list_defined (const struct buffer_list *ol)
|
||||||
{
|
{
|
||||||
return ol->head != NULL;
|
return ol && ol->head != NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
306
manage.c
306
manage.c
@ -101,6 +101,10 @@ man_help ()
|
|||||||
#ifdef MANAGEMENT_PF
|
#ifdef MANAGEMENT_PF
|
||||||
msg (M_CLIENT, "client-pf CID : Define packet filter for client CID (MULTILINE)");
|
msg (M_CLIENT, "client-pf CID : Define packet filter for client CID (MULTILINE)");
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
#ifdef MANAGMENT_EXTERNAL_KEY
|
||||||
|
msg (M_CLIENT, "rsa-sig : Enter an RSA signature in response to >RSA_SIGN challenge");
|
||||||
|
msg (M_CLIENT, " Enter signature base64 on subsequent lines followed by END");
|
||||||
#endif
|
#endif
|
||||||
msg (M_CLIENT, "signal s : Send signal s to daemon,");
|
msg (M_CLIENT, "signal s : Send signal s to daemon,");
|
||||||
msg (M_CLIENT, " s = SIGHUP|SIGTERM|SIGUSR1|SIGUSR2.");
|
msg (M_CLIENT, " s = SIGHUP|SIGTERM|SIGUSR1|SIGUSR2.");
|
||||||
@ -768,6 +772,103 @@ man_hold (struct management *man, const char *cmd)
|
|||||||
msg (M_CLIENT, "SUCCESS: hold=%d", BOOL_CAST(man->settings.flags & MF_HOLD));
|
msg (M_CLIENT, "SUCCESS: hold=%d", BOOL_CAST(man->settings.flags & MF_HOLD));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef MANAGEMENT_IN_EXTRA
|
||||||
|
|
||||||
|
#define IER_RESET 0
|
||||||
|
#define IER_NEW 1
|
||||||
|
#define IER_CONDRESET 2
|
||||||
|
|
||||||
|
static void
|
||||||
|
in_extra_reset (struct man_connection *mc, const int mode)
|
||||||
|
{
|
||||||
|
if (mc && (mc->in_extra_cmd < IEC_STATEFUL_BASE || mode != IER_CONDRESET))
|
||||||
|
{
|
||||||
|
if (mode != IER_NEW)
|
||||||
|
{
|
||||||
|
mc->in_extra_cmd = IEC_UNDEF;
|
||||||
|
#ifdef MANAGEMENT_DEF_AUTH
|
||||||
|
mc->in_extra_cid = 0;
|
||||||
|
mc->in_extra_kid = 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
if (mc->in_extra)
|
||||||
|
{
|
||||||
|
buffer_list_free (mc->in_extra);
|
||||||
|
mc->in_extra = NULL;
|
||||||
|
}
|
||||||
|
if (mode == IER_NEW)
|
||||||
|
mc->in_extra = buffer_list_new (0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
in_extra_dispatch (struct management *man)
|
||||||
|
{
|
||||||
|
switch (man->connection.in_extra_cmd)
|
||||||
|
{
|
||||||
|
#ifdef MANAGEMENT_DEF_AUTH
|
||||||
|
case IEC_CLIENT_AUTH:
|
||||||
|
if (man->persist.callback.client_auth)
|
||||||
|
{
|
||||||
|
const bool status = (*man->persist.callback.client_auth)
|
||||||
|
(man->persist.callback.arg,
|
||||||
|
man->connection.in_extra_cid,
|
||||||
|
man->connection.in_extra_kid,
|
||||||
|
true,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
man->connection.in_extra);
|
||||||
|
man->connection.in_extra = NULL;
|
||||||
|
if (status)
|
||||||
|
{
|
||||||
|
msg (M_CLIENT, "SUCCESS: client-auth command succeeded");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
msg (M_CLIENT, "ERROR: client-auth command failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
msg (M_CLIENT, "ERROR: The client-auth command is not supported by the current daemon mode");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
#ifdef MANAGEMENT_PF
|
||||||
|
case IEC_CLIENT_PF:
|
||||||
|
if (man->persist.callback.client_pf)
|
||||||
|
{
|
||||||
|
const bool status = (*man->persist.callback.client_pf)
|
||||||
|
(man->persist.callback.arg,
|
||||||
|
man->connection.in_extra_cid,
|
||||||
|
man->connection.in_extra);
|
||||||
|
man->connection.in_extra = NULL;
|
||||||
|
if (status)
|
||||||
|
{
|
||||||
|
msg (M_CLIENT, "SUCCESS: client-pf command succeeded");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
msg (M_CLIENT, "ERROR: client-pf command failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
msg (M_CLIENT, "ERROR: The client-pf command is not supported by the current daemon mode");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
#ifdef MANAGMENT_EXTERNAL_KEY
|
||||||
|
case IEC_RSA_SIGN:
|
||||||
|
man->connection.in_extra_cmd = IEC_RSA_SIGN_FINAL;
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
in_extra_reset (&man->connection, IER_RESET);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* MANAGEMENT_IN_EXTRA */
|
||||||
|
|
||||||
#ifdef MANAGEMENT_DEF_AUTH
|
#ifdef MANAGEMENT_DEF_AUTH
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
@ -794,86 +895,6 @@ parse_kid (const char *str, unsigned int *kid)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
in_extra_reset (struct man_connection *mc, const bool new)
|
|
||||||
{
|
|
||||||
if (mc)
|
|
||||||
{
|
|
||||||
if (!new)
|
|
||||||
{
|
|
||||||
mc->in_extra_cmd = IEC_UNDEF;
|
|
||||||
mc->in_extra_cid = 0;
|
|
||||||
mc->in_extra_kid = 0;
|
|
||||||
}
|
|
||||||
if (mc->in_extra)
|
|
||||||
{
|
|
||||||
buffer_list_free (mc->in_extra);
|
|
||||||
mc->in_extra = NULL;
|
|
||||||
}
|
|
||||||
if (new)
|
|
||||||
mc->in_extra = buffer_list_new (0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
in_extra_dispatch (struct management *man)
|
|
||||||
{
|
|
||||||
switch (man->connection.in_extra_cmd)
|
|
||||||
{
|
|
||||||
case IEC_CLIENT_AUTH:
|
|
||||||
if (man->persist.callback.client_auth)
|
|
||||||
{
|
|
||||||
const bool status = (*man->persist.callback.client_auth)
|
|
||||||
(man->persist.callback.arg,
|
|
||||||
man->connection.in_extra_cid,
|
|
||||||
man->connection.in_extra_kid,
|
|
||||||
true,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
man->connection.in_extra);
|
|
||||||
man->connection.in_extra = NULL;
|
|
||||||
if (status)
|
|
||||||
{
|
|
||||||
msg (M_CLIENT, "SUCCESS: client-auth command succeeded");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
msg (M_CLIENT, "ERROR: client-auth command failed");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
msg (M_CLIENT, "ERROR: The client-auth command is not supported by the current daemon mode");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
#ifdef MANAGEMENT_PF
|
|
||||||
case IEC_CLIENT_PF:
|
|
||||||
if (man->persist.callback.client_pf)
|
|
||||||
{
|
|
||||||
const bool status = (*man->persist.callback.client_pf)
|
|
||||||
(man->persist.callback.arg,
|
|
||||||
man->connection.in_extra_cid,
|
|
||||||
man->connection.in_extra);
|
|
||||||
man->connection.in_extra = NULL;
|
|
||||||
if (status)
|
|
||||||
{
|
|
||||||
msg (M_CLIENT, "SUCCESS: client-pf command succeeded");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
msg (M_CLIENT, "ERROR: client-pf command failed");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
msg (M_CLIENT, "ERROR: The client-pf command is not supported by the current daemon mode");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
in_extra_reset (&man->connection, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
man_client_auth (struct management *man, const char *cid_str, const char *kid_str, const bool extra)
|
man_client_auth (struct management *man, const char *cid_str, const char *kid_str, const bool extra)
|
||||||
{
|
{
|
||||||
@ -884,7 +905,7 @@ man_client_auth (struct management *man, const char *cid_str, const char *kid_st
|
|||||||
&& parse_kid (kid_str, &mc->in_extra_kid))
|
&& parse_kid (kid_str, &mc->in_extra_kid))
|
||||||
{
|
{
|
||||||
mc->in_extra_cmd = IEC_CLIENT_AUTH;
|
mc->in_extra_cmd = IEC_CLIENT_AUTH;
|
||||||
in_extra_reset (mc, true);
|
in_extra_reset (mc, IER_NEW);
|
||||||
if (!extra)
|
if (!extra)
|
||||||
in_extra_dispatch (man);
|
in_extra_dispatch (man);
|
||||||
}
|
}
|
||||||
@ -980,11 +1001,28 @@ man_client_pf (struct management *man, const char *cid_str)
|
|||||||
if (parse_cid (cid_str, &mc->in_extra_cid))
|
if (parse_cid (cid_str, &mc->in_extra_cid))
|
||||||
{
|
{
|
||||||
mc->in_extra_cmd = IEC_CLIENT_PF;
|
mc->in_extra_cmd = IEC_CLIENT_PF;
|
||||||
in_extra_reset (mc, true);
|
in_extra_reset (mc, IER_NEW);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif /* MANAGEMENT_PF */
|
||||||
|
#endif /* MANAGEMENT_DEF_AUTH */
|
||||||
|
|
||||||
|
#ifdef MANAGMENT_EXTERNAL_KEY
|
||||||
|
|
||||||
|
static void
|
||||||
|
man_rsa_sig (struct management *man)
|
||||||
|
{
|
||||||
|
struct man_connection *mc = &man->connection;
|
||||||
|
if (mc->in_extra_cmd == IEC_RSA_SIGN_PRE)
|
||||||
|
{
|
||||||
|
in_extra_reset (&man->connection, IER_NEW);
|
||||||
|
mc->in_extra_cmd = IEC_RSA_SIGN;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
msg (M_CLIENT, "ERROR: The rsa-sig command is not currently available");
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -1250,6 +1288,12 @@ man_dispatch_command (struct management *man, struct status_output *so, const ch
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef MANAGMENT_EXTERNAL_KEY
|
||||||
|
else if (streq (p[0], "rsa-sig"))
|
||||||
|
{
|
||||||
|
man_rsa_sig (man);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
#ifdef ENABLE_PKCS11
|
#ifdef ENABLE_PKCS11
|
||||||
else if (streq (p[0], "pkcs11-id-count"))
|
else if (streq (p[0], "pkcs11-id-count"))
|
||||||
{
|
{
|
||||||
@ -1626,8 +1670,8 @@ man_reset_client_socket (struct management *man, const bool exiting)
|
|||||||
man->connection.state = MS_INITIAL;
|
man->connection.state = MS_INITIAL;
|
||||||
command_line_reset (man->connection.in);
|
command_line_reset (man->connection.in);
|
||||||
buffer_list_reset (man->connection.out);
|
buffer_list_reset (man->connection.out);
|
||||||
#ifdef MANAGEMENT_DEF_AUTH
|
#ifdef MANAGEMENT_IN_EXTRA
|
||||||
in_extra_reset (&man->connection, false);
|
in_extra_reset (&man->connection, IER_RESET);
|
||||||
#endif
|
#endif
|
||||||
msg (D_MANAGEMENT, "MANAGEMENT: Client disconnected");
|
msg (D_MANAGEMENT, "MANAGEMENT: Client disconnected");
|
||||||
}
|
}
|
||||||
@ -1666,8 +1710,8 @@ man_process_command (struct management *man, const char *line)
|
|||||||
|
|
||||||
CLEAR (parms);
|
CLEAR (parms);
|
||||||
so = status_open (NULL, 0, -1, &man->persist.vout, 0);
|
so = status_open (NULL, 0, -1, &man->persist.vout, 0);
|
||||||
#ifdef MANAGEMENT_DEF_AUTH
|
#ifdef MANAGEMENT_IN_EXTRA
|
||||||
in_extra_reset (&man->connection, false);
|
in_extra_reset (&man->connection, IER_CONDRESET);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (man_password_needed (man))
|
if (man_password_needed (man))
|
||||||
@ -1751,18 +1795,13 @@ man_read (struct management *man)
|
|||||||
const unsigned char *line;
|
const unsigned char *line;
|
||||||
while ((line = command_line_get (man->connection.in)))
|
while ((line = command_line_get (man->connection.in)))
|
||||||
{
|
{
|
||||||
#ifdef MANAGEMENT_DEF_AUTH
|
#ifdef MANAGEMENT_IN_EXTRA
|
||||||
if (man->connection.in_extra)
|
if (man->connection.in_extra)
|
||||||
{
|
{
|
||||||
if (!strcmp ((char *)line, "END"))
|
if (!strcmp ((char *)line, "END"))
|
||||||
{
|
in_extra_dispatch (man);
|
||||||
in_extra_dispatch (man);
|
|
||||||
in_extra_reset (&man->connection, false);
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
buffer_list_push (man->connection.in_extra, line);
|
||||||
buffer_list_push (man->connection.in_extra, line);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
@ -2063,8 +2102,8 @@ man_connection_close (struct management *man)
|
|||||||
command_line_free (mc->in);
|
command_line_free (mc->in);
|
||||||
if (mc->out)
|
if (mc->out)
|
||||||
buffer_list_free (mc->out);
|
buffer_list_free (mc->out);
|
||||||
#ifdef MANAGEMENT_DEF_AUTH
|
#ifdef MANAGEMENT_IN_EXTRA
|
||||||
in_extra_reset (&man->connection, false);
|
in_extra_reset (&man->connection, IER_RESET);
|
||||||
#endif
|
#endif
|
||||||
man_connection_clear (mc);
|
man_connection_clear (mc);
|
||||||
}
|
}
|
||||||
@ -2387,7 +2426,7 @@ management_learn_addr (struct management *management,
|
|||||||
gc_free (&gc);
|
gc_free (&gc);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif /* MANAGEMENT_DEF_AUTH */
|
||||||
|
|
||||||
void
|
void
|
||||||
management_echo (struct management *man, const char *string, const bool pull)
|
management_echo (struct management *man, const char *string, const bool pull)
|
||||||
@ -2693,6 +2732,7 @@ man_standalone_event_loop (struct management *man, volatile int *signal_received
|
|||||||
|
|
||||||
#define MWCC_PASSWORD_WAIT (1<<0)
|
#define MWCC_PASSWORD_WAIT (1<<0)
|
||||||
#define MWCC_HOLD_WAIT (1<<1)
|
#define MWCC_HOLD_WAIT (1<<1)
|
||||||
|
#define MWCC_OTHER_WAIT (1<<2)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Block until client connects
|
* Block until client connects
|
||||||
@ -2710,6 +2750,8 @@ man_wait_for_client_connection (struct management *man,
|
|||||||
msg (D_MANAGEMENT, "Need password(s) from management interface, waiting...");
|
msg (D_MANAGEMENT, "Need password(s) from management interface, waiting...");
|
||||||
if (flags & MWCC_HOLD_WAIT)
|
if (flags & MWCC_HOLD_WAIT)
|
||||||
msg (D_MANAGEMENT, "Need hold release from management interface, waiting...");
|
msg (D_MANAGEMENT, "Need hold release from management interface, waiting...");
|
||||||
|
if (flags & MWCC_OTHER_WAIT)
|
||||||
|
msg (D_MANAGEMENT, "Need information from management interface, waiting...");
|
||||||
do {
|
do {
|
||||||
man_standalone_event_loop (man, signal_received, expire);
|
man_standalone_event_loop (man, signal_received, expire);
|
||||||
if (signal_received && *signal_received)
|
if (signal_received && *signal_received)
|
||||||
@ -2873,6 +2915,74 @@ management_query_user_pass (struct management *man,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef MANAGMENT_EXTERNAL_KEY
|
||||||
|
|
||||||
|
char * /* returns allocated base64 signature */
|
||||||
|
management_query_rsa_sig (struct management *man,
|
||||||
|
const char *b64_data)
|
||||||
|
{
|
||||||
|
struct gc_arena gc = gc_new ();
|
||||||
|
char *ret = NULL;
|
||||||
|
volatile int signal_received = 0;
|
||||||
|
struct buffer alert_msg = clear_buf();
|
||||||
|
struct buffer *buf;
|
||||||
|
const bool standalone_disabled_save = man->persist.standalone_disabled;
|
||||||
|
|
||||||
|
if (man_standalone_ok (man))
|
||||||
|
{
|
||||||
|
man->persist.standalone_disabled = false; /* This is so M_CLIENT messages will be correctly passed through msg() */
|
||||||
|
man->persist.special_state_msg = NULL;
|
||||||
|
|
||||||
|
in_extra_reset (&man->connection, IER_RESET);
|
||||||
|
man->connection.in_extra_cmd = IEC_RSA_SIGN_PRE;
|
||||||
|
|
||||||
|
alert_msg = alloc_buf_gc (strlen(b64_data)+64, &gc);
|
||||||
|
buf_printf (&alert_msg, ">RSA_SIGN:%s", b64_data);
|
||||||
|
|
||||||
|
man_wait_for_client_connection (man, &signal_received, 0, MWCC_OTHER_WAIT);
|
||||||
|
|
||||||
|
if (signal_received)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
man->persist.special_state_msg = BSTR (&alert_msg);
|
||||||
|
msg (M_CLIENT, "%s", man->persist.special_state_msg);
|
||||||
|
|
||||||
|
/* run command processing event loop until we get our signature */
|
||||||
|
do
|
||||||
|
{
|
||||||
|
man_standalone_event_loop (man, &signal_received, 0);
|
||||||
|
if (!signal_received)
|
||||||
|
man_check_for_signals (&signal_received);
|
||||||
|
if (signal_received)
|
||||||
|
goto done;
|
||||||
|
} while (man->connection.in_extra_cmd != IEC_RSA_SIGN_FINAL);
|
||||||
|
|
||||||
|
if (buffer_list_defined(man->connection.in_extra))
|
||||||
|
{
|
||||||
|
buffer_list_aggregate (man->connection.in_extra, 2000);
|
||||||
|
buf = buffer_list_peek (man->connection.in_extra);
|
||||||
|
if (buf && BLEN(buf) > 0)
|
||||||
|
{
|
||||||
|
ret = (char *) malloc(BLEN(buf)+1);
|
||||||
|
check_malloc_return(ret);
|
||||||
|
memcpy(ret, buf->data, BLEN(buf));
|
||||||
|
ret[BLEN(buf)] = '\0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
done:
|
||||||
|
/* revert state */
|
||||||
|
man->persist.standalone_disabled = standalone_disabled_save;
|
||||||
|
man->persist.special_state_msg = NULL;
|
||||||
|
in_extra_reset (&man->connection, IER_RESET);
|
||||||
|
|
||||||
|
gc_free (&gc);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Return true if management_hold() would block
|
* Return true if management_hold() would block
|
||||||
*/
|
*/
|
||||||
|
24
manage.h
24
manage.h
@ -264,15 +264,22 @@ struct man_connection {
|
|||||||
struct command_line *in;
|
struct command_line *in;
|
||||||
struct buffer_list *out;
|
struct buffer_list *out;
|
||||||
|
|
||||||
#ifdef MANAGEMENT_DEF_AUTH
|
#ifdef MANAGEMENT_IN_EXTRA
|
||||||
# define IEC_UNDEF 0
|
# define IEC_UNDEF 0
|
||||||
# define IEC_CLIENT_AUTH 1
|
# define IEC_CLIENT_AUTH 1
|
||||||
# define IEC_CLIENT_PF 2
|
# define IEC_CLIENT_PF 2
|
||||||
|
|
||||||
|
# define IEC_STATEFUL_BASE 16
|
||||||
|
# define IEC_RSA_SIGN_PRE 16
|
||||||
|
# define IEC_RSA_SIGN 17
|
||||||
|
# define IEC_RSA_SIGN_FINAL 18
|
||||||
int in_extra_cmd;
|
int in_extra_cmd;
|
||||||
|
struct buffer_list *in_extra;
|
||||||
|
#ifdef MANAGEMENT_DEF_AUTH
|
||||||
unsigned long in_extra_cid;
|
unsigned long in_extra_cid;
|
||||||
unsigned int in_extra_kid;
|
unsigned int in_extra_kid;
|
||||||
struct buffer_list *in_extra;
|
|
||||||
int env_filter_level;
|
int env_filter_level;
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
struct event_set *es;
|
struct event_set *es;
|
||||||
|
|
||||||
@ -285,6 +292,10 @@ struct man_connection {
|
|||||||
const char *up_query_type;
|
const char *up_query_type;
|
||||||
int up_query_mode;
|
int up_query_mode;
|
||||||
struct user_pass up_query;
|
struct user_pass up_query;
|
||||||
|
|
||||||
|
#ifdef MANAGMENT_EXTERNAL_KEY
|
||||||
|
struct buffer_list *rsa_sig;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
struct management
|
struct management
|
||||||
@ -314,6 +325,9 @@ struct management *management_init (void);
|
|||||||
# define MF_CLIENT_PF (1<<7)
|
# define MF_CLIENT_PF (1<<7)
|
||||||
#endif
|
#endif
|
||||||
# define MF_UNIX_SOCK (1<<8)
|
# define MF_UNIX_SOCK (1<<8)
|
||||||
|
#ifdef MANAGMENT_EXTERNAL_KEY
|
||||||
|
# define MF_EXTERNAL_KEY (1<<9)
|
||||||
|
#endif
|
||||||
|
|
||||||
bool management_open (struct management *man,
|
bool management_open (struct management *man,
|
||||||
const char *addr,
|
const char *addr,
|
||||||
@ -374,6 +388,12 @@ void management_learn_addr (struct management *management,
|
|||||||
const bool primary);
|
const bool primary);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef MANAGMENT_EXTERNAL_KEY
|
||||||
|
|
||||||
|
char *management_query_rsa_sig (struct management *man, const char *b64_data);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
static inline bool
|
static inline bool
|
||||||
management_connected (const struct management *man)
|
management_connected (const struct management *man)
|
||||||
{
|
{
|
||||||
|
2
misc.c
2
misc.c
@ -1607,7 +1607,7 @@ get_auth_challenge (const char *auth_challenge, struct gc_arena *gc)
|
|||||||
if (!buf_parse(&b, ':', work, len))
|
if (!buf_parse(&b, ':', work, len))
|
||||||
return NULL;
|
return NULL;
|
||||||
ac->user = (char *) gc_malloc (strlen(work)+1, true, gc);
|
ac->user = (char *) gc_malloc (strlen(work)+1, true, gc);
|
||||||
base64_decode(work, (void*)ac->user);
|
base64_decode(work, (void*)ac->user, -1);
|
||||||
|
|
||||||
/* parse challenge text */
|
/* parse challenge text */
|
||||||
ac->challenge_text = string_alloc(BSTR(&b), gc);
|
ac->challenge_text = string_alloc(BSTR(&b), gc);
|
||||||
|
2
ntlm.c
2
ntlm.c
@ -242,7 +242,7 @@ ntlm_phase_3 (const struct http_proxy_info *p, const char *phase_2, struct gc_ar
|
|||||||
/* pad to 21 bytes */
|
/* pad to 21 bytes */
|
||||||
memset (md4_hash + 16, 0, 5);
|
memset (md4_hash + 16, 0, 5);
|
||||||
|
|
||||||
ret_val = base64_decode( phase_2, (void *)buf2);
|
ret_val = base64_decode( phase_2, (void *)buf2, -1);
|
||||||
if (ret_val < 0)
|
if (ret_val < 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
@ -3636,6 +3636,14 @@ add_option (struct options *options,
|
|||||||
options->management_flags |= MF_CONNECT_AS_CLIENT;
|
options->management_flags |= MF_CONNECT_AS_CLIENT;
|
||||||
options->management_write_peer_info_file = p[1];
|
options->management_write_peer_info_file = p[1];
|
||||||
}
|
}
|
||||||
|
#ifdef MANAGMENT_EXTERNAL_KEY
|
||||||
|
else if (streq (p[0], "management-external-key"))
|
||||||
|
{
|
||||||
|
VERIFY_PERMISSION (OPT_P_GENERAL);
|
||||||
|
options->management_flags |= MF_EXTERNAL_KEY;
|
||||||
|
options->priv_key_file = "EXTERNAL_PRIVATE_KEY";
|
||||||
|
}
|
||||||
|
#endif
|
||||||
#ifdef MANAGEMENT_DEF_AUTH
|
#ifdef MANAGEMENT_DEF_AUTH
|
||||||
else if (streq (p[0], "management-client-auth"))
|
else if (streq (p[0], "management-client-auth"))
|
||||||
{
|
{
|
||||||
|
214
ssl.c
214
ssl.c
@ -48,6 +48,7 @@
|
|||||||
#include "gremlin.h"
|
#include "gremlin.h"
|
||||||
#include "pkcs11.h"
|
#include "pkcs11.h"
|
||||||
#include "list.h"
|
#include "list.h"
|
||||||
|
#include "base64.h"
|
||||||
|
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
#include "cryptoapi.h"
|
#include "cryptoapi.h"
|
||||||
@ -1315,6 +1316,195 @@ info_callback (INFO_CALLBACK_SSL_CONST SSL * s, int where, int ret)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef MANAGMENT_EXTERNAL_KEY
|
||||||
|
|
||||||
|
/* encrypt */
|
||||||
|
static int
|
||||||
|
rsa_pub_enc(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding)
|
||||||
|
{
|
||||||
|
ASSERT(0);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* verify arbitrary data */
|
||||||
|
static int
|
||||||
|
rsa_pub_dec(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding)
|
||||||
|
{
|
||||||
|
ASSERT(0);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* decrypt */
|
||||||
|
static int
|
||||||
|
rsa_priv_dec(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding)
|
||||||
|
{
|
||||||
|
ASSERT(0);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* called at RSA_free */
|
||||||
|
static int
|
||||||
|
rsa_finish(RSA *rsa)
|
||||||
|
{
|
||||||
|
free ((void*)rsa->meth);
|
||||||
|
rsa->meth = NULL;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* sign arbitrary data */
|
||||||
|
static int
|
||||||
|
rsa_priv_enc(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding)
|
||||||
|
{
|
||||||
|
/* optional app data in rsa->meth->app_data; */
|
||||||
|
char *in_b64 = NULL;
|
||||||
|
char *out_b64 = NULL;
|
||||||
|
int ret = -1;
|
||||||
|
int len;
|
||||||
|
|
||||||
|
if (padding != RSA_PKCS1_PADDING)
|
||||||
|
{
|
||||||
|
RSAerr (RSA_F_RSA_EAY_PRIVATE_ENCRYPT, RSA_R_UNKNOWN_PADDING_TYPE);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* convert 'from' to base64 */
|
||||||
|
if (base64_encode (from, flen, &in_b64) <= 0)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
/* call MI for signature */
|
||||||
|
if (management)
|
||||||
|
out_b64 = management_query_rsa_sig (management, in_b64);
|
||||||
|
if (!out_b64)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
/* decode base64 signature to binary */
|
||||||
|
len = RSA_size(rsa);
|
||||||
|
ret = base64_decode (out_b64, to, len);
|
||||||
|
|
||||||
|
/* verify length */
|
||||||
|
if (ret != len)
|
||||||
|
ret = -1;
|
||||||
|
|
||||||
|
done:
|
||||||
|
if (in_b64)
|
||||||
|
free (in_b64);
|
||||||
|
if (out_b64)
|
||||||
|
free (out_b64);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
use_external_private_key (SSL_CTX *ssl_ctx, X509 *cert)
|
||||||
|
{
|
||||||
|
RSA *rsa = NULL;
|
||||||
|
RSA *pub_rsa;
|
||||||
|
RSA_METHOD *rsa_meth;
|
||||||
|
|
||||||
|
/* allocate custom RSA method object */
|
||||||
|
ALLOC_OBJ_CLEAR (rsa_meth, RSA_METHOD);
|
||||||
|
rsa_meth->name = "OpenVPN external private key RSA Method";
|
||||||
|
rsa_meth->rsa_pub_enc = rsa_pub_enc;
|
||||||
|
rsa_meth->rsa_pub_dec = rsa_pub_dec;
|
||||||
|
rsa_meth->rsa_priv_enc = rsa_priv_enc;
|
||||||
|
rsa_meth->rsa_priv_dec = rsa_priv_dec;
|
||||||
|
rsa_meth->init = NULL;
|
||||||
|
rsa_meth->finish = rsa_finish;
|
||||||
|
rsa_meth->flags = RSA_METHOD_FLAG_NO_CHECK;
|
||||||
|
rsa_meth->app_data = NULL;
|
||||||
|
|
||||||
|
/* allocate RSA object */
|
||||||
|
rsa = RSA_new();
|
||||||
|
if (rsa == NULL)
|
||||||
|
{
|
||||||
|
SSLerr(SSL_F_SSL_USE_PRIVATEKEY, ERR_R_MALLOC_FAILURE);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* get the public key */
|
||||||
|
ASSERT(cert->cert_info->key->pkey); /* NULL before SSL_CTX_use_certificate() is called */
|
||||||
|
pub_rsa = cert->cert_info->key->pkey->pkey.rsa;
|
||||||
|
|
||||||
|
/* initialize RSA object */
|
||||||
|
rsa->n = BN_dup(pub_rsa->n);
|
||||||
|
rsa->flags |= RSA_FLAG_EXT_PKEY;
|
||||||
|
if (!RSA_set_method(rsa, rsa_meth))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
/* bind our custom RSA object to ssl_ctx */
|
||||||
|
if (!SSL_CTX_use_RSAPrivateKey(ssl_ctx, rsa))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
RSA_free(rsa); /* doesn't necessarily free, just decrements refcount */
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
err:
|
||||||
|
if (rsa)
|
||||||
|
RSA_free(rsa);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (rsa_meth)
|
||||||
|
free(rsa_meth);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Basically a clone of SSL_CTX_use_certificate_file, but also return
|
||||||
|
* the x509 object.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
use_certificate_file(SSL_CTX *ctx, const char *file, int type, X509 **x509)
|
||||||
|
{
|
||||||
|
int j;
|
||||||
|
BIO *in;
|
||||||
|
int ret=0;
|
||||||
|
X509 *x=NULL;
|
||||||
|
|
||||||
|
in=BIO_new(BIO_s_file_internal());
|
||||||
|
if (in == NULL)
|
||||||
|
{
|
||||||
|
SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE,ERR_R_BUF_LIB);
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (BIO_read_filename(in,file) <= 0)
|
||||||
|
{
|
||||||
|
SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE,ERR_R_SYS_LIB);
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
if (type == SSL_FILETYPE_ASN1)
|
||||||
|
{
|
||||||
|
j=ERR_R_ASN1_LIB;
|
||||||
|
x=d2i_X509_bio(in,NULL);
|
||||||
|
}
|
||||||
|
else if (type == SSL_FILETYPE_PEM)
|
||||||
|
{
|
||||||
|
j=ERR_R_PEM_LIB;
|
||||||
|
x=PEM_read_bio_X509(in,NULL,ctx->default_passwd_callback,ctx->default_passwd_callback_userdata);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE,SSL_R_BAD_SSL_FILETYPE);
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (x == NULL)
|
||||||
|
{
|
||||||
|
SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE,j);
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret=SSL_CTX_use_certificate(ctx,x);
|
||||||
|
end:
|
||||||
|
if (in != NULL)
|
||||||
|
BIO_free(in);
|
||||||
|
if (x509)
|
||||||
|
*x509 = x;
|
||||||
|
return(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
#if ENABLE_INLINE_FILES
|
#if ENABLE_INLINE_FILES
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@ -1422,7 +1612,7 @@ use_inline_load_client_CA_file (SSL_CTX *ctx, const char *ca_string)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
use_inline_certificate_file (SSL_CTX *ctx, const char *cert_string)
|
use_inline_certificate_file (SSL_CTX *ctx, const char *cert_string, X509 **x509)
|
||||||
{
|
{
|
||||||
BIO *in = NULL;
|
BIO *in = NULL;
|
||||||
X509 *x = NULL;
|
X509 *x = NULL;
|
||||||
@ -1446,6 +1636,8 @@ use_inline_certificate_file (SSL_CTX *ctx, const char *cert_string)
|
|||||||
X509_free (x);
|
X509_free (x);
|
||||||
if (in)
|
if (in)
|
||||||
BIO_free (in);
|
BIO_free (in);
|
||||||
|
if (x509)
|
||||||
|
*x509 = x;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1490,6 +1682,7 @@ init_ssl (const struct options *options)
|
|||||||
DH *dh;
|
DH *dh;
|
||||||
BIO *bio;
|
BIO *bio;
|
||||||
bool using_cert_file = false;
|
bool using_cert_file = false;
|
||||||
|
X509 *my_cert = NULL;
|
||||||
|
|
||||||
ERR_clear_error ();
|
ERR_clear_error ();
|
||||||
|
|
||||||
@ -1589,7 +1782,6 @@ init_ssl (const struct options *options)
|
|||||||
management_auth_failure (management, UP_TYPE_PRIVATE_KEY, NULL);
|
management_auth_failure (management, UP_TYPE_PRIVATE_KEY, NULL);
|
||||||
#endif
|
#endif
|
||||||
PKCS12_free(p12);
|
PKCS12_free(p12);
|
||||||
msg (M_INFO, "OpenSSL ERROR code: %d", (ERR_GET_REASON (ERR_peek_error()))); // fixme
|
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1657,18 +1849,32 @@ init_ssl (const struct options *options)
|
|||||||
#if ENABLE_INLINE_FILES
|
#if ENABLE_INLINE_FILES
|
||||||
if (!strcmp (options->cert_file, INLINE_FILE_TAG) && options->cert_file_inline)
|
if (!strcmp (options->cert_file, INLINE_FILE_TAG) && options->cert_file_inline)
|
||||||
{
|
{
|
||||||
if (!use_inline_certificate_file (ctx, options->cert_file_inline))
|
if (!use_inline_certificate_file (ctx, options->cert_file_inline, &my_cert))
|
||||||
msg (M_SSLERR, "Cannot load inline certificate file");
|
msg (M_SSLERR, "Cannot load inline certificate file");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
|
#ifdef MANAGMENT_EXTERNAL_KEY
|
||||||
|
if (!use_certificate_file (ctx, options->cert_file, SSL_FILETYPE_PEM, &my_cert))
|
||||||
|
#else
|
||||||
if (!SSL_CTX_use_certificate_file (ctx, options->cert_file, SSL_FILETYPE_PEM))
|
if (!SSL_CTX_use_certificate_file (ctx, options->cert_file, SSL_FILETYPE_PEM))
|
||||||
|
#endif
|
||||||
msg (M_SSLERR, "Cannot load certificate file %s", options->cert_file);
|
msg (M_SSLERR, "Cannot load certificate file %s", options->cert_file);
|
||||||
using_cert_file = true;
|
using_cert_file = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef MANAGMENT_EXTERNAL_KEY
|
||||||
|
if (options->management_flags & MF_EXTERNAL_KEY)
|
||||||
|
{
|
||||||
|
ASSERT (my_cert);
|
||||||
|
if (!use_external_private_key(ctx, my_cert))
|
||||||
|
msg (M_SSLERR, "Cannot enable SSL external private key capability");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Load Private Key */
|
/* Load Private Key */
|
||||||
if (options->priv_key_file)
|
if (options->priv_key_file)
|
||||||
{
|
{
|
||||||
@ -1795,6 +2001,8 @@ init_ssl (const struct options *options)
|
|||||||
|
|
||||||
err:
|
err:
|
||||||
ERR_clear_error ();
|
ERR_clear_error ();
|
||||||
|
if (my_cert)
|
||||||
|
X509_free(my_cert);
|
||||||
if (ctx)
|
if (ctx)
|
||||||
SSL_CTX_free (ctx);
|
SSL_CTX_free (ctx);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
15
syshead.h
15
syshead.h
@ -508,6 +508,21 @@ socket_defined (const socket_descriptor_t sd)
|
|||||||
#define ENABLE_DEF_AUTH
|
#define ENABLE_DEF_AUTH
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Enable external private key
|
||||||
|
*/
|
||||||
|
#if defined(ENABLE_MANAGEMENT) && defined(USE_SSL)
|
||||||
|
#define MANAGMENT_EXTERNAL_KEY
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* MANAGEMENT_IN_EXTRA allows the management interface to
|
||||||
|
* read multi-line inputs from clients.
|
||||||
|
*/
|
||||||
|
#if defined(MANAGEMENT_DEF_AUTH) || defined(MANAGMENT_EXTERNAL_KEY)
|
||||||
|
#define MANAGEMENT_IN_EXTRA
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Enable packet filter?
|
* Enable packet filter?
|
||||||
*/
|
*/
|
||||||
|
Loading…
Reference in New Issue
Block a user