summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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 5108429..2952767 100644
--- a/buffer.c
+++ b/buffer.c
@@ -906,7 +906,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 f5a3b89..0f9dfcc 100644
--- a/misc.c
+++ b/misc.c
@@ -1607,7 +1607,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 b95ceb5..95b6254 100644
--- a/options.c
+++ b/options.c
@@ -3636,6 +3636,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 0f93cef..9ab907c 100644
--- a/ssl.c
+++ b/ssl.c
@@ -48,6 +48,7 @@
#include "gremlin.h"
#include "pkcs11.h"
#include "list.h"
+#include "base64.h"
#ifdef WIN32
#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
static int
@@ -1422,7 +1612,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;
@@ -1446,6 +1636,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;
}
@@ -1490,6 +1682,7 @@ init_ssl (const struct options *options)
DH *dh;
BIO *bio;
bool using_cert_file = false;
+ X509 *my_cert = NULL;
ERR_clear_error ();
@@ -1589,7 +1782,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;
}
}
@@ -1657,18 +1849,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)
{
@@ -1795,6 +2001,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 bad5ce0..3b835f7 100644
--- a/syshead.h
+++ b/syshead.h
@@ -509,6 +509,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)