summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJames Yonan <james@openvpn.net>2010-12-09 11:21:04 +0000
committerDavid Sommerseth <davids@redhat.com>2011-03-25 09:38:28 +0100
commitcf69617bbea45a15423c4188daa9386debcbe1ec (patch)
treec3786b3116633d98e037c76f3ced6378e05edcad
parent98c6662472adf7228e4265328aa8d067aa41695f (diff)
downloadopenvpn-cf69617bbea45a15423c4188daa9386debcbe1ec.tar.gz
openvpn-cf69617bbea45a15423c4188daa9386debcbe1ec.tar.xz
openvpn-cf69617bbea45a15423c4188daa9386debcbe1ec.zip
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
-rw-r--r--base64.c17
-rw-r--r--base64.h4
-rw-r--r--buffer.c2
-rw-r--r--manage.c204
-rw-r--r--manage.h24
-rw-r--r--misc.c2
-rw-r--r--ntlm.c2
-rw-r--r--options.c8
-rw-r--r--ssl.c214
-rw-r--r--syshead.h15
10 files changed, 433 insertions, 59 deletions
diff --git a/base64.c b/base64.c
index 3449ae5..8f0fb6c 100644
--- a/base64.c
+++ b/base64.c
@@ -33,7 +33,7 @@
#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"
@@ -115,22 +115,35 @@ token_decode(const char *token)
}
int
-base64_decode(const char *str, void *data)
+base64_decode(const char *str, void *data, int size)
{
const char *p;
unsigned char *q;
+ unsigned char *e = NULL;
q = data;
+ if (size >= 0)
+ e = q + size;
for (p = str; *p && (*p == '=' || strchr(base64_chars, *p)); p += 4) {
unsigned int val = token_decode(p);
unsigned int marker = (val >> 24) & 0xff;
if (val == DECODE_ERROR)
return -1;
+ if (e && q >= e)
+ return -1;
*q++ = (val >> 16) & 0xff;
if (marker < 2)
+ {
+ if (e && q >= e)
+ return -1;
*q++ = (val >> 8) & 0xff;
+ }
if (marker < 1)
+ {
+ if (e && q >= e)
+ return -1;
*q++ = val & 0xff;
+ }
}
return q - (unsigned char *) data;
}
diff --git a/base64.h b/base64.h
index 968d18d..64439a0 100644
--- a/base64.h
+++ b/base64.h
@@ -34,10 +34,10 @@
#ifndef _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_decode(const char *str, void *data);
+int base64_decode(const char *str, void *data, int size);
#endif
diff --git a/buffer.c b/buffer.c
index 947df90..e2f8caa 100644
--- a/buffer.c
+++ b/buffer.c
@@ -901,7 +901,7 @@ buffer_list_free (struct buffer_list *ol)
bool
buffer_list_defined (const struct buffer_list *ol)
{
- return ol->head != NULL;
+ return ol && ol->head != NULL;
}
void
diff --git a/manage.c b/manage.c
index 820621e..0c99d0f 100644
--- a/manage.c
+++ b/manage.c
@@ -102,6 +102,10 @@ man_help ()
msg (M_CLIENT, "client-pf CID : Define packet filter for client CID (MULTILINE)");
#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
msg (M_CLIENT, "signal s : Send signal s to daemon,");
msg (M_CLIENT, " s = SIGHUP|SIGTERM|SIGUSR1|SIGUSR2.");
msg (M_CLIENT, "state [on|off] [N|all] : Like log, but show state history.");
@@ -768,49 +772,31 @@ man_hold (struct management *man, const char *cmd)
msg (M_CLIENT, "SUCCESS: hold=%d", BOOL_CAST(man->settings.flags & MF_HOLD));
}
-#ifdef MANAGEMENT_DEF_AUTH
-
-static bool
-parse_cid (const char *str, unsigned long *cid)
-{
- if (sscanf (str, "%lu", cid) == 1)
- return true;
- else
- {
- msg (M_CLIENT, "ERROR: cannot parse CID");
- return false;
- }
-}
+#ifdef MANAGEMENT_IN_EXTRA
-static bool
-parse_kid (const char *str, unsigned int *kid)
-{
- if (sscanf (str, "%u", kid) == 1)
- return true;
- else
- {
- msg (M_CLIENT, "ERROR: cannot parse KID");
- return false;
- }
-}
+#define IER_RESET 0
+#define IER_NEW 1
+#define IER_CONDRESET 2
static void
-in_extra_reset (struct man_connection *mc, const bool new)
+in_extra_reset (struct man_connection *mc, const int mode)
{
- if (mc)
+ if (mc && (mc->in_extra_cmd < IEC_STATEFUL_BASE || mode != IER_CONDRESET))
{
- if (!new)
+ 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 (new)
+ if (mode == IER_NEW)
mc->in_extra = buffer_list_new (0);
}
}
@@ -820,6 +806,7 @@ 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)
{
@@ -846,6 +833,7 @@ in_extra_dispatch (struct management *man)
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)
@@ -870,8 +858,41 @@ in_extra_dispatch (struct management *man)
}
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
+
+static bool
+parse_cid (const char *str, unsigned long *cid)
+{
+ if (sscanf (str, "%lu", cid) == 1)
+ return true;
+ else
+ {
+ msg (M_CLIENT, "ERROR: cannot parse CID");
+ return false;
+ }
+}
+
+static bool
+parse_kid (const char *str, unsigned int *kid)
+{
+ if (sscanf (str, "%u", kid) == 1)
+ return true;
+ else
+ {
+ msg (M_CLIENT, "ERROR: cannot parse KID");
+ return false;
}
- in_extra_reset (&man->connection, false);
}
static void
@@ -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))
{
mc->in_extra_cmd = IEC_CLIENT_AUTH;
- in_extra_reset (mc, true);
+ in_extra_reset (mc, IER_NEW);
if (!extra)
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))
{
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
static void
@@ -1250,6 +1288,12 @@ man_dispatch_command (struct management *man, struct status_output *so, const ch
}
#endif
#endif
+#ifdef MANAGMENT_EXTERNAL_KEY
+ else if (streq (p[0], "rsa-sig"))
+ {
+ man_rsa_sig (man);
+ }
+#endif
#ifdef ENABLE_PKCS11
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;
command_line_reset (man->connection.in);
buffer_list_reset (man->connection.out);
-#ifdef MANAGEMENT_DEF_AUTH
- in_extra_reset (&man->connection, false);
+#ifdef MANAGEMENT_IN_EXTRA
+ in_extra_reset (&man->connection, IER_RESET);
#endif
msg (D_MANAGEMENT, "MANAGEMENT: Client disconnected");
}
@@ -1666,8 +1710,8 @@ man_process_command (struct management *man, const char *line)
CLEAR (parms);
so = status_open (NULL, 0, -1, &man->persist.vout, 0);
-#ifdef MANAGEMENT_DEF_AUTH
- in_extra_reset (&man->connection, false);
+#ifdef MANAGEMENT_IN_EXTRA
+ in_extra_reset (&man->connection, IER_CONDRESET);
#endif
if (man_password_needed (man))
@@ -1751,18 +1795,13 @@ man_read (struct management *man)
const unsigned char *line;
while ((line = command_line_get (man->connection.in)))
{
-#ifdef MANAGEMENT_DEF_AUTH
+#ifdef MANAGEMENT_IN_EXTRA
if (man->connection.in_extra)
{
if (!strcmp ((char *)line, "END"))
- {
- in_extra_dispatch (man);
- in_extra_reset (&man->connection, false);
- }
+ in_extra_dispatch (man);
else
- {
- buffer_list_push (man->connection.in_extra, line);
- }
+ buffer_list_push (man->connection.in_extra, line);
}
else
#endif
@@ -2063,8 +2102,8 @@ man_connection_close (struct management *man)
command_line_free (mc->in);
if (mc->out)
buffer_list_free (mc->out);
-#ifdef MANAGEMENT_DEF_AUTH
- in_extra_reset (&man->connection, false);
+#ifdef MANAGEMENT_IN_EXTRA
+ in_extra_reset (&man->connection, IER_RESET);
#endif
man_connection_clear (mc);
}
@@ -2387,7 +2426,7 @@ management_learn_addr (struct management *management,
gc_free (&gc);
}
-#endif
+#endif /* MANAGEMENT_DEF_AUTH */
void
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_HOLD_WAIT (1<<1)
+#define MWCC_OTHER_WAIT (1<<2)
/*
* 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...");
if (flags & MWCC_HOLD_WAIT)
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 {
man_standalone_event_loop (man, signal_received, expire);
if (signal_received && *signal_received)
@@ -2873,6 +2915,74 @@ management_query_user_pass (struct management *man,
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
*/
diff --git a/manage.h b/manage.h
index 6a9ccd8..697ddf8 100644
--- a/manage.h
+++ b/manage.h
@@ -264,16 +264,23 @@ struct man_connection {
struct command_line *in;
struct buffer_list *out;
-#ifdef MANAGEMENT_DEF_AUTH
+#ifdef MANAGEMENT_IN_EXTRA
# define IEC_UNDEF 0
# define IEC_CLIENT_AUTH 1
# 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;
+ struct buffer_list *in_extra;
+#ifdef MANAGEMENT_DEF_AUTH
unsigned long in_extra_cid;
unsigned int in_extra_kid;
- struct buffer_list *in_extra;
int env_filter_level;
#endif
+#endif
struct event_set *es;
bool state_realtime;
@@ -285,6 +292,10 @@ struct man_connection {
const char *up_query_type;
int up_query_mode;
struct user_pass up_query;
+
+#ifdef MANAGMENT_EXTERNAL_KEY
+ struct buffer_list *rsa_sig;
+#endif
};
struct management
@@ -314,6 +325,9 @@ struct management *management_init (void);
# define MF_CLIENT_PF (1<<7)
#endif
# define MF_UNIX_SOCK (1<<8)
+#ifdef MANAGMENT_EXTERNAL_KEY
+# define MF_EXTERNAL_KEY (1<<9)
+#endif
bool management_open (struct management *man,
const char *addr,
@@ -374,6 +388,12 @@ void management_learn_addr (struct management *management,
const bool primary);
#endif
+#ifdef MANAGMENT_EXTERNAL_KEY
+
+char *management_query_rsa_sig (struct management *man, const char *b64_data);
+
+#endif
+
static inline bool
management_connected (const struct management *man)
{
diff --git a/misc.c b/misc.c
index 4067d85..9e70744 100644
--- a/misc.c
+++ b/misc.c
@@ -1618,7 +1618,7 @@ get_auth_challenge (const char *auth_challenge, struct gc_arena *gc)
if (!buf_parse(&b, ':', work, len))
return NULL;
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 */
ac->challenge_text = string_alloc(BSTR(&b), gc);
diff --git a/ntlm.c b/ntlm.c
index 0453358..4dfeed3 100644
--- a/ntlm.c
+++ b/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 */
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)
return NULL;
diff --git a/options.c b/options.c
index 4f6434b..fca4a8e 100644
--- a/options.c
+++ b/options.c
@@ -3663,6 +3663,14 @@ add_option (struct options *options,
options->management_flags |= MF_CONNECT_AS_CLIENT;
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
else if (streq (p[0], "management-client-auth"))
{
diff --git a/ssl.c b/ssl.c
index 7b2291c..66ee14d 100644
--- a/ssl.c
+++ b/ssl.c
@@ -51,6 +51,7 @@
#include "gremlin.h"
#include "pkcs11.h"
#include "list.h"
+#include "base64.h"
#ifdef WIN32
#include "cryptoapi.h"
@@ -1482,6 +1483,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
static int
@@ -1589,7 +1779,7 @@ use_inline_load_client_CA_file (SSL_CTX *ctx, const char *ca_string)
}
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;
X509 *x = NULL;
@@ -1613,6 +1803,8 @@ use_inline_certificate_file (SSL_CTX *ctx, const char *cert_string)
X509_free (x);
if (in)
BIO_free (in);
+ if (x509)
+ *x509 = x;
return ret;
}
@@ -1657,6 +1849,7 @@ init_ssl (const struct options *options)
DH *dh;
BIO *bio;
bool using_cert_file = false;
+ X509 *my_cert = NULL;
ERR_clear_error ();
@@ -1756,7 +1949,6 @@ init_ssl (const struct options *options)
management_auth_failure (management, UP_TYPE_PRIVATE_KEY, NULL);
#endif
PKCS12_free(p12);
- msg (M_INFO, "OpenSSL ERROR code: %d", (ERR_GET_REASON (ERR_peek_error()))); // fixme
goto err;
}
}
@@ -1824,18 +2016,32 @@ init_ssl (const struct options *options)
#if ENABLE_INLINE_FILES
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");
}
else
#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))
+#endif
msg (M_SSLERR, "Cannot load certificate file %s", options->cert_file);
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 */
if (options->priv_key_file)
{
@@ -1967,6 +2173,8 @@ init_ssl (const struct options *options)
err:
ERR_clear_error ();
+ if (my_cert)
+ X509_free(my_cert);
if (ctx)
SSL_CTX_free (ctx);
return NULL;
diff --git a/syshead.h b/syshead.h
index 63b82ba..30ff556 100644
--- a/syshead.h
+++ b/syshead.h
@@ -510,6 +510,21 @@ socket_defined (const socket_descriptor_t sd)
#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?
*/
#if defined(CONFIGURE_PF) && P2MP_SERVER && defined(ENABLE_PLUGIN) && defined(HAVE_STAT)