OpenVPN
keyingmaterialexporter.c
Go to the documentation of this file.
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-2024 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 /*
25  * This file implements a Sample (HTTP) SSO OpenVPN plugin module
26  *
27  * See the README file for build instructions.
28  */
29 
30 #include <stdio.h>
31 #include <string.h>
32 #include <strings.h>
33 #include <stdlib.h>
34 
35 #include "openvpn-plugin.h"
36 
37 #ifndef MAXPATH
38 #define MAXPATH 1024
39 #endif
40 
41 #define ovpn_err(fmt, ...) \
42  plugin->log(PLOG_ERR, "SSO", fmt, ## __VA_ARGS__)
43 #define ovpn_dbg(fmt, ...) \
44  plugin->log(PLOG_DEBUG, "SSO", fmt, ## __VA_ARGS__)
45 #define ovpn_note(fmt, ...) \
46  plugin->log(PLOG_NOTE, "SSO", fmt, ## __VA_ARGS__)
47 
48 enum endpoint { CLIENT = 1, SERVER = 2 };
49 
50 struct plugin {
52  enum endpoint type;
53  int mask;
54 };
55 
56 struct session {
57  char user[48];
58  char key[48];
59 };
60 
61 /*
62  * Given an environmental variable name, search
63  * the envp array for its value, returning it
64  * if found or NULL otherwise.
65  */
66 
67 static const char *
68 get_env(const char *name, const char *envp[])
69 {
70  if (envp)
71  {
72  int i;
73  const int namelen = strlen(name);
74  for (i = 0; envp[i]; ++i)
75  {
76  if (!strncmp(envp[i], name, namelen))
77  {
78  const char *cp = envp[i] + namelen;
79  if (*cp == '=')
80  {
81  return cp + 1;
82  }
83  }
84  }
85  }
86  return NULL;
87 }
88 
90 openvpn_plugin_open_v3(const int version,
91  struct openvpn_plugin_args_open_in const *args,
93 {
94  struct plugin *plugin = calloc(1, sizeof(*plugin));
95 
96  if (plugin == NULL)
97  {
98  printf("PLUGIN: allocating memory for context failed\n");
100  }
101 
102  plugin->type = get_env("remote_1", args->envp) ? CLIENT : SERVER;
103  plugin->log = args->callbacks->plugin_log;
104 
107 
108  ovpn_note("vpn endpoint type=%s", plugin->type == CLIENT ? "client" : "server");
109 
110  rv->type_mask = plugin->mask;
111  rv->handle = (void *)plugin;
112 
114 }
115 
116 static void
117 session_user_set(struct session *sess, X509 *x509)
118 {
119  int fn_nid;
120  ASN1_OBJECT *fn;
121  ASN1_STRING *val;
122  X509_NAME *x509_name;
123  X509_NAME_ENTRY *ent;
124  const char *objbuf;
125 
126  x509_name = X509_get_subject_name(x509);
127  int i, n = X509_NAME_entry_count(x509_name);
128  for (i = 0; i < n; ++i)
129  {
130  if (!(ent = X509_NAME_get_entry(x509_name, i)))
131  {
132  continue;
133  }
134  if (!(fn = X509_NAME_ENTRY_get_object(ent)))
135  {
136  continue;
137  }
138  if (!(val = X509_NAME_ENTRY_get_data(ent)))
139  {
140  continue;
141  }
142  if ((fn_nid = OBJ_obj2nid(fn)) == NID_undef)
143  {
144  continue;
145  }
146  if (!(objbuf = OBJ_nid2sn(fn_nid)))
147  {
148  continue;
149  }
150  unsigned char *buf = NULL;
151  if (ASN1_STRING_to_UTF8(&buf, val) < 0)
152  {
153  continue;
154  }
155 
156  if (!strncasecmp(objbuf, "CN", 2))
157  {
158  strncpy(sess->user, (char *)buf, sizeof(sess->user) - 1);
159  }
160 
161  OPENSSL_free(buf);
162  }
163 }
164 
165 static int
167 {
168  struct plugin *plugin = (struct plugin *)args->handle;
169  struct session *sess = (struct session *)args->per_client_context;
170 
171  /* we store cert subject for the server end point only */
172  if (plugin->type != SERVER)
173  {
175  }
176 
177  if (!args->current_cert)
178  {
179  ovpn_err("this example plugin requires client certificate");
181  }
182 
183  session_user_set(sess, args->current_cert);
184 
186 }
187 
188 static void
189 file_store(char *file, char *content)
190 {
191  FILE *f;
192  if (!(f = fopen(file, "w+")))
193  {
194  return;
195  }
196 
197  fprintf(f, "%s", content);
198  fclose(f);
199 }
200 
201 static void
203 {
204  struct plugin *plugin = (struct plugin *)args->handle;
205  struct session *sess = (struct session *)args->per_client_context;
206 
207  char file[MAXPATH];
208  snprintf(file, sizeof(file) - 1, "/tmp/openvpn_sso_%s", sess->key);
209  ovpn_note("app session file: %s", file);
210  file_store(file, sess->user);
211 }
212 
213 static void
215 {
216  struct plugin *plugin = (struct plugin *)args->handle;
217  struct session *sess = (struct session *)args->per_client_context;
218 
219  char *file = "/tmp/openvpn_sso_user";
220  ovpn_note("app session file: %s", file);
221  file_store(file, sess->key);
222 }
223 
224 static int
227 {
228  struct plugin *plugin = (struct plugin *)args->handle;
229  struct session *sess = (struct session *)args->per_client_context;
230 
231  const char *key;
232  if (!(key = get_env("exported_keying_material", args->envp)))
233  {
235  }
236 
237  strncpy(sess->key, key, sizeof(sess->key) - 1);
238  ovpn_note("app session key: %s", sess->key);
239 
240  switch (plugin->type)
241  {
242  case SERVER:
243  server_store(args);
244  break;
245 
246  case CLIENT:
247  client_store(args);
249  }
250 
251  ovpn_note("app session user: %s", sess->user);
253 }
254 
255 OPENVPN_EXPORT int
256 openvpn_plugin_func_v3(const int version,
257  struct openvpn_plugin_args_func_in const *args,
259 {
260  switch (args->type)
261  {
263  return tls_verify(args);
264 
266  return tls_final(args, rv);
267  }
269 }
270 
271 OPENVPN_EXPORT void *
273 {
274  struct plugin *plugin = (struct plugin *)handle;
275  struct session *sess = calloc(1, sizeof(*sess));
276 
277  ovpn_note("app session created");
278 
279  return (void *)sess;
280 }
281 
282 OPENVPN_EXPORT void
284 {
285  struct plugin *plugin = (struct plugin *)handle;
286  struct session *sess = (struct session *)ctx;
287 
288  ovpn_note("app session key: %s", sess->key);
289  ovpn_note("app session destroyed");
290 
291  free(sess);
292 }
293 
294 OPENVPN_EXPORT void
296 {
297  struct plugin *plugin = (struct plugin *)handle;
298  free(plugin);
299 }
plugin::mask
int mask
Definition: keyingmaterialexporter.c:53
get_env
static const char * get_env(const char *name, const char *envp[])
Definition: keyingmaterialexporter.c:68
plugin::type
enum endpoint type
Definition: keyingmaterialexporter.c:52
openvpn_plugin_args_func_in::handle
openvpn_plugin_handle_t handle
Definition: openvpn-plugin.h:434
openvpn_plugin_args_open_in
Arguments used to transport variables to the plug-in.
Definition: openvpn-plugin.h:359
file_store
static void file_store(char *file, char *content)
Definition: keyingmaterialexporter.c:189
session::key
char key[48]
Definition: keyingmaterialexporter.c:58
openvpn_plugin_args_open_return::type_mask
int type_mask
Definition: openvpn-plugin.h:396
tls_verify
static int tls_verify(struct openvpn_plugin_args_func_in const *args)
Definition: keyingmaterialexporter.c:166
openvpn_plugin_open_v3
OPENVPN_EXPORT int openvpn_plugin_open_v3(const int version, struct openvpn_plugin_args_open_in const *args, struct openvpn_plugin_args_open_return *rv)
Definition: keyingmaterialexporter.c:90
plugin_log_t
void(* plugin_log_t)(openvpn_plugin_log_flags_t flags, const char *plugin_name, const char *format,...) _ovpn_chk_fmt(3
Definition: openvpn-plugin.h:254
OPENVPN_PLUGIN_MASK
#define OPENVPN_PLUGIN_MASK(x)
Definition: openvpn-plugin.h:137
client_store
static void client_store(struct openvpn_plugin_args_func_in const *args)
Definition: keyingmaterialexporter.c:214
key
Container for unidirectional cipher and HMAC key material.
Definition: crypto.h:149
openvpn_plugin_close_v1
OPENVPN_EXPORT void openvpn_plugin_close_v1(openvpn_plugin_handle_t handle)
Definition: keyingmaterialexporter.c:295
openvpn_plugin_args_func_in::type
const int type
Definition: openvpn-plugin.h:431
OPENVPN_PLUGIN_FUNC_ERROR
#define OPENVPN_PLUGIN_FUNC_ERROR
Definition: openvpn-plugin.h:149
openvpn_plugin_args_func_in::current_cert
openvpn_x509_cert_t * current_cert
Definition: openvpn-plugin.h:437
OPENVPN_EXPORT
#define OPENVPN_EXPORT
Definition: openvpn-plugin.h:156
tls_final
static int tls_final(struct openvpn_plugin_args_func_in const *args, struct openvpn_plugin_args_func_return *rv)
Definition: keyingmaterialexporter.c:225
plugin
Definition: keyingmaterialexporter.c:50
openvpn_plugin_client_constructor_v1
OPENVPN_EXPORT void * openvpn_plugin_client_constructor_v1(openvpn_plugin_handle_t handle)
Definition: keyingmaterialexporter.c:272
openvpn_plugin_args_func_in::per_client_context
void * per_client_context
Definition: openvpn-plugin.h:435
openvpn_plugin_args_func_in::envp
const char **const envp
Definition: openvpn-plugin.h:433
OPENVPN_PLUGIN_TLS_VERIFY
#define OPENVPN_PLUGIN_TLS_VERIFY
Definition: openvpn-plugin.h:121
CLIENT
@ CLIENT
Definition: keyingmaterialexporter.c:48
SERVER
@ SERVER
Definition: keyingmaterialexporter.c:48
plugin::log
plugin_log_t log
Definition: keyingmaterialexporter.c:51
openvpn_plugin_args_func_return
Arguments used to transport variables to and from the plug-in.
Definition: openvpn-plugin.h:452
openvpn_plugin_args_open_in::envp
const char **const envp
Definition: openvpn-plugin.h:363
session_user_set
static void session_user_set(struct session *sess, X509 *x509)
Definition: keyingmaterialexporter.c:117
openvpn_plugin_args_open_return
Arguments used to transport variables from the plug-in back to the OpenVPN process.
Definition: openvpn-plugin.h:394
server_store
static void server_store(struct openvpn_plugin_args_func_in const *args)
Definition: keyingmaterialexporter.c:202
openvpn_plugin_args_func_in
Arguments used to transport variables to and from the plug-in.
Definition: openvpn-plugin.h:429
openvpn_plugin_args_open_return::handle
openvpn_plugin_handle_t handle
Definition: openvpn-plugin.h:397
OPENVPN_PLUGIN_FUNC_SUCCESS
#define OPENVPN_PLUGIN_FUNC_SUCCESS
Definition: openvpn-plugin.h:148
OPENVPN_PLUGIN_TLS_FINAL
#define OPENVPN_PLUGIN_TLS_FINAL
Definition: openvpn-plugin.h:127
ovpn_err
#define ovpn_err(fmt,...)
Definition: keyingmaterialexporter.c:41
session
Definition: keyingmaterialexporter.c:56
endpoint
endpoint
Definition: keyingmaterialexporter.c:48
openvpn-plugin.h
ovpn_note
#define ovpn_note(fmt,...)
Definition: keyingmaterialexporter.c:45
openvpn_plugin_handle_t
void * openvpn_plugin_handle_t
Definition: openvpn-plugin.h:143
http-client.f
string f
Definition: http-client.py:6
session::user
char user[48]
Definition: keyingmaterialexporter.c:57
openvpn_plugin_args_open_in::callbacks
struct openvpn_plugin_callbacks * callbacks
Definition: openvpn-plugin.h:364
openvpn_plugin_func_v3
OPENVPN_EXPORT int openvpn_plugin_func_v3(const int version, struct openvpn_plugin_args_func_in const *args, struct openvpn_plugin_args_func_return *rv)
Definition: keyingmaterialexporter.c:256
MAXPATH
#define MAXPATH
Definition: keyingmaterialexporter.c:38
openvpn_plugin_callbacks::plugin_log
plugin_log_t plugin_log
Definition: openvpn-plugin.h:319
openvpn_plugin_client_destructor_v1
OPENVPN_EXPORT void openvpn_plugin_client_destructor_v1(openvpn_plugin_handle_t handle, void *ctx)
Definition: keyingmaterialexporter.c:283