Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 17 additions & 6 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,25 +1,36 @@
cmake_minimum_required(VERSION 3.7)
project(strongswan-import)

set(STANDALONE_IMPORT)
set(CMAKE_CXX_STANDARD 14)
find_package(PkgConfig REQUIRED)
set(CMAKE_CXX_COMPILER "clang++")
set(CMAKE_C_COMPILER "clang")
set(CMAKE_C_FLAGS "-fno-omit-frame-pointer -g -fsanitize=address -fsanitize-coverage=trace-pc-guard")
set(CMAKE_CXX_FLAGS "-fno-omit-frame-pointer -g -fsanitize=address -fsanitize-coverage=trace-pc-guard")

set(SOURCE_FILES main.cc)
add_library(strongswan_profile STATIC strongswan_profile.c)
add_executable(fuzz fuzz.cc)
add_executable(strongswan-import ${SOURCE_FILES})

pkg_search_module(LIBSSL libssl)
pkg_search_module(GLIB glib-2.0)
pkg_search_module(JSON json-glib-1.0)
pkg_search_module(LIBNM libnm)
pkg_search_module(LIBCRYPTO libcrypto)
include_directories(${LIBNM_INCLUDE_DIRS})
include_directories(${GLIB_INCLUDE_DIRS})
include_directories(${JSON_INCLUDE_DIRS})
link_libraries(${GLIB_LIBRARIES})
link_libraries(${JSON_LIBRARIES})
link_libraries(${LIBNM_LIBRARIES})
add_library(strongswan_profile STATIC strongswan_profile.c)
set(SOURCE_FILES main.cc)
add_executable(fuzz fuzz.cc strongswan_profile.c)

target_include_directories(strongswan_profile PUBLIC
${GLIB_INCLUDE_DIRS} ${JSON_INCLUDE_DIRS} ${LIBNM_INCLUDE_DIRS}
${JSON_INCLUDE_DIRS} ${LIBSSL_INCLUDE_DIRS} ${LIBCRYPTO_INCLUDE_DIRS})
target_link_libraries(strongswan_profile PUBLIC
${GLIB_LIBRARIES} ${JSON_LIBRARIES} ${LIBNM_LIBRARIES}
${JSON_LIBRARIES} ${LIBSSL_LIBRARIES} ${LIBCRYPTO_LIBRARIES})

target_link_libraries(fuzz /usr/lib/llvm-4.0/lib/libFuzzer.a)
add_executable(strongswan-import ${SOURCE_FILES})
target_link_libraries(strongswan-import strongswan_profile)
target_link_libraries(fuzz strongswan_profile)
2 changes: 1 addition & 1 deletion fuzz.cc
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#include <cstdint>
#include <cstdlib>
#include "strongswan_profile.h"
#include "strongswan_profile.hh"

extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
GError *error = NULL;
Expand Down
5 changes: 2 additions & 3 deletions main.cc
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
#include <iostream>
#include <glib.h>
#include <NetworkManager.h>
#include "strongswan_profile.h"

//extern "C" NMConnection* strongswan_import_sswan(const char *path);
#include "strongswan_profile.hh"


static void added_cb (GObject *client, GAsyncResult *result, gpointer user_data) {
Expand Down Expand Up @@ -31,6 +29,7 @@ int main(int argc, char **argv) {
GError *error = NULL;
if (argc <= 1)
return -1;

NMConnection *connection = strongswan_import_sswan(nullptr, argv[1], &error);
if(error) {
g_message("%s", error->message);
Expand Down
167 changes: 140 additions & 27 deletions strongswan_profile.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,18 @@
* SOFTWARE.
*/

#include <openssl/pem.h>
#include <openssl/err.h>
#include <openssl/pkcs12.h>
#include <openssl/bio.h>
#include <stdlib.h>
#include <string.h>
#include "strongswan_profile.h"

static void serializable_iface_init(JsonSerializableIface *iface) {}

G_DEFINE_TYPE_WITH_CODE(StrongSwanProfile, strongswan_profile, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE(JSON_TYPE_SERIALIZABLE, serializable_iface_init));
G_IMPLEMENT_INTERFACE(JSON_TYPE_SERIALIZABLE, serializable_iface_init))

static GParamSpec *properties[N_PROPERTIES] = {NULL};

Expand Down Expand Up @@ -135,15 +139,15 @@ static void strongswan_profile_dispose(GObject *gObject) {

static void strongswan_profile_finalize(GObject *gObject) {
StrongSwanProfile *priv = strongswan_profile_get_instance_private(STRONGSWAN_PROFILE_SOURCE(gObject));
if(priv->user_key) g_free(priv->user_key);
if(priv->user_cert) g_free(priv->user_cert);
if(priv->certificate) g_free(priv->certificate);
if(priv->remote_addr) g_free(priv->remote_addr);
if(priv->name) g_free(priv->name);
if(priv->esp) g_free(priv->esp);
if(priv->ike) g_free(priv->ike);
if(priv->p12) g_free(priv->p12);
if(priv->uuid) g_free(priv->uuid);
if (priv->user_key) g_free(priv->user_key);
if (priv->user_cert) g_free(priv->user_cert);
if (priv->certificate) g_free(priv->certificate);
if (priv->remote_addr) g_free(priv->remote_addr);
if (priv->name) g_free(priv->name);
if (priv->esp) g_free(priv->esp);
if (priv->ike) g_free(priv->ike);
if (priv->p12) g_free(priv->p12);
if (priv->uuid) g_free(priv->uuid);
}

static void strongswan_profile_class_init(StrongSwanProfileClass *klass) {
Expand All @@ -158,10 +162,10 @@ static void strongswan_profile_class_init(StrongSwanProfileClass *klass) {
NULL,
G_PARAM_READWRITE);
properties[PROP_VPNNAME] = g_param_spec_string("name",
"Profile name",
"The name of the VPN Profile.",
NULL,
G_PARAM_READWRITE);
"Profile name",
"The name of the VPN Profile.",
NULL,
G_PARAM_READWRITE);
properties[PROP_METHOD] = g_param_spec_enum("method",
"VPN connection method",
"The method of VPN connection; one of (key, agent, smartcard, eap)",
Expand Down Expand Up @@ -214,15 +218,18 @@ NMConnection *parse_sswan(JsonParser *parser, GError **error) {
NMSettingIPConfig *s_ip4;
NMSettingVpn *s_vpn;
StrongSwanProfile *profile;
gsize length = 0;
profile_t *prof;
char *p12_data;
JsonNode *root = json_parser_get_root(parser);

if(root==NULL) { return NULL; }
if (root == NULL) { return NULL; }

//TODO: check for memory leaks throughout all of this
connection = nm_simple_connection_new();

profile = (StrongSwanProfile *) json_gobject_deserialize(STRONGSWAN_PROFILE_TYPE_SOURCE, root);
if(profile == NULL) { return NULL; }
profile = (StrongSwanProfile *) json_gobject_deserialize(STRONGSWAN_PROFILE_TYPE_SOURCE, root);
if (profile == NULL) { return NULL; }

s_con = NM_SETTING_CONNECTION(nm_setting_connection_new());

Expand Down Expand Up @@ -277,14 +284,23 @@ NMConnection *parse_sswan(JsonParser *parser, GError **error) {
switch (profile->method) {
case METHOD_KEY:
setting_vpn_add_data_item(s_vpn, "method", "key");
if (profile->p12)
nm_setting_vpn_add_secret(s_vpn, "p12", profile->p12);
if (profile->certificate)
setting_vpn_add_data_item(s_vpn, "certificate", profile->certificate);
if (profile->user_cert)
setting_vpn_add_data_item(s_vpn, "usercert", profile->user_cert);
if (profile->user_key)
setting_vpn_add_data_item(s_vpn, "userkey", profile->user_key);
if (profile->p12) {
p12_data = (char *) g_base64_decode(profile->p12, &length);
g_assert(p12_data != NULL);
prof = load_p12(p12_data, length);
g_free(p12_data);
nm_setting_vpn_add_secret(s_vpn, "userkey", prof->priv_key);
nm_setting_vpn_add_secret(s_vpn, "usercert", prof->user_cert);
nm_setting_vpn_add_secret(s_vpn, "certificate", prof->ca);
prof->destroy(prof);
} else {
if (profile->certificate)
setting_vpn_add_data_item(s_vpn, "certificate", profile->certificate);
if (profile->user_cert)
setting_vpn_add_data_item(s_vpn, "usercert", profile->user_cert);
if (profile->user_key)
setting_vpn_add_data_item(s_vpn, "userkey", profile->user_key);
}
break;
case METHOD_AGENT:
case METHOD_SMARTCARD:
Expand Down Expand Up @@ -321,6 +337,7 @@ NMConnection *parse_sswan(JsonParser *parser, GError **error) {
return connection;
}


NMConnection *strongswan_fuzz_import(const char *data, size_t size, GError **error) {
NMConnection *connection;
JsonParser *parser = json_parser_new();
Expand All @@ -329,11 +346,107 @@ NMConnection *strongswan_fuzz_import(const char *data, size_t size, GError **err
g_object_unref(parser);
return NULL;
}
connection = parse_sswan(parser, error);
connection = parse_sswan(parser, error);
g_object_unref(parser);
return connection;
}

void destroy_profile_fn(profile_t *this) {
if (this->priv_key) g_free(this->priv_key);
if (this->user_cert) g_free(this->user_cert);
if (this->ca) g_free(this->ca);
free(this);
}

profile_t *profile_t_new(EVP_PKEY *pkey, X509 *cert, struct stack_st_X509 *ca) {
BIO *biobuf;
char *buf;
profile_t *profile = malloc(sizeof(profile_t));
profile->destroy = destroy_profile_fn;
profile->priv_key = NULL;
profile->user_cert = NULL;
profile->ca = NULL;

if (!pkey) {
fprintf(stderr, "No private key was found.\n");
if (cert) X509_free(cert);
if (ca) sk_X509_pop_free(ca, X509_free);
exit(1);
}
if (!cert) {
fprintf(stderr, "No user certificate was found.\n");
EVP_PKEY_free(pkey);
if (ca) sk_X509_pop_free(ca, X509_free);
exit(1);
}
if (!ca || !sk_X509_num(ca)) {
fprintf(stderr, "No CA was found.\n");
EVP_PKEY_free(pkey);
X509_free(cert);
exit(1);
}

biobuf = BIO_new(BIO_s_mem());
PEM_write_bio_PrivateKey(biobuf, pkey, NULL, NULL, 0, NULL, NULL);
buf = malloc(biobuf->num_write + 1);
memset(buf, 0, biobuf->num_write + 1);
// TODO: security: I don't like casting... would it ever be possible to overflow this?
BIO_read(biobuf, buf, (int) biobuf->num_write);
profile->priv_key = g_strdup(buf);

PEM_write_bio_X509_AUX(biobuf, cert);
buf = realloc(buf, biobuf->num_write + 1);
memset(buf, 0, biobuf->num_write + 1);
BIO_read(biobuf, buf, (int) biobuf->num_write);
profile->user_cert = g_strdup(buf);

// Just take the first CA... ignore the rest.
PEM_write_bio_X509_AUX(biobuf, sk_X509_value(ca, 0));
buf = realloc(buf, biobuf->num_write + 1);
memset(buf, 0, biobuf->num_write + 1);
BIO_read(biobuf, buf, (int) biobuf->num_write);
profile->ca = g_strdup(buf);

BIO_free(biobuf);
free(buf);
EVP_PKEY_free(pkey);
X509_free(cert);
sk_X509_pop_free(ca, X509_free);
return profile;
}

profile_t *load_p12(char *data, size_t len) {
EVP_PKEY *pkey;
X509 *cert;
STACK_OF(X509) *ca = NULL;
PKCS12 *p12;
char *pass;
BIO *bio;

OpenSSL_add_all_algorithms();
ERR_load_crypto_strings();
bio = BIO_new_mem_buf(data, (int) len);

p12 = d2i_PKCS12_bio(bio, NULL);
if (!p12) {
ERR_print_errors_fp(stderr);
BIO_free(bio);
exit(1);
}
pass = getpass("Passphrase:");
if (!PKCS12_parse(p12, pass, &pkey, &cert, &ca)) {
ERR_print_errors_fp(stderr);
BIO_free(bio);
PKCS12_free(p12);
free(pass);
exit(1);
}
BIO_free(bio);
PKCS12_free(p12);
free(pass);
return profile_t_new(pkey, cert, ca);
}

NMConnection *strongswan_import_sswan(NMVpnEditorPlugin *iface, const char *path, GError **error) {
NMConnection *connection;
JsonParser *parser = json_parser_new();
Expand All @@ -342,7 +455,7 @@ NMConnection *strongswan_import_sswan(NMVpnEditorPlugin *iface, const char *path
g_object_unref(parser);
return NULL;
}
connection = parse_sswan(parser, error);
connection = parse_sswan(parser, error);
g_object_unref(parser);
return connection;
}
Expand Down
15 changes: 15 additions & 0 deletions strongswan_profile.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@
#ifndef STRONGSWAN_PROFILE_H
#define STRONGSWAN_PROFILE_H 1

#include <openssl/pem.h>
#include <openssl/err.h>
#include <openssl/pkcs12.h>
#include <openssl/bio.h>
#include <glib-object.h>
#include <json-glib/json-glib.h>
#include <NetworkManager.h>
Expand Down Expand Up @@ -79,11 +83,22 @@ typedef struct StrongSwanProfileClass_ {
GObjectClass parent_class;
} StrongSwanProfileClass;

typedef struct profile_t {
gchar *priv_key;
gchar *user_cert;
gchar *ca;
void (*destroy)(struct profile_t *this);
} profile_t;


GType strongswan_profile_get_type(void);
GType strongswan_vpn_method_get_type(void);
NMConnection *parse_sswan(JsonParser *parser, GError **error);
NMConnection *strongswan_import_sswan(NMVpnEditorPlugin *iface, const char *path, GError **error);
NMConnection *strongswan_fuzz_import(const char *data, size_t size, GError **error);
profile_t* load_p12(char *data, size_t len);
void destroy_profile_fn(profile_t *this);
profile_t* profile_t_new(EVP_PKEY *pkey, X509 *cert, struct stack_st_X509 *ca);

G_END_DECLS

Expand Down
16 changes: 16 additions & 0 deletions strongswan_profile.hh
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//
// Created by ubuntu on 6/5/17.
//

#ifndef STRONGSWAN_IMPORT_STRONGSWAN_HH_H
#define STRONGSWAN_IMPORT_STRONGSWAN_HH_H
#include <NetworkManager.h>

G_BEGIN_DECLS

NMConnection *strongswan_import_sswan(NMVpnEditorPlugin *iface, const char *path, GError **error);
NMConnection *strongswan_fuzz_import(const char *data, size_t size, GError **error);

G_END_DECLS

#endif //STRONGSWAN_IMPORT_STRONGSWAN_HH_H