keyingmaterialexporter.c 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. /*
  2. * OpenVPN -- An application to securely tunnel IP networks
  3. * over a single TCP/UDP port, with support for SSL/TLS-based
  4. * session authentication and key exchange,
  5. * packet encryption, packet authentication, and
  6. * packet compression.
  7. *
  8. * Copyright (C) 2002-2018 OpenVPN Inc <sales@openvpn.net>
  9. *
  10. * This program is free software; you can redistribute it and/or modify
  11. * it under the terms of the GNU General Public License version 2
  12. * as published by the Free Software Foundation.
  13. *
  14. * This program is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU General Public License along
  20. * with this program; if not, write to the Free Software Foundation, Inc.,
  21. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  22. */
  23. /*
  24. * This file implements a Sample (HTTP) SSO OpenVPN plugin module
  25. *
  26. * See the README file for build instructions.
  27. */
  28. #define ENABLE_CRYPTO
  29. #include <stdio.h>
  30. #include <string.h>
  31. #include <stdlib.h>
  32. #include "openvpn-plugin.h"
  33. #ifndef MAXPATH
  34. #define MAXPATH 1024
  35. #endif
  36. #define ovpn_err(fmt, ...) \
  37. plugin->log(PLOG_ERR, "SSO", fmt, ## __VA_ARGS__)
  38. #define ovpn_dbg(fmt, ...) \
  39. plugin->log(PLOG_DEBUG, "SSO", fmt, ## __VA_ARGS__)
  40. #define ovpn_note(fmt, ...) \
  41. plugin->log(PLOG_NOTE, "SSO", fmt, ## __VA_ARGS__)
  42. enum endpoint { CLIENT = 1, SERVER = 2 };
  43. struct plugin {
  44. plugin_log_t log;
  45. enum endpoint type;
  46. int mask;
  47. };
  48. struct session {
  49. char user[48];
  50. char key [48];
  51. };
  52. /*
  53. * Given an environmental variable name, search
  54. * the envp array for its value, returning it
  55. * if found or NULL otherwise.
  56. */
  57. static const char *
  58. get_env(const char *name, const char *envp[])
  59. {
  60. if (envp)
  61. {
  62. int i;
  63. const int namelen = strlen(name);
  64. for (i = 0; envp[i]; ++i)
  65. {
  66. if (!strncmp(envp[i], name, namelen))
  67. {
  68. const char *cp = envp[i] + namelen;
  69. if (*cp == '=')
  70. {
  71. return cp + 1;
  72. }
  73. }
  74. }
  75. }
  76. return NULL;
  77. }
  78. OPENVPN_EXPORT int
  79. openvpn_plugin_open_v3(const int version,
  80. struct openvpn_plugin_args_open_in const *args,
  81. struct openvpn_plugin_args_open_return *rv)
  82. {
  83. struct plugin *plugin = calloc(1, sizeof(*plugin));
  84. plugin->type = get_env("remote_1", args->envp) ? CLIENT : SERVER;
  85. plugin->log = args->callbacks->plugin_log;
  86. plugin->mask = OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_TLS_FINAL);
  87. plugin->mask |= OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_TLS_VERIFY);
  88. ovpn_note("vpn endpoint type=%s",plugin->type == CLIENT ? "client" : "server");
  89. rv->type_mask = plugin->mask;
  90. rv->handle = (void *)plugin;
  91. return OPENVPN_PLUGIN_FUNC_SUCCESS;
  92. }
  93. static void
  94. session_user_set(struct session *sess, X509 *x509)
  95. {
  96. int fn_nid;
  97. ASN1_OBJECT *fn;
  98. ASN1_STRING *val;
  99. X509_NAME *x509_name;
  100. X509_NAME_ENTRY *ent;
  101. const char *objbuf;
  102. x509_name = X509_get_subject_name(x509);
  103. int i, n = X509_NAME_entry_count(x509_name);
  104. for (i = 0; i < n; ++i)
  105. {
  106. if (!(ent = X509_NAME_get_entry(x509_name, i)))
  107. {
  108. continue;
  109. }
  110. if (!(fn = X509_NAME_ENTRY_get_object(ent)))
  111. {
  112. continue;
  113. }
  114. if (!(val = X509_NAME_ENTRY_get_data(ent)))
  115. {
  116. continue;
  117. }
  118. if ((fn_nid = OBJ_obj2nid(fn)) == NID_undef)
  119. {
  120. continue;
  121. }
  122. if (!(objbuf = OBJ_nid2sn(fn_nid)))
  123. {
  124. continue;
  125. }
  126. unsigned char *buf = NULL;
  127. if (ASN1_STRING_to_UTF8(&buf, val) < 0)
  128. {
  129. continue;
  130. }
  131. if (!strncasecmp(objbuf, "CN", 2))
  132. {
  133. snprintf(sess->user, sizeof(sess->user) - 1, (char *)buf);
  134. }
  135. OPENSSL_free(buf);
  136. }
  137. }
  138. static int
  139. tls_verify(struct openvpn_plugin_args_func_in const *args)
  140. {
  141. struct plugin *plugin = (struct plugin *)args->handle;
  142. struct session *sess = (struct session *)args->per_client_context;
  143. /* we store cert subject for the server end point only */
  144. if (plugin->type != SERVER)
  145. {
  146. return OPENVPN_PLUGIN_FUNC_SUCCESS;
  147. }
  148. if (!args->current_cert)
  149. {
  150. ovpn_err("this example plugin requires client certificate");
  151. return OPENVPN_PLUGIN_FUNC_ERROR;
  152. }
  153. session_user_set(sess, args->current_cert);
  154. return OPENVPN_PLUGIN_FUNC_SUCCESS;
  155. }
  156. static void
  157. file_store(char *file, char *content)
  158. {
  159. FILE *f;
  160. if (!(f = fopen(file, "w+")))
  161. {
  162. return;
  163. }
  164. fprintf(f, "%s", content);
  165. fclose(f);
  166. }
  167. static void
  168. server_store(struct openvpn_plugin_args_func_in const *args)
  169. {
  170. struct plugin *plugin = (struct plugin *)args->handle;
  171. struct session *sess = (struct session *)args->per_client_context;
  172. char file[MAXPATH];
  173. snprintf(file, sizeof(file) - 1, "/tmp/openvpn_sso_%s", sess->key);
  174. ovpn_note("app session file: %s", file);
  175. file_store(file, sess->user);
  176. }
  177. static void
  178. client_store(struct openvpn_plugin_args_func_in const *args)
  179. {
  180. struct plugin *plugin = (struct plugin *)args->handle;
  181. struct session *sess = (struct session *)args->per_client_context;
  182. char *file = "/tmp/openvpn_sso_user";
  183. ovpn_note("app session file: %s", file);
  184. file_store(file, sess->key);
  185. }
  186. static int
  187. tls_final(struct openvpn_plugin_args_func_in const *args,
  188. struct openvpn_plugin_args_func_return *rv)
  189. {
  190. struct plugin *plugin = (struct plugin *)args->handle;
  191. struct session *sess = (struct session *)args->per_client_context;
  192. const char *key;
  193. if (!(key = get_env("exported_keying_material", args->envp)))
  194. {
  195. return OPENVPN_PLUGIN_FUNC_ERROR;
  196. }
  197. snprintf(sess->key, sizeof(sess->key) - 1, "%s", key);
  198. ovpn_note("app session key: %s", sess->key);
  199. switch (plugin->type) {
  200. case SERVER:
  201. server_store(args);
  202. break;
  203. case CLIENT:
  204. client_store(args);
  205. return OPENVPN_PLUGIN_FUNC_SUCCESS;
  206. }
  207. ovpn_note("app session user: %s", sess->user);
  208. return OPENVPN_PLUGIN_FUNC_SUCCESS;
  209. }
  210. OPENVPN_EXPORT int
  211. openvpn_plugin_func_v3(const int version,
  212. struct openvpn_plugin_args_func_in const *args,
  213. struct openvpn_plugin_args_func_return *rv)
  214. {
  215. switch (args->type) {
  216. case OPENVPN_PLUGIN_TLS_VERIFY:
  217. return tls_verify(args);
  218. case OPENVPN_PLUGIN_TLS_FINAL:
  219. return tls_final(args, rv);
  220. }
  221. return OPENVPN_PLUGIN_FUNC_SUCCESS;
  222. }
  223. OPENVPN_EXPORT void *
  224. openvpn_plugin_client_constructor_v1(openvpn_plugin_handle_t handle)
  225. {
  226. struct plugin *plugin = (struct plugin *)handle;
  227. struct session *sess = calloc(1, sizeof(*sess));
  228. ovpn_note("app session created");
  229. return (void *)sess;
  230. }
  231. OPENVPN_EXPORT void
  232. openvpn_plugin_client_destructor_v1(openvpn_plugin_handle_t handle, void *ctx)
  233. {
  234. struct plugin *plugin = (struct plugin *)handle;
  235. struct session *sess = (struct session *)ctx;
  236. ovpn_note("app session key: %s", sess->key);
  237. ovpn_note("app session destroyed");
  238. free(sess);
  239. }
  240. OPENVPN_EXPORT void
  241. openvpn_plugin_close_v1(openvpn_plugin_handle_t handle)
  242. {
  243. struct plugin *plugin = (struct plugin *)handle;
  244. free(plugin);
  245. }