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
48enum endpoint { CLIENT = 1, SERVER = 2 };
49
50struct plugin {
51 plugin_log_t log;
53 int mask;
54};
55
56struct 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
67static const char *
68get_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
89OPENVPN_EXPORT int
90openvpn_plugin_open_v3(const int version,
91 struct openvpn_plugin_args_open_in const *args,
92 struct openvpn_plugin_args_open_return *rv)
93{
94 struct plugin *plugin = calloc(1, sizeof(*plugin));
95
96 if (plugin == NULL)
97 {
98 printf("PLUGIN: allocating memory for context failed\n");
99 return OPENVPN_PLUGIN_FUNC_ERROR;
100 }
101
102 plugin->type = get_env("remote_1", args->envp) ? CLIENT : SERVER;
103 plugin->log = args->callbacks->plugin_log;
104
105 plugin->mask = OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_TLS_FINAL);
106 plugin->mask |= OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_TLS_VERIFY);
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
113 return OPENVPN_PLUGIN_FUNC_SUCCESS;
114}
115
116static void
117session_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
165static int
166tls_verify(struct openvpn_plugin_args_func_in const *args)
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 {
174 return OPENVPN_PLUGIN_FUNC_SUCCESS;
175 }
176
177 if (!args->current_cert)
178 {
179 ovpn_err("this example plugin requires client certificate");
180 return OPENVPN_PLUGIN_FUNC_ERROR;
181 }
182
183 session_user_set(sess, args->current_cert);
184
185 return OPENVPN_PLUGIN_FUNC_SUCCESS;
186}
187
188static void
189file_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
201static void
202server_store(struct openvpn_plugin_args_func_in const *args)
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
213static void
214client_store(struct openvpn_plugin_args_func_in const *args)
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
224static int
225tls_final(struct openvpn_plugin_args_func_in const *args,
226 struct openvpn_plugin_args_func_return *rv)
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 {
234 return OPENVPN_PLUGIN_FUNC_ERROR;
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);
248 return OPENVPN_PLUGIN_FUNC_SUCCESS;
249 }
250
251 ovpn_note("app session user: %s", sess->user);
252 return OPENVPN_PLUGIN_FUNC_SUCCESS;
253}
254
255OPENVPN_EXPORT int
256openvpn_plugin_func_v3(const int version,
257 struct openvpn_plugin_args_func_in const *args,
258 struct openvpn_plugin_args_func_return *rv)
259{
260 switch (args->type)
261 {
262 case OPENVPN_PLUGIN_TLS_VERIFY:
263 return tls_verify(args);
264
265 case OPENVPN_PLUGIN_TLS_FINAL:
266 return tls_final(args, rv);
267 }
268 return OPENVPN_PLUGIN_FUNC_SUCCESS;
269}
270
271OPENVPN_EXPORT void *
272openvpn_plugin_client_constructor_v1(openvpn_plugin_handle_t handle)
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
282OPENVPN_EXPORT void
283openvpn_plugin_client_destructor_v1(openvpn_plugin_handle_t handle, void *ctx)
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
294OPENVPN_EXPORT void
295openvpn_plugin_close_v1(openvpn_plugin_handle_t handle)
296{
297 struct plugin *plugin = (struct plugin *)handle;
298 free(plugin);
299}
static void server_store(struct openvpn_plugin_args_func_in const *args)
OPENVPN_EXPORT void openvpn_plugin_close_v1(openvpn_plugin_handle_t handle)
static int tls_verify(struct openvpn_plugin_args_func_in const *args)
#define MAXPATH
static void client_store(struct openvpn_plugin_args_func_in const *args)
OPENVPN_EXPORT void openvpn_plugin_client_destructor_v1(openvpn_plugin_handle_t handle, void *ctx)
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)
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)
static void file_store(char *file, char *content)
static const char * get_env(const char *name, const char *envp[])
static int tls_final(struct openvpn_plugin_args_func_in const *args, struct openvpn_plugin_args_func_return *rv)
OPENVPN_EXPORT void * openvpn_plugin_client_constructor_v1(openvpn_plugin_handle_t handle)
static void session_user_set(struct session *sess, X509 *x509)
#define ovpn_err(fmt,...)
#define ovpn_note(fmt,...)
Container for unidirectional cipher and HMAC key material.
Definition crypto.h:152
plugin_log_t log
enum endpoint type