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-2026 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, see <https://www.gnu.org/licenses/>.
21 */
22
23/*
24 * This file implements a Sample (HTTP) SSO OpenVPN plugin module
25 *
26 * See the README file for build instructions.
27 */
28
29#include <stdio.h>
30#include <string.h>
31#include <strings.h>
32#include <stdlib.h>
33
34#include "openvpn-plugin.h"
35
36#ifndef MAXPATH
37#define MAXPATH 1024
38#endif
39
40#define ovpn_err(fmt, ...) plugin->log(PLOG_ERR, "SSO", fmt, ##__VA_ARGS__)
41#define ovpn_dbg(fmt, ...) plugin->log(PLOG_DEBUG, "SSO", fmt, ##__VA_ARGS__)
42#define ovpn_note(fmt, ...) plugin->log(PLOG_NOTE, "SSO", fmt, ##__VA_ARGS__)
43
45{
46 CLIENT = 1,
47 SERVER = 2
48};
49
50struct plugin
51{
54 int mask;
55};
56
57struct session
58{
59 char user[48];
60 char key[48];
61};
62
63/*
64 * Given an environmental variable name, search
65 * the envp array for its value, returning it
66 * if found or NULL otherwise.
67 */
68
69static const char *
70get_env(const char *name, const char *envp[])
71{
72 if (envp)
73 {
74 const size_t namelen = strlen(name);
75 for (int i = 0; envp[i]; ++i)
76 {
77 if (!strncmp(envp[i], name, namelen))
78 {
79 const char *cp = envp[i] + namelen;
80 if (*cp == '=')
81 {
82 return cp + 1;
83 }
84 }
85 }
86 }
87 return NULL;
88}
89
91openvpn_plugin_open_v3(const int version, 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
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 const char *objbuf;
124
125 x509_name = X509_get_subject_name(x509);
126 int n = X509_NAME_entry_count(x509_name);
127 for (int i = 0; i < n; ++i)
128 {
129 X509_NAME_ENTRY *ent;
130
131 if (!(ent = X509_NAME_get_entry(x509_name, i)))
132 {
133 continue;
134 }
135 if (!(fn = X509_NAME_ENTRY_get_object(ent)))
136 {
137 continue;
138 }
139 if (!(val = X509_NAME_ENTRY_get_data(ent)))
140 {
141 continue;
142 }
143 if ((fn_nid = OBJ_obj2nid(fn)) == NID_undef)
144 {
145 continue;
146 }
147 if (!(objbuf = OBJ_nid2sn(fn_nid)))
148 {
149 continue;
150 }
151 unsigned char *buf = NULL;
152 if (ASN1_STRING_to_UTF8(&buf, val) < 0)
153 {
154 continue;
155 }
156
157 if (!strncasecmp(objbuf, "CN", 2))
158 {
159 strncpy(sess->user, (char *)buf, sizeof(sess->user) - 1);
160 }
161
162 OPENSSL_free(buf);
163 }
164}
165
166static int
168{
169 struct plugin *plugin = (struct plugin *)args->handle;
170 struct session *sess = (struct session *)args->per_client_context;
171
172 /* we store cert subject for the server end point only */
173 if (plugin->type != SERVER)
174 {
176 }
177
178 if (!args->current_cert)
179 {
180 ovpn_err("this example plugin requires client certificate");
182 }
183
184 session_user_set(sess, args->current_cert);
185
187}
188
189static void
190file_store(char *file, char *content)
191{
192 FILE *f;
193 if (!(f = fopen(file, "w+")))
194 {
195 return;
196 }
197
198 fprintf(f, "%s", content);
199 fclose(f);
200}
201
202static void
204{
205 struct plugin *plugin = (struct plugin *)args->handle;
206 struct session *sess = (struct session *)args->per_client_context;
207
208 char file[MAXPATH];
209 snprintf(file, sizeof(file) - 1, "/tmp/openvpn_sso_%s", sess->key);
210 ovpn_note("app session file: %s", file);
211 file_store(file, sess->user);
212}
213
214static void
216{
217 struct plugin *plugin = (struct plugin *)args->handle;
218 struct session *sess = (struct session *)args->per_client_context;
219
220 char *file = "/tmp/openvpn_sso_user";
221 ovpn_note("app session file: %s", file);
222 file_store(file, sess->key);
223}
224
225static int
228{
229 struct plugin *plugin = (struct plugin *)args->handle;
230 struct session *sess = (struct session *)args->per_client_context;
231
232 const char *key;
233 if (!(key = get_env("exported_keying_material", args->envp)))
234 {
236 }
237
238 strncpy(sess->key, key, sizeof(sess->key) - 1);
239 ovpn_note("app session key: %s", sess->key);
240
241 switch (plugin->type)
242 {
243 case SERVER:
244 server_store(args);
245 break;
246
247 case CLIENT:
248 client_store(args);
250 }
251
252 ovpn_note("app session user: %s", sess->user);
254}
255
257openvpn_plugin_func_v3(const int version, 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
271OPENVPN_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
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
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,...)
void * openvpn_plugin_handle_t
#define OPENVPN_PLUGIN_MASK(x)
#define OPENVPN_PLUGIN_TLS_FINAL
#define OPENVPN_PLUGIN_TLS_VERIFY
void(* plugin_log_t)(openvpn_plugin_log_flags_t flags, const char *plugin_name, const char *format,...) _ovpn_chk_fmt(3
#define OPENVPN_PLUGIN_FUNC_SUCCESS
#define OPENVPN_EXPORT
#define OPENVPN_PLUGIN_FUNC_ERROR
Container for unidirectional cipher and HMAC key material.
Definition crypto.h:152
Arguments used to transport variables to and from the plug-in.
openvpn_x509_cert_t * current_cert
openvpn_plugin_handle_t handle
Arguments used to transport variables to and from the plug-in.
Arguments used to transport variables to the plug-in.
struct openvpn_plugin_callbacks * callbacks
Arguments used to transport variables from the plug-in back to the OpenVPN process.
openvpn_plugin_handle_t handle
plugin_log_t log
enum endpoint type