OpenVPN supports using OpenSSL engines by loading them with the
--engine configuration option. Some of those engines require
configuration options themself.

This patch extends the --engine option so that engine-options can be
specified as well.

Signed-off-by: Heiko Hund <heiko.h...@sophos.com>
---
 doc/openvpn.8                 |   11 ++++++-----
 src/openvpn/crypto.c          |    4 ++--
 src/openvpn/crypto.h          |    2 +-
 src/openvpn/crypto_backend.h  |   17 ++++++++++++++++-
 src/openvpn/crypto_openssl.c  |   33 +++++++++++++++++++++------------
 src/openvpn/crypto_polarssl.c |    4 ++--
 src/openvpn/options.c         |   32 +++++++++++++++++++++++++++-----
 src/openvpn/options.h         |    3 ++-
 src/openvpn/ssl.c             |    4 ++--
 src/openvpn/ssl.h             |    2 +-
 10 files changed, 80 insertions(+), 32 deletions(-)

diff --git a/doc/openvpn.8 b/doc/openvpn.8
index 56be29e..d967ebd 100644
--- a/doc/openvpn.8
+++ b/doc/openvpn.8
@@ -3704,13 +3704,14 @@ to disable the PRNG and use the OpenSSL RAND_bytes 
function
 instead for all of OpenVPN's pseudo-random number needs.
 .\"*********************************************************
 .TP
-.B \-\-engine [engine-name]
-Enable OpenSSL hardware-based crypto engine functionality.
-
+.B \-\-engine [engine-name [engine-option ...]]
+Enable OpenSSL crypto engine functionality.
 If
 .B engine-name
-is specified,
-use a specific crypto engine.  Use the
+is specified, use a specific crypto engine.
+.B engine-options
+must be given as name=value pairs.
+Use the
 .B \-\-show-engines
 standalone option to list the crypto engines which are
 supported by OpenSSL.
diff --git a/src/openvpn/crypto.c b/src/openvpn/crypto.c
index b95865e..7fdbb95 100644
--- a/src/openvpn/crypto.c
+++ b/src/openvpn/crypto.c
@@ -1376,9 +1376,9 @@ get_random()
 #ifndef ENABLE_SSL

 void
-init_ssl_lib (const char *engine_name)
+init_ssl_lib (const struct crypto_engine *engine)
 {
-  crypto_init_lib (engine_name);
+  crypto_init_lib (engine);
 }

 void
diff --git a/src/openvpn/crypto.h b/src/openvpn/crypto.h
index cd08cf3..5c34597 100644
--- a/src/openvpn/crypto.h
+++ b/src/openvpn/crypto.h
@@ -358,7 +358,7 @@ void get_tls_handshake_key (const struct key_type *key_type,

 #else

-void init_ssl_lib (const char *engine_name);
+void init_ssl_lib (const struct crypto_engine *engine);
 void free_ssl_lib (void);

 #endif /* ENABLE_SSL */
diff --git a/src/openvpn/crypto_backend.h b/src/openvpn/crypto_backend.h
index 9727a92..4b68687 100644
--- a/src/openvpn/crypto_backend.h
+++ b/src/openvpn/crypto_backend.h
@@ -40,10 +40,25 @@


 /*
+ * Structures for crypto library engine configuration.
+ */
+struct crypto_engine_option
+{
+  struct crypto_engine_option *next;
+  const char *name;
+  const char *value;
+};
+struct crypto_engine
+{
+  const char *name;
+  struct crypto_engine_option *options;
+};
+
+/*
  * This routine should have additional OpenSSL crypto library initialisations
  * used by both crypto and ssl components of OpenVPN.
  */
-void crypto_init_lib (const char *engine_name);
+void crypto_init_lib (const struct crypto_engine *engine);

 void crypto_uninit_lib (void);

diff --git a/src/openvpn/crypto_openssl.c b/src/openvpn/crypto_openssl.c
index a7ee168..deaf0ca 100644
--- a/src/openvpn/crypto_openssl.c
+++ b/src/openvpn/crypto_openssl.c
@@ -135,7 +135,7 @@ try_load_engine (const char *engine)
 }

 static ENGINE *
-setup_engine (const char *engine)
+setup_engine (const struct crypto_engine *engine)
 {
   ENGINE *e = NULL;

@@ -143,24 +143,33 @@ setup_engine (const char *engine)

   if (engine)
     {
-      if (strcmp (engine, "auto") == 0)
+      struct crypto_engine_option *o;
+      
+      if (strcmp (engine->name, "auto") == 0)
        {
          msg (M_INFO, "Initializing OpenSSL auto engine support");
          ENGINE_register_all_complete ();
          return NULL;
        }
-      if ((e = ENGINE_by_id (engine)) == NULL
-        && (e = try_load_engine (engine)) == NULL)
+      if ((e = ENGINE_by_id (engine->name)) == NULL
+        && (e = try_load_engine (engine->name)) == NULL)
        {
-         msg (M_FATAL, "OpenSSL error: cannot load engine '%s'", engine);
+         msg (M_FATAL, "OpenSSL error: cannot load engine '%s'", engine->name);
        }

       if (!ENGINE_set_default (e, ENGINE_METHOD_ALL))
        {
          msg (M_FATAL, "OpenSSL error: ENGINE_set_default failed on engine 
'%s'",
-              engine);
+              engine->name);
        }

+      for (o = engine->options; o; o = o->next)
+        {
+          if (!ENGINE_ctrl_cmd_string (e, o->name, o->value, 0))
+            msg (M_FATAL, "OpenSSL error: ENGINE_ctrl_cmd_string failed on 
engine '%s'",
+                engine->name);
+        }
+
       msg (M_INFO, "Initializing OpenSSL support for engine '%s'",
           ENGINE_get_id (e));
     }
@@ -170,14 +179,14 @@ setup_engine (const char *engine)
 #endif /* HAVE_OPENSSL_ENGINE */

 static void
-crypto_init_lib_engine (const char *engine_name)
+crypto_init_lib_engine (const struct crypto_engine *engine)
 {
 #if HAVE_OPENSSL_ENGINE
   if (!engine_initialized)
     {
-      ASSERT (engine_name);
+      ASSERT (engine->name);
       ASSERT (!engine_persist);
-      engine_persist = setup_engine (engine_name);
+      engine_persist = setup_engine (engine);
       engine_initialized = true;
     }
 #else
@@ -192,10 +201,10 @@ crypto_init_lib_engine (const char *engine_name)
  */

 void
-crypto_init_lib (const char *engine_name)
+crypto_init_lib (const struct crypto_engine *engine)
 {
-  if (engine_name)
-    crypto_init_lib_engine (engine_name);
+  if (engine)
+    crypto_init_lib_engine (engine);

 #ifndef USE_SSL
 #ifndef ENABLE_SMALL
diff --git a/src/openvpn/crypto_polarssl.c b/src/openvpn/crypto_polarssl.c
index b7f13e3..6b1193a 100644
--- a/src/openvpn/crypto_polarssl.c
+++ b/src/openvpn/crypto_polarssl.c
@@ -59,9 +59,9 @@
  */

 void
-crypto_init_lib (const char *engine_name)
+crypto_init_lib (const struct crypto_engine *engine)
 {
-  if (engine_name)
+  if (engine)
     msg (M_WARN, "Note: PolarSSL hardware crypto engine functionality is not "
         "available");
 }
diff --git a/src/openvpn/options.c b/src/openvpn/options.c
index 19690e1..b78ff15 100644
--- a/src/openvpn/options.c
+++ b/src/openvpn/options.c
@@ -531,7 +531,7 @@ static const char usage_message[] =
   "                  If unspecified, defaults to cipher-specific default.\n"
 #endif
 #ifndef ENABLE_CRYPTO_POLARSSL
-  "--engine [name] : Enable OpenSSL hardware crypto engine functionality.\n"
+  "--engine [name [opts]] : Enable OpenSSL crypto engine functionality.\n"
 #endif
   "--no-replay     : Disable replay protection.\n"
   "--mute-replay-warnings : Silence the output of replay warnings to log 
file.\n"
@@ -6287,12 +6287,34 @@ add_option (struct options *options,
   else if (streq (p[0], "engine"))
     {
       VERIFY_PERMISSION (OPT_P_GENERAL);
+      ALLOC_OBJ_CLEAR_GC (options->engine, struct crypto_engine, &options->gc);
+      
       if (p[1])
-       {
-         options->engine = p[1];
-       }
+        {
+          int i;
+
+          options->engine->name = p[1];
+
+          for (i = 2; p[i]; i++)
+            {
+              struct crypto_engine_option *next_option;
+              char *eq = strchr (p[i], '=');
+              if (eq == NULL)
+                {
+                  msg (msglevel, "Bad option for engine %s: %s", p[1], p[i]);
+                  goto err;
+                }
+              *eq = '\0';
+
+              next_option = options->engine->options;
+              ALLOC_OBJ_GC (options->engine->options, struct 
crypto_engine_option, &options->gc);
+              options->engine->options->next = next_option;
+              options->engine->options->name = p[i];
+              options->engine->options->value = eq + 1;
+            }
+        }
       else
-       options->engine = "auto";
+        options->engine->name = "auto";
     }  
 #endif /* ENABLE_CRYPTO_POLARSSL */
 #ifdef HAVE_EVP_CIPHER_CTX_SET_KEY_LENGTH
diff --git a/src/openvpn/options.h b/src/openvpn/options.h
index 306520b..36eab25 100644
--- a/src/openvpn/options.h
+++ b/src/openvpn/options.h
@@ -42,6 +42,7 @@
 #include "lzo.h"
 #include "pushlist.h"
 #include "clinat.h"
+#include "crypto.h"

 /*
  * Maximum number of parameters associated with an option,
@@ -481,7 +482,7 @@ struct options
   int keysize;
   const char *prng_hash;
   int prng_nonce_secret_len;
-  const char *engine;
+  struct crypto_engine *engine;
   bool replay;
   bool mute_replay_warnings;
   int replay_window;
diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c
index e9a7d0a..a1a0628 100644
--- a/src/openvpn/ssl.c
+++ b/src/openvpn/ssl.c
@@ -153,9 +153,9 @@ tls_init_control_channel_frame_parameters(const struct 
frame *data_channel_frame
 }

 void
-init_ssl_lib (const char *engine_name)
+init_ssl_lib (const struct crypto_engine *engine)
 {
-  crypto_init_lib (engine_name);
+  crypto_init_lib (engine);
   tls_init_lib ();
 }

diff --git a/src/openvpn/ssl.h b/src/openvpn/ssl.h
index daa654c..001e4fd 100644
--- a/src/openvpn/ssl.h
+++ b/src/openvpn/ssl.h
@@ -144,7 +144,7 @@ struct tls_auth_standalone
 /*
  * Prepare the SSL library for use
  */
-void init_ssl_lib (const char *engine_name);
+void init_ssl_lib (const struct crypto_engine *engine);

 /*
  * Free any internal state that the SSL library might have
-- 
1.7.9.5


Reply via email to