-
Emily Ehlert authored4a0969a0
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
main.cpp 10.82 KiB
#include <iostream>
#include <dlfcn.h>
#include <openssl/evp.h>
#include <vector>
#include <chrono>
#include "openvpn-plugin.h"
#define STRUCT_VERSION 5
#define SMARTCARD_KEY_WRAPPING_PATH "./plugins/libSmartcardKeyWrappingLibrary.so"
#define SMARTCARD_KEY_DERIVATION_PATH "./plugins/libSmartcardKeyDerivationLibrary.so"
#define YUBIKEY_PATH "./plugins/libYubikeyKeyManagementLib.so"
#define SOFTHSM_PATH "./plugins/libPKCS11KeyWrappingLibrary.so"
#define SOFTHSM_WKC "kTkvfenmeqP7LR3uCgR3dZBt/E2XKVwEd8ZpUlpMqwdY0wx1iND6Yv2021y1VODpM0Z8y6gebW6Syf0Ye/EDjKr/Xv/qSos6l/U+mVeU+iizCr9844qx5iDyQI5VAducK9daf7nTdkZmeQVK80CvhtxbOsGUDcmoPQb6mHsbJXwmyoyLsxM2ubp7EWx1ZBNIYtor9LKq4uyqQFthKkPfp9Ab0//asGNaowHc5q1oCRZLquhDD03uZyMUj0Fb/Aqgol5zroSK2JW+hJzt+ngKbf5twLDwR5ksG6CS2qf6uD4c85CgUVGhf7hMWWs3eX6KVTzXpByeeUXjLJUQ/B9xFKkhPhF6vGsQeO4O8VaQXma3D2pDidqFGpItd+Y7fTDPsbwcGOkVbVRBASs="
#define YUBIKEY_WKC "+JBssE/PrQvQNdUm8Utbe06drdDnpB5+/31VdJLlZE7t5MufueRRHUVdD1xADWQA2QH1oHXUyYT204TxxvS362ZuaoVbYjF3aUfMjqmTQOCUxoE6piJvQdibNOMGPCoeO8NVTnXY92s602yBaIsPoMvtf5VCV3FFd9Fb56Ai0dmF9NErnW58oNsxXCFOJaQxbHmPmRGPqWQPxhirYBsW0xWYykkOQDtwV7Er/I6fPJh6bhDaSU//eVjGkqno+/xIUh5+YWSTQVIuhXCzySCp3CfVGo51RZ8k0NOwaQpSYqomshu7gDYjZiaPlTxdNyNFLLJbArQm9TNifR41hKx+39xjXZlhRa8BrOquih0DUFEaX5KQCfjHCDds6Wj1nSxVLl9KrNXR6tfRASs="
#define SMARTCARD_KEY_WRAPPING_WKC "fUH11DDJbn4VM2IIePOK/Uu1ytVbpTtBoFsTFjKhrM79AFUlx6ySchE0Xck3FSyvwtlBZQ+QRK7Gd/+x0xsNeL/ha7hKkRrW2JK6dPXN9qdAqhf50ZJKIwEboOZMD+pzrzJGeNslTwmRWOxuRXWFBQafjElePDSLZBKSzBJnAT5j6tB0vAXdS34j8IzyuuyLnoiDzrCm6S7aoaRfotLpxsLefPatKGwvoimxLEyfIcU4IaMhNktb7iRlFZAM15TLcEkQloB8Hv2moe7pus5EJHxsHPt/WmJYD7Naz6PXS+ynip++z6bu6LUC8kPIcnhqfHU7ieGnP8L2KD70Y/uQ+OkrcmCRhonkBdPgIFK/+RLBNJQtDwjyb6dXTgvn0LcCmLZx/lVfBy91ASs="
#define SMARTCARD_KEY_DERIVATION_WKC "KW9RjSfhyM6JBgfvs7/SDcFD9eFwO/5FiDOChWE1PZ31pfNhhYl5Iytg7Y6VDGuWNyhYq47koVuXdLSpva5qNSt1uRcqaY1nNbWwBMCgSIjcNJb3+t0FxtbZeYP4w78v18Ad8j3Qf2e3T2NN4VvEebffsihPf0vlvqGaRJvn7W8NXh3Y28/vPb4tXLSalpR5+lZrXHLwn+pl03sH3+nSYIO4Fk+DbSA0aVTKXDulVtNYugMy2P9XqQRtlM1lOuMBqxbyc2FB7oqFvrLTHVZnWqGFimvwasIaktKfkxXT+X1uaoUYzsFNbvs8s/Xul+9NF4YXMZpffMbA5ah5629zG8HW9L1tI9crd5GOKdH5QSThtSZinnSXhmhYCvAzhNdjDQc/oCpIicpeASs="
extern "C"
{
#include "base64.h"
}
void vlog_func(openvpn_plugin_log_flags_t flags, const char *plugin_name, const char *format, va_list arglist) {
(void)plugin_name;
// Ignore notes and debug messages
vprintf(format, arglist);
puts("");
}
void plugin_secure_memzero(void *data, size_t len) {
(void) data;
(void) len;
// Not Implemented
}
void plugin_log(openvpn_plugin_log_flags_t flags, const char *plugin_name, const char *format, ...) {
(void) flags;
(void) plugin_name;
(void) format;
// Not Implemented
}
std::string bytes_to_hex(const unsigned char *data, int size) {
char const hex_chars[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
std::string hex;
for( int i = 0; i < size; i++) {
unsigned char byte = data[i];
hex.push_back(hex_chars[ ( byte & 0xF0 ) >> 4 ]);
hex.push_back(hex_chars[ ( byte & 0x0F ) >> 0 ]);
}
return hex;
}
class Plugin
{
void *plugin_lib;
int (*openvpn_plugin_open_v3)(const int v3structver,
struct openvpn_plugin_args_open_in const *args,
struct openvpn_plugin_args_open_return *ret);
int (*openvpn_plugin_func_v3)(const int version,
struct openvpn_plugin_args_func_in const *arguments,
struct openvpn_plugin_args_func_return *retptr);
openvpn_plugin_handle_t handle{};
public:
explicit Plugin(const std::string &plugin_path);
~Plugin();
void open_plugin(int num, ...);
std::string execute_plugin(int call_type, int num, ...);
int up_plugin();
};
Plugin::Plugin(const std::string &plugin_path)
{
this->plugin_lib = dlopen(plugin_path.c_str(), RTLD_LAZY);
if (!this->plugin_lib) {
std::cerr << dlerror() << std::endl;
throw std::invalid_argument("Couldn't load plugin library");
}
this->openvpn_plugin_open_v3 = reinterpret_cast<int (*)(const int v3structver, struct openvpn_plugin_args_open_in const *args, struct openvpn_plugin_args_open_return *ret)>
(
dlsym(this->plugin_lib, "openvpn_plugin_open_v3")
);
this->openvpn_plugin_func_v3 = reinterpret_cast<int (*)(const int version, struct openvpn_plugin_args_func_in const *arguments, struct openvpn_plugin_args_func_return *retptr)>
(
dlsym(this->plugin_lib, "openvpn_plugin_func_v3")
);
char *error;
if ((error = dlerror()) != nullptr) {
std::cerr << error << std::endl;
throw std::exception();
}
}
void free_stringlist(openvpn_plugin_string_list **string_list)
{
auto next = *string_list;
while (next)
{
auto current = next;
next = current->next;
free(current);
}
free(string_list);
}
void Plugin::open_plugin(int num, ...) {
va_list valist;
va_start(valist, num);
const char **argv_open = static_cast<const char **>(
calloc(num, sizeof(char *)));
for (int i = 0; i < num; i++)
{
argv_open[i+1] = va_arg(valist, char *);
}
openvpn_plugin_callbacks callbacks = {
nullptr,
vlog_func,
plugin_secure_memzero,
openvpn_base64_encode,
openvpn_base64_decode,
};
struct openvpn_plugin_args_open_in args_open =
{
0,
reinterpret_cast<const char **const>(argv_open),
nullptr,
&callbacks,
SSLAPI_OPENSSL,
nullptr,
0,
0,
nullptr
};
struct openvpn_plugin_args_open_return ret_open{};
auto retlist = static_cast<openvpn_plugin_string_list **>(
calloc(1,sizeof(openvpn_plugin_string_list *)));
ret_open.return_list = retlist;
openvpn_plugin_open_v3(STRUCT_VERSION, &args_open, &ret_open);
this->handle = ret_open.handle;
free_stringlist(ret_open.return_list);
ret_open.return_list = nullptr;
}
std::string Plugin::execute_plugin(int call_type, int num, ...) {
va_list valist;
va_start(valist, num);
const char **argv_func = static_cast<const char **>(
calloc(num, sizeof(char *)));
for (int i = 0; i < num; i++)
{
argv_func[i+1] = va_arg(valist, char *);
}
struct openvpn_plugin_args_func_in args_func = {
call_type,
argv_func,
nullptr,
this->handle,
nullptr,
0,
nullptr
};
struct openvpn_plugin_args_func_return ret_func{};
auto retlist = static_cast<openvpn_plugin_string_list **>(
calloc(1,sizeof(openvpn_plugin_string_list *)));
ret_func.return_list = retlist;
int ret_code = openvpn_plugin_func_v3(STRUCT_VERSION, &args_func, &ret_func);
if(ret_code != OPENVPN_PLUGIN_FUNC_SUCCESS)
return "";
char * return_base64 = (*ret_func.return_list)->value;
unsigned char return_bytes[strlen(return_base64)];
int byte_len = openvpn_base64_decode(return_base64, return_bytes, (int) sizeof(return_bytes));
std::string return_hex = bytes_to_hex(return_bytes, byte_len);
free_stringlist(ret_func.return_list);
ret_func.return_list = nullptr;
return return_hex;
}
int Plugin::up_plugin() {
struct openvpn_plugin_args_func_in args_func = {
OPENVPN_PLUGIN_UP,
nullptr,
nullptr,
this->handle,
nullptr,
0,
nullptr
};
struct openvpn_plugin_args_func_return ret_func{};
auto retlist = static_cast<openvpn_plugin_string_list **>(
calloc(1,sizeof(openvpn_plugin_string_list *)));
ret_func.return_list = retlist;
int ret_code = openvpn_plugin_func_v3(STRUCT_VERSION, &args_func, &ret_func);
free_stringlist(ret_func.return_list);
ret_func.return_list = nullptr;
return ret_code;
}
Plugin::~Plugin() {
dlclose(this->plugin_lib);
}
enum plugin_types {
SMARTCARD_KEY_WRAPPING,
SMARTCARD_KEY_DERIVATION,
YUBIKEY,
SOFTHSM
};
Plugin createPlugin(int type) {
Plugin *plugin = nullptr;
switch(type)
{
case SMARTCARD_KEY_WRAPPING:
plugin = new Plugin(SMARTCARD_KEY_WRAPPING_PATH);
plugin->open_plugin(0);
break;
case SMARTCARD_KEY_DERIVATION:
plugin = new Plugin(SMARTCARD_KEY_DERIVATION_PATH);
plugin->open_plugin(0 ,"/usr/lib/pkcs11/libsofthsm2.so");
break;
case YUBIKEY:
plugin = new Plugin(YUBIKEY_PATH);
// Slot: 2; Access_Code: 0
plugin->open_plugin(2 , "2", "0");
plugin->up_plugin();
break;
case SOFTHSM:
plugin = new Plugin(SOFTHSM_PATH);
plugin->open_plugin(2 ,"/usr/lib/pkcs11/libsofthsm2.so", "1234");
break;
default:
throw std::invalid_argument("Plugin type not implemented!");
}
return *plugin;
}
int main() {
Plugin plugin = createPlugin(SMARTCARD_KEY_DERIVATION);
int iterations = 10;
std::string WKc = SMARTCARD_KEY_DERIVATION_WKC;
auto begin = std::chrono::high_resolution_clock::now();
for(int i = 0; i < iterations; i++)
{
plugin.execute_plugin(OPENVPN_PLUGIN_CLIENT_KEY_WRAPPING, 2, "unwrap", WKc.c_str());
std::cout << "\r" << i+1 << " / " << iterations << " completed";
std::cout.flush();
}
std::cout << std::endl;
auto end = std::chrono::high_resolution_clock::now();
float duration = (static_cast<float>(std::chrono::duration_cast<std::chrono::nanoseconds>(end-begin).count()) / 1000000);
std::cout << duration << "ms total, average : " << duration / iterations << "ms." << std::endl;
std::string result = plugin.execute_plugin(OPENVPN_PLUGIN_CLIENT_KEY_WRAPPING, 2, "unwrap", WKc.c_str());
/*
if(result != "1298789D57618EC2FEF4936C6DD96CB56BCDF804816E02286F14B4156D13BED63279101A4FFAEE654A3FE6F990428061A1F9DE83ABB1B1347B865BC3A68A4ED57446BC0B6206B45640C50A3CA776DA195FD38126A471EBE296E1F77BB4581EA605DA37EDF4946843B7ABAD840A08EB1F3C53F818D6C4D1664CF7A14412ED79D329ED22B66D7771350397B4EE8B6D9D94E666809D8B8C5E7ACF1E536D78DC07ABA147E73FDA4F0E527FD87B8B28CF425047B128890975F156EC48237D8D4BCEA8EA361573BC187B61984764344AA5C778972E249F8AA08097C0FCE9DB0C69C1A36A01BF71C73E3425B9B66F241990A423DCFF9642CD97E11D4B90A2E7CF0732BF010000000063920AA4")
throw std::exception();
*/
return EXIT_SUCCESS;
}