Browse code

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

James Yonan authored on 2010/12/09 20:21:04
Showing 10 changed files
... ...
@@ -33,7 +33,7 @@
33 33
 
34 34
 #include "syshead.h"
35 35
 
36
-#if defined(ENABLE_HTTP_PROXY) || defined(ENABLE_PKCS11) || defined(ENABLE_CLIENT_CR)
36
+#if defined(ENABLE_HTTP_PROXY) || defined(ENABLE_PKCS11) || defined(ENABLE_CLIENT_CR) || defined(MANAGMENT_EXTERNAL_KEY)
37 37
 
38 38
 #include "base64.h"
39 39
 
... ...
@@ -115,22 +115,35 @@ token_decode(const char *token)
115 115
 }
116 116
 
117 117
 int
118
-base64_decode(const char *str, void *data)
118
+base64_decode(const char *str, void *data, int size)
119 119
 {
120 120
     const char *p;
121 121
     unsigned char *q;
122
+    unsigned char *e = NULL;
122 123
 
123 124
     q = data;
125
+    if (size >= 0)
126
+      e = q + size;
124 127
     for (p = str; *p && (*p == '=' || strchr(base64_chars, *p)); p += 4) {
125 128
 	unsigned int val = token_decode(p);
126 129
 	unsigned int marker = (val >> 24) & 0xff;
127 130
 	if (val == DECODE_ERROR)
128 131
 	    return -1;
132
+	if (e && q >= e)
133
+	  return -1;
129 134
 	*q++ = (val >> 16) & 0xff;
130 135
 	if (marker < 2)
136
+	  {
137
+	    if (e && q >= e)
138
+	      return -1;
131 139
 	    *q++ = (val >> 8) & 0xff;
140
+	  }
132 141
 	if (marker < 1)
142
+	  {
143
+	    if (e && q >= e)
144
+	      return -1;
133 145
 	    *q++ = val & 0xff;
146
+	  }
134 147
     }
135 148
     return q - (unsigned char *) data;
136 149
 }
... ...
@@ -34,10 +34,10 @@
34 34
 #ifndef _BASE64_H_
35 35
 #define _BASE64_H_
36 36
 
37
-#if defined(ENABLE_HTTP_PROXY) || defined(ENABLE_PKCS11) || defined(ENABLE_CLIENT_CR)
37
+#if defined(ENABLE_HTTP_PROXY) || defined(ENABLE_PKCS11) || defined(ENABLE_CLIENT_CR) || defined(MANAGMENT_EXTERNAL_KEY)
38 38
 
39 39
 int base64_encode(const void *data, int size, char **str);
40
-int base64_decode(const char *str, void *data);
40
+int base64_decode(const char *str, void *data, int size);
41 41
 
42 42
 #endif
43 43
 
... ...
@@ -901,7 +901,7 @@ buffer_list_free (struct buffer_list *ol)
901 901
 bool
902 902
 buffer_list_defined (const struct buffer_list *ol)
903 903
 {
904
-  return ol->head != NULL;
904
+  return ol && ol->head != NULL;
905 905
 }
906 906
 
907 907
 void
... ...
@@ -102,6 +102,10 @@ man_help ()
102 102
   msg (M_CLIENT, "client-pf CID          : Define packet filter for client CID (MULTILINE)");
103 103
 #endif
104 104
 #endif
105
+#ifdef MANAGMENT_EXTERNAL_KEY
106
+  msg (M_CLIENT, "rsa-sig                : Enter an RSA signature in response to >RSA_SIGN challenge");
107
+  msg (M_CLIENT, "                         Enter signature base64 on subsequent lines followed by END");
108
+#endif
105 109
   msg (M_CLIENT, "signal s               : Send signal s to daemon,");
106 110
   msg (M_CLIENT, "                         s = SIGHUP|SIGTERM|SIGUSR1|SIGUSR2.");
107 111
   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)
768 768
     msg (M_CLIENT, "SUCCESS: hold=%d", BOOL_CAST(man->settings.flags & MF_HOLD));
769 769
 }
770 770
 
771
-#ifdef MANAGEMENT_DEF_AUTH
772
-
773
-static bool
774
-parse_cid (const char *str, unsigned long *cid)
775
-{
776
-  if (sscanf (str, "%lu", cid) == 1)
777
-    return true;
778
-  else
779
-    {
780
-      msg (M_CLIENT, "ERROR: cannot parse CID");
781
-      return false;
782
-    }
783
-}
771
+#ifdef MANAGEMENT_IN_EXTRA
784 772
 
785
-static bool
786
-parse_kid (const char *str, unsigned int *kid)
787
-{
788
-  if (sscanf (str, "%u", kid) == 1)
789
-    return true;
790
-  else
791
-    {
792
-      msg (M_CLIENT, "ERROR: cannot parse KID");
793
-      return false;
794
-    }
795
-}
773
+#define IER_RESET      0
774
+#define IER_NEW        1
775
+#define IER_CONDRESET  2
796 776
 
797 777
 static void
798
-in_extra_reset (struct man_connection *mc, const bool new)
778
+in_extra_reset (struct man_connection *mc, const int mode)
799 779
 {
800
-  if (mc)
780
+  if (mc && (mc->in_extra_cmd < IEC_STATEFUL_BASE || mode != IER_CONDRESET))
801 781
     {
802
-      if (!new)
782
+      if (mode != IER_NEW)
803 783
 	{
804 784
 	  mc->in_extra_cmd = IEC_UNDEF;
785
+#ifdef MANAGEMENT_DEF_AUTH
805 786
 	  mc->in_extra_cid = 0;
806 787
 	  mc->in_extra_kid = 0;
788
+#endif
807 789
 	}
808 790
       if (mc->in_extra)
809 791
 	{
810 792
 	  buffer_list_free (mc->in_extra);
811 793
 	  mc->in_extra = NULL;
812 794
 	}
813
-      if (new)
795
+      if (mode == IER_NEW)
814 796
 	mc->in_extra = buffer_list_new (0);
815 797
     }
816 798
 }
... ...
@@ -820,6 +806,7 @@ in_extra_dispatch (struct management *man)
820 820
 {
821 821
    switch (man->connection.in_extra_cmd)
822 822
     {
823
+#ifdef MANAGEMENT_DEF_AUTH
823 824
     case IEC_CLIENT_AUTH:
824 825
        if (man->persist.callback.client_auth)
825 826
 	{
... ...
@@ -846,6 +833,7 @@ in_extra_dispatch (struct management *man)
846 846
 	  msg (M_CLIENT, "ERROR: The client-auth command is not supported by the current daemon mode");
847 847
 	}
848 848
       break;
849
+#endif
849 850
 #ifdef MANAGEMENT_PF
850 851
     case IEC_CLIENT_PF:
851 852
       if (man->persist.callback.client_pf)
... ...
@@ -870,8 +858,41 @@ in_extra_dispatch (struct management *man)
870 870
 	}
871 871
       break;
872 872
 #endif
873
+#ifdef MANAGMENT_EXTERNAL_KEY
874
+    case IEC_RSA_SIGN:
875
+      man->connection.in_extra_cmd = IEC_RSA_SIGN_FINAL;
876
+      return;
877
+#endif
878
+    }
879
+   in_extra_reset (&man->connection, IER_RESET);
880
+}
881
+
882
+#endif /* MANAGEMENT_IN_EXTRA */
883
+
884
+#ifdef MANAGEMENT_DEF_AUTH
885
+
886
+static bool
887
+parse_cid (const char *str, unsigned long *cid)
888
+{
889
+  if (sscanf (str, "%lu", cid) == 1)
890
+    return true;
891
+  else
892
+    {
893
+      msg (M_CLIENT, "ERROR: cannot parse CID");
894
+      return false;
895
+    }
896
+}
897
+
898
+static bool
899
+parse_kid (const char *str, unsigned int *kid)
900
+{
901
+  if (sscanf (str, "%u", kid) == 1)
902
+    return true;
903
+  else
904
+    {
905
+      msg (M_CLIENT, "ERROR: cannot parse KID");
906
+      return false;
873 907
     }
874
-   in_extra_reset (&man->connection, false);
875 908
 }
876 909
 
877 910
 static void
... ...
@@ -884,7 +905,7 @@ man_client_auth (struct management *man, const char *cid_str, const char *kid_st
884 884
       && parse_kid (kid_str, &mc->in_extra_kid))
885 885
     {
886 886
       mc->in_extra_cmd = IEC_CLIENT_AUTH;
887
-      in_extra_reset (mc, true);
887
+      in_extra_reset (mc, IER_NEW);
888 888
       if (!extra)
889 889
 	in_extra_dispatch (man);
890 890
     }
... ...
@@ -980,11 +1001,28 @@ man_client_pf (struct management *man, const char *cid_str)
980 980
   if (parse_cid (cid_str, &mc->in_extra_cid))
981 981
     {
982 982
       mc->in_extra_cmd = IEC_CLIENT_PF;
983
-      in_extra_reset (mc, true);
983
+      in_extra_reset (mc, IER_NEW);
984 984
     }
985 985
 }
986 986
 
987
-#endif
987
+#endif /* MANAGEMENT_PF */
988
+#endif /* MANAGEMENT_DEF_AUTH */
989
+
990
+#ifdef MANAGMENT_EXTERNAL_KEY
991
+
992
+static void
993
+man_rsa_sig (struct management *man)
994
+{
995
+  struct man_connection *mc = &man->connection;
996
+  if (mc->in_extra_cmd == IEC_RSA_SIGN_PRE)
997
+    {
998
+      in_extra_reset (&man->connection, IER_NEW);
999
+      mc->in_extra_cmd = IEC_RSA_SIGN;
1000
+    }
1001
+  else
1002
+    msg (M_CLIENT, "ERROR: The rsa-sig command is not currently available");
1003
+}
1004
+
988 1005
 #endif
989 1006
 
990 1007
 static void
... ...
@@ -1250,6 +1288,12 @@ man_dispatch_command (struct management *man, struct status_output *so, const ch
1250 1250
     }
1251 1251
 #endif
1252 1252
 #endif
1253
+#ifdef MANAGMENT_EXTERNAL_KEY
1254
+  else if (streq (p[0], "rsa-sig"))
1255
+    {
1256
+      man_rsa_sig (man);
1257
+    }
1258
+#endif
1253 1259
 #ifdef ENABLE_PKCS11
1254 1260
   else if (streq (p[0], "pkcs11-id-count"))
1255 1261
     {
... ...
@@ -1626,8 +1670,8 @@ man_reset_client_socket (struct management *man, const bool exiting)
1626 1626
       man->connection.state = MS_INITIAL;
1627 1627
       command_line_reset (man->connection.in);
1628 1628
       buffer_list_reset (man->connection.out);
1629
-#ifdef MANAGEMENT_DEF_AUTH
1630
-      in_extra_reset (&man->connection, false);
1629
+#ifdef MANAGEMENT_IN_EXTRA
1630
+      in_extra_reset (&man->connection, IER_RESET);
1631 1631
 #endif
1632 1632
       msg (D_MANAGEMENT, "MANAGEMENT: Client disconnected");
1633 1633
     }
... ...
@@ -1666,8 +1710,8 @@ man_process_command (struct management *man, const char *line)
1666 1666
 
1667 1667
   CLEAR (parms);
1668 1668
   so = status_open (NULL, 0, -1, &man->persist.vout, 0);
1669
-#ifdef MANAGEMENT_DEF_AUTH
1670
-  in_extra_reset (&man->connection, false);
1669
+#ifdef MANAGEMENT_IN_EXTRA
1670
+  in_extra_reset (&man->connection, IER_CONDRESET);
1671 1671
 #endif
1672 1672
 
1673 1673
   if (man_password_needed (man))
... ...
@@ -1751,18 +1795,13 @@ man_read (struct management *man)
1751 1751
 	const unsigned char *line;
1752 1752
 	while ((line = command_line_get (man->connection.in)))
1753 1753
 	  {
1754
-#ifdef MANAGEMENT_DEF_AUTH
1754
+#ifdef MANAGEMENT_IN_EXTRA
1755 1755
 	    if (man->connection.in_extra)
1756 1756
 	      {
1757 1757
 		if (!strcmp ((char *)line, "END"))
1758
-		  {
1759
-		    in_extra_dispatch (man);
1760
-		    in_extra_reset (&man->connection, false);
1761
-		  }
1758
+		  in_extra_dispatch (man);
1762 1759
 		else
1763
-		  {
1764
-		    buffer_list_push (man->connection.in_extra, line);
1765
-		  }
1760
+		  buffer_list_push (man->connection.in_extra, line);
1766 1761
 	      }
1767 1762
 	    else
1768 1763
 #endif
... ...
@@ -2063,8 +2102,8 @@ man_connection_close (struct management *man)
2063 2063
     command_line_free (mc->in);
2064 2064
   if (mc->out)
2065 2065
     buffer_list_free (mc->out);
2066
-#ifdef MANAGEMENT_DEF_AUTH
2067
-  in_extra_reset (&man->connection, false);
2066
+#ifdef MANAGEMENT_IN_EXTRA
2067
+  in_extra_reset (&man->connection, IER_RESET);
2068 2068
 #endif
2069 2069
   man_connection_clear (mc);
2070 2070
 }
... ...
@@ -2387,7 +2426,7 @@ management_learn_addr (struct management *management,
2387 2387
   gc_free (&gc);
2388 2388
 }
2389 2389
 
2390
-#endif
2390
+#endif /* MANAGEMENT_DEF_AUTH */
2391 2391
 
2392 2392
 void
2393 2393
 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
2693 2693
 
2694 2694
 #define MWCC_PASSWORD_WAIT (1<<0)
2695 2695
 #define MWCC_HOLD_WAIT     (1<<1)
2696
+#define MWCC_OTHER_WAIT    (1<<2)
2696 2697
 
2697 2698
 /*
2698 2699
  * Block until client connects
... ...
@@ -2710,6 +2750,8 @@ man_wait_for_client_connection (struct management *man,
2710 2710
 	msg (D_MANAGEMENT, "Need password(s) from management interface, waiting...");
2711 2711
       if (flags & MWCC_HOLD_WAIT)
2712 2712
 	msg (D_MANAGEMENT, "Need hold release from management interface, waiting...");
2713
+      if (flags & MWCC_OTHER_WAIT)
2714
+	msg (D_MANAGEMENT, "Need information from management interface, waiting...");
2713 2715
       do {
2714 2716
 	man_standalone_event_loop (man, signal_received, expire);
2715 2717
 	if (signal_received && *signal_received)
... ...
@@ -2873,6 +2915,74 @@ management_query_user_pass (struct management *man,
2873 2873
   return ret;
2874 2874
 }
2875 2875
 
2876
+#ifdef MANAGMENT_EXTERNAL_KEY
2877
+
2878
+char * /* returns allocated base64 signature */
2879
+management_query_rsa_sig (struct management *man,
2880
+			  const char *b64_data)
2881
+{
2882
+  struct gc_arena gc = gc_new ();
2883
+  char *ret = NULL;
2884
+  volatile int signal_received = 0;
2885
+  struct buffer alert_msg = clear_buf();
2886
+  struct buffer *buf;
2887
+  const bool standalone_disabled_save = man->persist.standalone_disabled;
2888
+
2889
+  if (man_standalone_ok (man))
2890
+    {
2891
+      man->persist.standalone_disabled = false; /* This is so M_CLIENT messages will be correctly passed through msg() */
2892
+      man->persist.special_state_msg = NULL;
2893
+
2894
+      in_extra_reset (&man->connection, IER_RESET);
2895
+      man->connection.in_extra_cmd = IEC_RSA_SIGN_PRE;
2896
+
2897
+      alert_msg = alloc_buf_gc (strlen(b64_data)+64, &gc);
2898
+      buf_printf (&alert_msg, ">RSA_SIGN:%s", b64_data);
2899
+
2900
+      man_wait_for_client_connection (man, &signal_received, 0, MWCC_OTHER_WAIT);
2901
+
2902
+      if (signal_received)
2903
+	goto done;
2904
+
2905
+      man->persist.special_state_msg = BSTR (&alert_msg);
2906
+      msg (M_CLIENT, "%s", man->persist.special_state_msg);
2907
+
2908
+      /* run command processing event loop until we get our signature */
2909
+      do
2910
+	{
2911
+	  man_standalone_event_loop (man, &signal_received, 0);
2912
+	  if (!signal_received)
2913
+	    man_check_for_signals (&signal_received);
2914
+	  if (signal_received)
2915
+	    goto done;
2916
+	} while (man->connection.in_extra_cmd != IEC_RSA_SIGN_FINAL);
2917
+
2918
+      if (buffer_list_defined(man->connection.in_extra))
2919
+	{
2920
+	  buffer_list_aggregate (man->connection.in_extra, 2000);
2921
+	  buf = buffer_list_peek (man->connection.in_extra);
2922
+	  if (buf && BLEN(buf) > 0)
2923
+	    {
2924
+	      ret = (char *) malloc(BLEN(buf)+1);
2925
+	      check_malloc_return(ret);
2926
+	      memcpy(ret, buf->data, BLEN(buf));
2927
+	      ret[BLEN(buf)] = '\0';
2928
+	    }
2929
+	}
2930
+    }
2931
+
2932
+ done:
2933
+  /* revert state */
2934
+  man->persist.standalone_disabled = standalone_disabled_save;
2935
+  man->persist.special_state_msg = NULL;
2936
+  in_extra_reset (&man->connection, IER_RESET);
2937
+
2938
+  gc_free (&gc);
2939
+  return ret;
2940
+}
2941
+
2942
+#endif
2943
+
2876 2944
 /*
2877 2945
  * Return true if management_hold() would block
2878 2946
  */
... ...
@@ -264,16 +264,23 @@ struct man_connection {
264 264
   struct command_line *in;
265 265
   struct buffer_list *out;
266 266
 
267
-#ifdef MANAGEMENT_DEF_AUTH
267
+#ifdef MANAGEMENT_IN_EXTRA
268 268
 # define IEC_UNDEF       0
269 269
 # define IEC_CLIENT_AUTH 1
270 270
 # define IEC_CLIENT_PF   2
271
+
272
+# define IEC_STATEFUL_BASE  16
273
+# define IEC_RSA_SIGN_PRE   16
274
+# define IEC_RSA_SIGN       17
275
+# define IEC_RSA_SIGN_FINAL 18
271 276
   int in_extra_cmd;
277
+  struct buffer_list *in_extra;
278
+#ifdef MANAGEMENT_DEF_AUTH
272 279
   unsigned long in_extra_cid;
273 280
   unsigned int in_extra_kid;
274
-  struct buffer_list *in_extra;
275 281
   int env_filter_level;
276 282
 #endif
283
+#endif
277 284
   struct event_set *es;
278 285
 
279 286
   bool state_realtime;
... ...
@@ -285,6 +292,10 @@ struct man_connection {
285 285
   const char *up_query_type;
286 286
   int up_query_mode;
287 287
   struct user_pass up_query;
288
+
289
+#ifdef MANAGMENT_EXTERNAL_KEY
290
+  struct buffer_list *rsa_sig;
291
+#endif
288 292
 };
289 293
 
290 294
 struct management
... ...
@@ -314,6 +325,9 @@ struct management *management_init (void);
314 314
 # define MF_CLIENT_PF         (1<<7)
315 315
 #endif
316 316
 # define MF_UNIX_SOCK       (1<<8)
317
+#ifdef MANAGMENT_EXTERNAL_KEY
318
+# define MF_EXTERNAL_KEY    (1<<9)
319
+#endif
317 320
 
318 321
 bool management_open (struct management *man,
319 322
 		      const char *addr,
... ...
@@ -374,6 +388,12 @@ void management_learn_addr (struct management *management,
374 374
 			    const bool primary);
375 375
 #endif
376 376
 
377
+#ifdef MANAGMENT_EXTERNAL_KEY
378
+
379
+char *management_query_rsa_sig (struct management *man, const char *b64_data);
380
+
381
+#endif
382
+
377 383
 static inline bool
378 384
 management_connected (const struct management *man)
379 385
 {
... ...
@@ -1618,7 +1618,7 @@ get_auth_challenge (const char *auth_challenge, struct gc_arena *gc)
1618 1618
       if (!buf_parse(&b, ':', work, len))
1619 1619
 	return NULL;
1620 1620
       ac->user = (char *) gc_malloc (strlen(work)+1, true, gc);
1621
-      base64_decode(work, (void*)ac->user);
1621
+      base64_decode(work, (void*)ac->user, -1);
1622 1622
 
1623 1623
       /* parse challenge text */
1624 1624
       ac->challenge_text = string_alloc(BSTR(&b), gc);
... ...
@@ -242,7 +242,7 @@ ntlm_phase_3 (const struct http_proxy_info *p, const char *phase_2, struct gc_ar
242 242
   /* pad to 21 bytes */
243 243
   memset (md4_hash + 16, 0, 5);
244 244
 
245
-  ret_val = base64_decode( phase_2, (void *)buf2);
245
+  ret_val = base64_decode( phase_2, (void *)buf2, -1);
246 246
   if (ret_val < 0)
247 247
     return NULL;
248 248
 
... ...
@@ -3663,6 +3663,14 @@ add_option (struct options *options,
3663 3663
       options->management_flags |= MF_CONNECT_AS_CLIENT;
3664 3664
       options->management_write_peer_info_file = p[1];
3665 3665
     }
3666
+#ifdef MANAGMENT_EXTERNAL_KEY
3667
+  else if (streq (p[0], "management-external-key"))
3668
+    {
3669
+      VERIFY_PERMISSION (OPT_P_GENERAL);
3670
+      options->management_flags |= MF_EXTERNAL_KEY;
3671
+      options->priv_key_file = "EXTERNAL_PRIVATE_KEY";
3672
+    }
3673
+#endif
3666 3674
 #ifdef MANAGEMENT_DEF_AUTH
3667 3675
   else if (streq (p[0], "management-client-auth"))
3668 3676
     {
... ...
@@ -51,6 +51,7 @@
51 51
 #include "gremlin.h"
52 52
 #include "pkcs11.h"
53 53
 #include "list.h"
54
+#include "base64.h"
54 55
 
55 56
 #ifdef WIN32
56 57
 #include "cryptoapi.h"
... ...
@@ -1482,6 +1483,195 @@ info_callback (INFO_CALLBACK_SSL_CONST SSL * s, int where, int ret)
1482 1482
     }
1483 1483
 }
1484 1484
 
1485
+#ifdef MANAGMENT_EXTERNAL_KEY
1486
+
1487
+/* encrypt */
1488
+static int
1489
+rsa_pub_enc(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding)
1490
+{
1491
+  ASSERT(0);
1492
+  return -1;
1493
+}
1494
+
1495
+/* verify arbitrary data */
1496
+static int
1497
+rsa_pub_dec(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding)
1498
+{
1499
+  ASSERT(0);
1500
+  return -1;
1501
+}
1502
+
1503
+/* decrypt */
1504
+static int
1505
+rsa_priv_dec(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding)
1506
+{
1507
+  ASSERT(0);
1508
+  return -1;
1509
+}
1510
+
1511
+/* called at RSA_free */
1512
+static int
1513
+rsa_finish(RSA *rsa)
1514
+{
1515
+  free ((void*)rsa->meth);
1516
+  rsa->meth = NULL;
1517
+  return 1;
1518
+}
1519
+
1520
+/* sign arbitrary data */
1521
+static int
1522
+rsa_priv_enc(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding)
1523
+{
1524
+  /* optional app data in rsa->meth->app_data; */
1525
+  char *in_b64 = NULL;
1526
+  char *out_b64 = NULL;
1527
+  int ret = -1;
1528
+  int len;
1529
+
1530
+  if (padding != RSA_PKCS1_PADDING)
1531
+    {
1532
+      RSAerr (RSA_F_RSA_EAY_PRIVATE_ENCRYPT, RSA_R_UNKNOWN_PADDING_TYPE);
1533
+      goto done;
1534
+    }
1535
+
1536
+  /* convert 'from' to base64 */
1537
+  if (base64_encode (from, flen, &in_b64) <= 0)
1538
+    goto done;
1539
+
1540
+  /* call MI for signature */
1541
+  if (management)
1542
+    out_b64 = management_query_rsa_sig (management, in_b64);
1543
+  if (!out_b64)
1544
+    goto done;
1545
+
1546
+  /* decode base64 signature to binary */
1547
+  len = RSA_size(rsa);
1548
+  ret = base64_decode (out_b64, to, len);
1549
+
1550
+  /* verify length */
1551
+  if (ret != len)
1552
+    ret = -1;
1553
+
1554
+ done:
1555
+  if (in_b64)
1556
+    free (in_b64);
1557
+  if (out_b64)
1558
+    free (out_b64);
1559
+  return ret;
1560
+}
1561
+
1562
+static int
1563
+use_external_private_key (SSL_CTX *ssl_ctx, X509 *cert)
1564
+{
1565
+  RSA *rsa = NULL;
1566
+  RSA *pub_rsa;
1567
+  RSA_METHOD *rsa_meth;
1568
+
1569
+  /* allocate custom RSA method object */
1570
+  ALLOC_OBJ_CLEAR (rsa_meth, RSA_METHOD);
1571
+  rsa_meth->name = "OpenVPN external private key RSA Method";
1572
+  rsa_meth->rsa_pub_enc = rsa_pub_enc;
1573
+  rsa_meth->rsa_pub_dec = rsa_pub_dec;
1574
+  rsa_meth->rsa_priv_enc = rsa_priv_enc;
1575
+  rsa_meth->rsa_priv_dec = rsa_priv_dec;
1576
+  rsa_meth->init = NULL;
1577
+  rsa_meth->finish = rsa_finish;
1578
+  rsa_meth->flags = RSA_METHOD_FLAG_NO_CHECK;
1579
+  rsa_meth->app_data = NULL;
1580
+
1581
+  /* allocate RSA object */
1582
+  rsa = RSA_new();
1583
+  if (rsa == NULL)
1584
+    {
1585
+      SSLerr(SSL_F_SSL_USE_PRIVATEKEY, ERR_R_MALLOC_FAILURE);
1586
+      goto err;
1587
+    }
1588
+
1589
+  /* get the public key */
1590
+  ASSERT(cert->cert_info->key->pkey); /* NULL before SSL_CTX_use_certificate() is called */
1591
+  pub_rsa = cert->cert_info->key->pkey->pkey.rsa;
1592
+
1593
+  /* initialize RSA object */
1594
+  rsa->n = BN_dup(pub_rsa->n);
1595
+  rsa->flags |= RSA_FLAG_EXT_PKEY;
1596
+  if (!RSA_set_method(rsa, rsa_meth))
1597
+    goto err;
1598
+
1599
+  /* bind our custom RSA object to ssl_ctx */
1600
+  if (!SSL_CTX_use_RSAPrivateKey(ssl_ctx, rsa))
1601
+    goto err;
1602
+
1603
+  RSA_free(rsa); /* doesn't necessarily free, just decrements refcount */
1604
+  return 1;
1605
+
1606
+ err:
1607
+  if (rsa)
1608
+    RSA_free(rsa);
1609
+  else
1610
+    {
1611
+      if (rsa_meth)
1612
+	free(rsa_meth);
1613
+    }
1614
+  return 0;
1615
+}
1616
+
1617
+/*
1618
+ * Basically a clone of SSL_CTX_use_certificate_file, but also return
1619
+ * the x509 object.
1620
+ */
1621
+static int
1622
+use_certificate_file(SSL_CTX *ctx, const char *file, int type, X509 **x509)
1623
+{
1624
+  int j;
1625
+  BIO *in;
1626
+  int ret=0;
1627
+  X509 *x=NULL;
1628
+
1629
+  in=BIO_new(BIO_s_file_internal());
1630
+  if (in == NULL)
1631
+    {
1632
+      SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE,ERR_R_BUF_LIB);
1633
+      goto end;
1634
+    }
1635
+
1636
+  if (BIO_read_filename(in,file) <= 0)
1637
+    {
1638
+      SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE,ERR_R_SYS_LIB);
1639
+      goto end;
1640
+    }
1641
+  if (type == SSL_FILETYPE_ASN1)
1642
+    {
1643
+      j=ERR_R_ASN1_LIB;
1644
+      x=d2i_X509_bio(in,NULL);
1645
+    }
1646
+  else if (type == SSL_FILETYPE_PEM)
1647
+    {
1648
+      j=ERR_R_PEM_LIB;
1649
+      x=PEM_read_bio_X509(in,NULL,ctx->default_passwd_callback,ctx->default_passwd_callback_userdata);
1650
+    }
1651
+  else
1652
+    {
1653
+      SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE,SSL_R_BAD_SSL_FILETYPE);
1654
+      goto end;
1655
+    }
1656
+
1657
+  if (x == NULL)
1658
+    {
1659
+      SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE,j);
1660
+      goto end;
1661
+    }
1662
+
1663
+  ret=SSL_CTX_use_certificate(ctx,x);
1664
+ end:
1665
+  if (in != NULL)
1666
+    BIO_free(in);
1667
+  if (x509)
1668
+    *x509 = x;
1669
+  return(ret);
1670
+}
1671
+
1672
+#endif
1673
+
1485 1674
 #if ENABLE_INLINE_FILES
1486 1675
 
1487 1676
 static int
... ...
@@ -1589,7 +1779,7 @@ use_inline_load_client_CA_file (SSL_CTX *ctx, const char *ca_string)
1589 1589
 }
1590 1590
 
1591 1591
 static int
1592
-use_inline_certificate_file (SSL_CTX *ctx, const char *cert_string)
1592
+use_inline_certificate_file (SSL_CTX *ctx, const char *cert_string, X509 **x509)
1593 1593
 {
1594 1594
   BIO *in = NULL;
1595 1595
   X509 *x = NULL;
... ...
@@ -1613,6 +1803,8 @@ use_inline_certificate_file (SSL_CTX *ctx, const char *cert_string)
1613 1613
     X509_free (x);
1614 1614
   if (in)
1615 1615
     BIO_free (in);
1616
+  if (x509)
1617
+    *x509 = x;
1616 1618
   return ret;
1617 1619
 }
1618 1620
 
... ...
@@ -1657,6 +1849,7 @@ init_ssl (const struct options *options)
1657 1657
   DH *dh;
1658 1658
   BIO *bio;
1659 1659
   bool using_cert_file = false;
1660
+  X509 *my_cert = NULL;
1660 1661
 
1661 1662
   ERR_clear_error ();
1662 1663
 
... ...
@@ -1756,7 +1949,6 @@ init_ssl (const struct options *options)
1756 1756
 		management_auth_failure (management, UP_TYPE_PRIVATE_KEY, NULL);
1757 1757
 #endif
1758 1758
 	      PKCS12_free(p12);
1759
-	      msg (M_INFO, "OpenSSL ERROR code: %d", (ERR_GET_REASON (ERR_peek_error()))); // fixme
1760 1759
 	      goto err;
1761 1760
 	    }
1762 1761
         }
... ...
@@ -1824,18 +2016,32 @@ init_ssl (const struct options *options)
1824 1824
 #if ENABLE_INLINE_FILES
1825 1825
 	      if (!strcmp (options->cert_file, INLINE_FILE_TAG) && options->cert_file_inline)
1826 1826
 		{
1827
-		  if (!use_inline_certificate_file (ctx, options->cert_file_inline))
1827
+		  if (!use_inline_certificate_file (ctx, options->cert_file_inline, &my_cert))
1828 1828
 		    msg (M_SSLERR, "Cannot load inline certificate file");
1829 1829
 		}
1830 1830
 	      else
1831 1831
 #endif
1832 1832
 		{
1833
+#ifdef MANAGMENT_EXTERNAL_KEY
1834
+		  if (!use_certificate_file (ctx, options->cert_file, SSL_FILETYPE_PEM, &my_cert))
1835
+#else
1833 1836
 		  if (!SSL_CTX_use_certificate_file (ctx, options->cert_file, SSL_FILETYPE_PEM))
1837
+#endif
1834 1838
 		    msg (M_SSLERR, "Cannot load certificate file %s", options->cert_file);
1835 1839
 		  using_cert_file = true;
1836 1840
 		}
1837 1841
 	    }
1838 1842
 
1843
+#ifdef MANAGMENT_EXTERNAL_KEY
1844
+	  if (options->management_flags & MF_EXTERNAL_KEY)
1845
+	    {
1846
+	      ASSERT (my_cert);
1847
+	      if (!use_external_private_key(ctx, my_cert))
1848
+		msg (M_SSLERR, "Cannot enable SSL external private key capability");
1849
+	    }
1850
+	  else
1851
+#endif
1852
+
1839 1853
 	  /* Load Private Key */
1840 1854
 	  if (options->priv_key_file)
1841 1855
 	    {
... ...
@@ -1967,6 +2173,8 @@ init_ssl (const struct options *options)
1967 1967
 
1968 1968
  err:
1969 1969
   ERR_clear_error ();
1970
+  if (my_cert)
1971
+    X509_free(my_cert);
1970 1972
   if (ctx)
1971 1973
     SSL_CTX_free (ctx);
1972 1974
   return NULL;
... ...
@@ -510,6 +510,21 @@ socket_defined (const socket_descriptor_t sd)
510 510
 #endif
511 511
 
512 512
 /*
513
+ * Enable external private key
514
+ */
515
+#if defined(ENABLE_MANAGEMENT) && defined(USE_SSL)
516
+#define MANAGMENT_EXTERNAL_KEY
517
+#endif
518
+
519
+/*
520
+ * MANAGEMENT_IN_EXTRA allows the management interface to
521
+ * read multi-line inputs from clients.
522
+ */
523
+#if defined(MANAGEMENT_DEF_AUTH) || defined(MANAGMENT_EXTERNAL_KEY)
524
+#define MANAGEMENT_IN_EXTRA
525
+#endif
526
+
527
+/*
513 528
  * Enable packet filter?
514 529
  */
515 530
 #if defined(CONFIGURE_PF) && P2MP_SERVER && defined(ENABLE_PLUGIN) && defined(HAVE_STAT)