>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
... | ... |
@@ -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 |
|
... | ... |
@@ -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) |