diff --git a/lib/Makefile.am b/lib/Makefile.am
index 8f68202..0088e0b 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -18,14 +18,20 @@ noinst_LTLIBRARIES += $(core_lib)
 
 lib_libpbcore_la_CPPFLAGS = \
 	$(AM_CPPFLAGS) \
-	-DPREFIX='"$(prefix)"'
+	-DPREFIX='"$(prefix)"' \
+	$(OPENSSL_INCLUDES)
 
-if WITH_GPGME
-gpg_int_SOURCES = lib/security/gpg.h \
-	lib/security/gpg.c
-else
-gpg_int_SOURCES =
-endif
+lib_libpbcore_la_LIBADD = \
+	$(GPGME_LIBS) \
+	$(OPENSSL_LIBS)
+
+lib_libpbcore_la_LDFLAGS = \
+	$(AM_LDFLAGS) \
+	$(OPENSSL_LDFLAGS)
+
+lib_libpbcore_la_CFLAGS = \
+	$(AM_CFLAGS) \
+	$(GPGME_CFLAGS)
 
 lib_libpbcore_la_SOURCES = \
 	lib/ccan/endian/endian.h \
@@ -59,19 +65,27 @@ lib_libpbcore_la_SOURCES = \
 	lib/util/util.h \
 	lib/flash/config.h \
 	lib/flash/flash.h \
-	$(gpg_int_SOURCES)
+	lib/security/security.h
 
 if ENABLE_MTD
 lib_libpbcore_la_SOURCES += \
 	lib/flash/flash.c
 
-lib_libpbcore_la_CPPFLAGS += \
-	$(AM_CPPFLAGS)
-
-lib_libpbcore_la_LDFLAGS = \
-	$(AM_LDFLAGS) \
+lib_libpbcore_la_LDFLAGS += \
 	$(LIBFLASH_LIBS)
+endif
 
+if WITH_GPGME
 lib_libpbcore_la_SOURCES += \
-	lib/flash/flash.c
+	lib/security/common.c \
+	lib/security/gpg.c
+else
+if WITH_OPENSSL
+lib_libpbcore_la_SOURCES += \
+	lib/security/common.c \
+	lib/security/openssl.c
+else
+lib_libpbcore_la_SOURCES += \
+	lib/security/none.c
+endif
 endif
diff --git a/lib/security/common.c b/lib/security/common.c
new file mode 100644
index 0000000..df04054
--- /dev/null
+++ b/lib/security/common.c
@@ -0,0 +1,230 @@
+/*
+ *  Copyright (C) 2016 Raptor Engineering, LLC
+ *  Copyright (C) 2018 Opengear, Inc
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#if defined(HAVE_CONFIG_H)
+#include "config.h"
+#endif
+
+#include <stdbool.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <dirent.h>
+#include <string.h>
+#include <fcntl.h>
+#include <locale.h>
+#include <sys/types.h>
+
+#include <log/log.h>
+#include <file/file.h>
+#include <talloc/talloc.h>
+#include <url/url.h>
+#include <util/util.h>
+#include <i18n/i18n.h>
+
+#include "security.h"
+
+struct pb_url * get_signature_url(void *ctx, struct pb_url *base_file)
+{
+	struct pb_url *signature_file = NULL;
+
+	signature_file = pb_url_copy(ctx, base_file);
+	talloc_free(signature_file->file);
+	signature_file->file = talloc_asprintf(signature_file,
+		"%s.sig", base_file->file);
+	talloc_free(signature_file->path);
+	signature_file->path = talloc_asprintf(signature_file,
+		"%s.sig", base_file->path);
+
+	return signature_file;
+}
+
+int validate_boot_files(struct boot_task *boot_task) {
+    int result = 0;
+    char *kernel_filename = NULL;
+    char *initrd_filename = NULL;
+    char *dtb_filename = NULL;
+
+    FILE *authorized_signatures_handle = NULL;
+
+    char cmdline_template[] = "/tmp/petitbootXXXXXX";
+    int cmdline_fd = mkstemp(cmdline_template);
+    FILE *cmdline_handle = NULL;
+
+    const char* local_initrd_signature = (boot_task->verify_signature) ?
+        boot_task->local_initrd_signature : NULL;
+    const char* local_dtb_signature = (boot_task->verify_signature) ?
+        boot_task->local_dtb_signature : NULL;
+    const char* local_image_signature = (boot_task->verify_signature) ?
+        boot_task->local_image_signature : NULL;
+    const char* local_cmdline_signature =
+        (boot_task->verify_signature || boot_task->decrypt_files) ?
+        boot_task->local_cmdline_signature : NULL;
+
+    if ((!boot_task->verify_signature) && (!boot_task->decrypt_files))
+        return result;
+
+    /* Load authorized signatures file */
+    authorized_signatures_handle = fopen(LOCKDOWN_FILE, "r");
+    if (!authorized_signatures_handle) {
+        pb_log("%s: unable to read lockdown file\n", __func__);
+        return KEXEC_LOAD_SIG_SETUP_INVALID;
+    }
+
+    /* Copy files to temporary directory for verification / boot */
+    result = copy_file_secure_dest(boot_task,
+        boot_task->local_image,
+        &kernel_filename);
+    if (result) {
+        pb_log("%s: image copy failed: (%d)\n",
+            __func__, result);
+        return result;
+    }
+    if (boot_task->local_initrd) {
+        result = copy_file_secure_dest(boot_task,
+            boot_task->local_initrd,
+            &initrd_filename);
+        if (result) {
+            pb_log("%s: initrd copy failed: (%d)\n",
+                __func__, result);
+            return result;
+        }
+    }
+    if (boot_task->local_dtb) {
+        result = copy_file_secure_dest(boot_task,
+            boot_task->local_dtb,
+            &dtb_filename);
+        if (result) {
+            pb_log("%s: dtb copy failed: (%d)\n",
+                __func__, result);
+            return result;
+        }
+    }
+    boot_task->local_image_override = talloc_strdup(boot_task,
+        kernel_filename);
+    if (boot_task->local_initrd)
+        boot_task->local_initrd_override = talloc_strdup(boot_task,
+            initrd_filename);
+    if (boot_task->local_dtb)
+        boot_task->local_dtb_override = talloc_strdup(boot_task,
+            dtb_filename);
+
+    /* Write command line to temporary file for verification */
+    if (cmdline_fd < 0) {
+        /* mkstemp failed */
+        pb_log("%s: failed: unable to create command line"
+            " temporary file for verification\n",
+            __func__);
+        result = -1;
+    }
+    else {
+        cmdline_handle = fdopen(cmdline_fd, "w");
+    }
+    if (!cmdline_handle) {
+        /* Failed to open file */
+        pb_log("%s: failed: unable to write command line"
+            " temporary file for verification\n",
+            __func__);
+        result = -1;
+    }
+    else {
+        fwrite(boot_task->args, sizeof(char),
+            strlen(boot_task->args), cmdline_handle);
+        fflush(cmdline_handle);
+    }
+
+    if (boot_task->verify_signature) {
+        /* Check signatures */
+        if (verify_file_signature(kernel_filename,
+            local_image_signature,
+            authorized_signatures_handle,
+            KEYRING_PATH))
+            result = KEXEC_LOAD_SIGNATURE_FAILURE;
+        if (verify_file_signature(cmdline_template,
+            local_cmdline_signature,
+            authorized_signatures_handle,
+            KEYRING_PATH))
+            result = KEXEC_LOAD_SIGNATURE_FAILURE;
+
+        if (boot_task->local_initrd_signature)
+            if (verify_file_signature(initrd_filename,
+                local_initrd_signature,
+                authorized_signatures_handle,
+                KEYRING_PATH))
+                result = KEXEC_LOAD_SIGNATURE_FAILURE;
+        if (boot_task->local_dtb_signature)
+            if (verify_file_signature(dtb_filename,
+                local_dtb_signature,
+                authorized_signatures_handle,
+                KEYRING_PATH))
+                result = KEXEC_LOAD_SIGNATURE_FAILURE;
+
+        /* Clean up */
+        if (cmdline_handle) {
+            fclose(cmdline_handle);
+            unlink(cmdline_template);
+        }
+        fclose(authorized_signatures_handle);
+    } else if (boot_task->decrypt_files) {
+        /* Decrypt files */
+        if (decrypt_file(kernel_filename,
+            authorized_signatures_handle,
+            KEYRING_PATH))
+            result = KEXEC_LOAD_DECRYPTION_FALURE;
+        if (verify_file_signature(cmdline_template,
+            local_cmdline_signature,
+            authorized_signatures_handle,
+            KEYRING_PATH))
+            result = KEXEC_LOAD_SIGNATURE_FAILURE;
+        if (boot_task->local_initrd)
+            if (decrypt_file(initrd_filename,
+                authorized_signatures_handle,
+                KEYRING_PATH))
+                result = KEXEC_LOAD_DECRYPTION_FALURE;
+        if (boot_task->local_dtb)
+            if (decrypt_file(dtb_filename,
+                authorized_signatures_handle,
+                KEYRING_PATH))
+                result = KEXEC_LOAD_DECRYPTION_FALURE;
+
+        /* Clean up */
+        if (cmdline_handle) {
+            fclose(cmdline_handle);
+            unlink(cmdline_template);
+        }
+        fclose(authorized_signatures_handle);
+    }
+
+    return result;
+}
+
+void validate_boot_files_cleanup(struct boot_task *boot_task) {
+	if ((boot_task->verify_signature) || (boot_task->decrypt_files)) {
+		unlink(boot_task->local_image_override);
+		if (boot_task->local_initrd_override)
+			unlink(boot_task->local_initrd_override);
+		if (boot_task->local_dtb_override)
+			unlink(boot_task->local_dtb_override);
+
+		talloc_free(boot_task->local_image_override);
+		if (boot_task->local_initrd_override)
+			talloc_free(boot_task->local_initrd_override);
+		if (boot_task->local_dtb_override)
+			talloc_free(boot_task->local_dtb_override);
+	}
+}
+
diff --git a/lib/security/gpg.c b/lib/security/gpg.c
index 76e2c6c..761d6ce 100644
--- a/lib/security/gpg.c
+++ b/lib/security/gpg.c
@@ -25,6 +25,7 @@
 #include <dirent.h>
 #include <string.h>
 #include <fcntl.h>
+#include <locale.h>
 #include <sys/types.h>
 
 #include <log/log.h>
@@ -34,7 +35,9 @@
 #include <util/util.h>
 #include <i18n/i18n.h>
 
-#include "gpg.h"
+#include <gpgme.h>
+
+#include "security.h"
 
 /*
  * If --with-signed-boot is enabled lib/security provides the ability to handle
@@ -45,21 +48,6 @@
  * to guarantee secure boot by itself.
  */
 
-struct pb_url * gpg_get_signature_url(void *ctx, struct pb_url *base_file)
-{
-	struct pb_url *signature_file = NULL;
-
-	signature_file = pb_url_copy(ctx, base_file);
-	talloc_free(signature_file->file);
-	signature_file->file = talloc_asprintf(signature_file,
-		"%s.sig", base_file->file);
-	talloc_free(signature_file->path);
-	signature_file->path = talloc_asprintf(signature_file,
-		"%s.sig", base_file->path);
-
-	return signature_file;
-}
-
 int decrypt_file(const char *filename,
 	FILE *authorized_signatures_handle, const char *keyring_path)
 {
@@ -362,181 +350,6 @@ int verify_file_signature(const char *plaintext_filename,
 	return 0;
 }
 
-int gpg_validate_boot_files(struct boot_task *boot_task) {
-	int result = 0;
-	char *kernel_filename = NULL;
-	char *initrd_filename = NULL;
-	char *dtb_filename = NULL;
-
-	FILE *authorized_signatures_handle = NULL;
-
-	char cmdline_template[] = "/tmp/petitbootXXXXXX";
-	int cmdline_fd = mkstemp(cmdline_template);
-	FILE *cmdline_handle = NULL;
-
-	const char* local_initrd_signature = (boot_task->verify_signature) ?
-		boot_task->local_initrd_signature : NULL;
-	const char* local_dtb_signature = (boot_task->verify_signature) ?
-		boot_task->local_dtb_signature : NULL;
-	const char* local_image_signature = (boot_task->verify_signature) ?
-		boot_task->local_image_signature : NULL;
-	const char* local_cmdline_signature =
-		(boot_task->verify_signature || boot_task->decrypt_files) ?
-		boot_task->local_cmdline_signature : NULL;
-
-	if ((!boot_task->verify_signature) && (!boot_task->decrypt_files))
-		return result;
-
-	/* Load authorized signatures file */
-	authorized_signatures_handle = fopen(LOCKDOWN_FILE, "r");
-	if (!authorized_signatures_handle) {
-		pb_log("%s: unable to read lockdown file\n", __func__);
-		return KEXEC_LOAD_SIG_SETUP_INVALID;
-	}
-
-	/* Copy files to temporary directory for verification / boot */
-	result = copy_file_secure_dest(boot_task,
-		boot_task->local_image,
-		&kernel_filename);
-	if (result) {
-		pb_log("%s: image copy failed: (%d)\n",
-			__func__, result);
-		return result;
-	}
-	if (boot_task->local_initrd) {
-		result = copy_file_secure_dest(boot_task,
-			boot_task->local_initrd,
-			&initrd_filename);
-		if (result) {
-			pb_log("%s: initrd copy failed: (%d)\n",
-				__func__, result);
-			return result;
-		}
-	}
-	if (boot_task->local_dtb) {
-		result = copy_file_secure_dest(boot_task,
-			boot_task->local_dtb,
-			&dtb_filename);
-		if (result) {
-			pb_log("%s: dtb copy failed: (%d)\n",
-				__func__, result);
-			return result;
-		}
-	}
-	boot_task->local_image_override = talloc_strdup(boot_task,
-		kernel_filename);
-	if (boot_task->local_initrd)
-		boot_task->local_initrd_override = talloc_strdup(boot_task,
-			initrd_filename);
-	if (boot_task->local_dtb)
-		boot_task->local_dtb_override = talloc_strdup(boot_task,
-			dtb_filename);
-
-	/* Write command line to temporary file for verification */
-	if (cmdline_fd < 0) {
-		/* mkstemp failed */
-		pb_log("%s: failed: unable to create command line"
-			" temporary file for verification\n",
-			__func__);
-		result = -1;
-	}
-	else {
-		cmdline_handle = fdopen(cmdline_fd, "w");
-	}
-	if (!cmdline_handle) {
-		/* Failed to open file */
-		pb_log("%s: failed: unable to write command line"
-			" temporary file for verification\n",
-			__func__);
-		result = -1;
-	}
-	else {
-		fwrite(boot_task->args, sizeof(char),
-			strlen(boot_task->args), cmdline_handle);
-		fflush(cmdline_handle);
-	}
-
-	if (boot_task->verify_signature) {
-		/* Check signatures */
-		if (verify_file_signature(kernel_filename,
-			local_image_signature,
-			authorized_signatures_handle,
-			"/etc/gpg"))
-			result = KEXEC_LOAD_SIGNATURE_FAILURE;
-		if (verify_file_signature(cmdline_template,
-			local_cmdline_signature,
-			authorized_signatures_handle,
-			"/etc/gpg"))
-			result = KEXEC_LOAD_SIGNATURE_FAILURE;
-
-		if (boot_task->local_initrd_signature)
-			if (verify_file_signature(initrd_filename,
-				local_initrd_signature,
-				authorized_signatures_handle,
-				"/etc/gpg"))
-				result = KEXEC_LOAD_SIGNATURE_FAILURE;
-		if (boot_task->local_dtb_signature)
-			if (verify_file_signature(dtb_filename,
-				local_dtb_signature,
-				authorized_signatures_handle,
-				"/etc/gpg"))
-				result = KEXEC_LOAD_SIGNATURE_FAILURE;
-
-		/* Clean up */
-		if (cmdline_handle) {
-			fclose(cmdline_handle);
-			unlink(cmdline_template);
-		}
-		fclose(authorized_signatures_handle);
-	} else if (boot_task->decrypt_files) {
-		/* Decrypt files */
-		if (decrypt_file(kernel_filename,
-			authorized_signatures_handle,
-			"/etc/gpg"))
-			result = KEXEC_LOAD_DECRYPTION_FALURE;
-		if (verify_file_signature(cmdline_template,
-			local_cmdline_signature,
-			authorized_signatures_handle,
-			"/etc/gpg"))
-			result = KEXEC_LOAD_SIGNATURE_FAILURE;
-		if (boot_task->local_initrd)
-			if (decrypt_file(initrd_filename,
-				authorized_signatures_handle,
-				"/etc/gpg"))
-				result = KEXEC_LOAD_DECRYPTION_FALURE;
-		if (boot_task->local_dtb)
-			if (decrypt_file(dtb_filename,
-				authorized_signatures_handle,
-				"/etc/gpg"))
-				result = KEXEC_LOAD_DECRYPTION_FALURE;
-
-		/* Clean up */
-		if (cmdline_handle) {
-			fclose(cmdline_handle);
-			unlink(cmdline_template);
-		}
-		fclose(authorized_signatures_handle);
-	}
-
-	return result;
-}
-
-void gpg_validate_boot_files_cleanup(struct boot_task *boot_task) {
-	if ((boot_task->verify_signature) || (boot_task->decrypt_files)) {
-		unlink(boot_task->local_image_override);
-		if (boot_task->local_initrd_override)
-			unlink(boot_task->local_initrd_override);
-		if (boot_task->local_dtb_override)
-			unlink(boot_task->local_dtb_override);
-
-		talloc_free(boot_task->local_image_override);
-		if (boot_task->local_initrd_override)
-			talloc_free(boot_task->local_initrd_override);
-		if (boot_task->local_dtb_override)
-			talloc_free(boot_task->local_dtb_override);
-	}
-}
-
 int lockdown_status() {
 	/* assume most restrictive lockdown type */
 	int ret = PB_LOCKDOWN_SIGN;
@@ -559,8 +372,8 @@ int lockdown_status() {
 		authorized_signatures_handle)) != -1) {
 		auth_sig_len = strlen(auth_sig_line);
 		while ((auth_sig_line[auth_sig_len-1] == '\n')
-			|| (auth_sig_line[auth_sig_len-1] == '\r'))
-		auth_sig_len--;
+		    || (auth_sig_line[auth_sig_len-1] == '\r'))
+			auth_sig_len--;
 		auth_sig_line[auth_sig_len] = 0;
 		if (strcmp(auth_sig_line, "ENCRYPTED") == 0) {
 			/* first line indicates encrypted files
@@ -571,5 +384,6 @@ int lockdown_status() {
 	}
 	free(auth_sig_line);
 
-	return ret;
+    return ret;
 }
+
diff --git a/lib/security/gpg.h b/lib/security/gpg.h
deleted file mode 100644
index 6efc3d2..0000000
--- a/lib/security/gpg.h
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- *  Copyright (C) 2016 Raptor Engineering, LLC
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; version 2 of the License.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-#ifndef _PB_GPG_H
-#define _PB_GPG_H
-
-#include <discover/boot.h>
-
-enum {
-	PB_LOCKDOWN_NONE	= 0,
-	PB_LOCKDOWN_SIGN	= 1,
-	PB_LOCKDOWN_DECRYPT	= 2,
-};
-
-#if defined(HAVE_LIBGPGME)
-#include <gpgme.h>
-#endif /* HAVE_LIBGPGME */
-
-int lockdown_status(void);
-
-struct pb_url * gpg_get_signature_url(void *ctx, struct pb_url *base_file);
-
-int verify_file_signature(const char *plaintext_filename,
-	const char *signature_filename, FILE *authorized_signatures_handle,
-	const char *keyring_path);
-
-int decrypt_file(const char * filename,
-	FILE * authorized_signatures_handle, const char * keyring_path);
-
-int gpg_validate_boot_files(struct boot_task *boot_task);
-
-void gpg_validate_boot_files_cleanup(struct boot_task *boot_task);
-
-#if !defined(HAVE_LIBGPGME)
-
-int lockdown_status(void) { return PB_LOCKDOWN_NONE; }
-
-struct pb_url * gpg_get_signature_url(void *ctx __attribute__((unused)),
-			struct pb_url *base_file __attribute__((unused)))
-{
-	return NULL;
-}
-
-int verify_file_signature(const char *plaintext_filename __attribute__((unused)),
-	const char *signature_filename __attribute__((unused)),
-	FILE *authorized_signatures_handle __attribute__((unused)),
-	const char *keyring_path __attribute__((unused)))
-{
-	return -1;
-}
-
-int decrypt_file(const char * filename __attribute__((unused)),
-	FILE * authorized_signatures_handle __attribute__((unused)),
-	const char * keyring_path __attribute__((unused)))
-{
-	return -1;
-}
-
-int gpg_validate_boot_files(struct boot_task *boot_task __attribute__((unused)))
-{
-	return 0;
-}
-
-void gpg_validate_boot_files_cleanup(struct boot_task *boot_task __attribute__((unused)))
-{}
-
-#endif /* HAVE_LIBGPGME */
-
-#endif /* _PB_GPG_H */
\ No newline at end of file
diff --git a/lib/security/none.c b/lib/security/none.c
new file mode 100644
index 0000000..8ef54e1
--- /dev/null
+++ b/lib/security/none.c
@@ -0,0 +1,61 @@
+/*
+ *  Copyright (C) 2016 Raptor Engineering, LLC
+ *  Copyright (C) 2018 Opengear, Inc
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#if defined(HAVE_CONFIG_H)
+#include "config.h"
+#endif
+
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <url/url.h>
+
+#include "security.h"
+
+int lockdown_status(void) { return PB_LOCKDOWN_NONE; }
+
+struct pb_url * get_signature_url(void *ctx __attribute__((unused)),
+            struct pb_url *base_file __attribute__((unused)))
+{
+	return NULL;
+}
+
+int verify_file_signature(const char *plaintext_filename __attribute__((unused)),
+    const char *signature_filename __attribute__((unused)),
+    FILE *authorized_signatures_handle __attribute__((unused)),
+    const char *keyring_path __attribute__((unused)))
+{
+	return -1;
+}
+
+int decrypt_file(const char * filename __attribute__((unused)),
+    FILE * authorized_signatures_handle __attribute__((unused)),
+    const char * keyring_path __attribute__((unused)))
+{
+	return -1;
+}
+
+int validate_boot_files(struct boot_task *boot_task __attribute__((unused)))
+{
+	return 0;
+}
+
+void validate_boot_files_cleanup(struct boot_task *boot_task __attribute__((unused)))
+{}
+
diff --git a/lib/security/openssl.c b/lib/security/openssl.c
new file mode 100644
index 0000000..03ea332
--- /dev/null
+++ b/lib/security/openssl.c
@@ -0,0 +1,476 @@
+/*
+ *  Copyright (C) 2018 Opengear
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#if defined(HAVE_CONFIG_H)
+#include "config.h"
+#endif
+
+#include <stdbool.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <dirent.h>
+#include <string.h>
+#include <fcntl.h>
+#include <locale.h>
+#include <sys/types.h>
+
+#include <log/log.h>
+#include <file/file.h>
+#include <talloc/talloc.h>
+#include <url/url.h>
+#include <util/util.h>
+#include <i18n/i18n.h>
+
+#include <openssl/conf.h>
+#include <openssl/bio.h>
+#include <openssl/pem.h>
+#include <openssl/rsa.h>
+#include <openssl/evp.h>
+#include <openssl/err.h>
+#include <openssl/cms.h>
+#include <openssl/pkcs12.h>
+
+#include "security.h"
+
+static const EVP_MD *s_verify_md = NULL;
+
+static	__attribute__((constructor)) void crypto_init(void)
+{
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
+	OPENSSL_no_config();
+	OpenSSL_add_all_algorithms();
+	ERR_load_crypto_strings();
+	ERR_load_CMS_strings();
+#endif
+
+	s_verify_md = EVP_get_digestbyname(VERIFY_DIGEST);
+	if (!s_verify_md)
+		pb_log("Specified OpenSSL digest '%s' not found\n", VERIFY_DIGEST);
+
+}
+
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
+static __attribute__((destructor)) void crypto_fini(void)
+{
+	EVP_cleanup();
+	ERR_free_strings();
+}
+#endif
+
+static int pb_log_print_errors_cb(const char *str,
+				  size_t len __attribute__((unused)),
+				  void *u __attribute__((unused)))
+{
+	pb_log("    %s\n", str);
+	return 0;
+}
+
+static int get_pkcs12(FILE *keyfile, X509 **cert, EVP_PKEY **priv)
+{
+	PKCS12 *p12 = NULL;
+	int ok = 0;
+
+	rewind(keyfile);
+
+	p12 = d2i_PKCS12_fp(keyfile, NULL);
+	if (p12) {
+		/*
+		 * annoying but NULL and "" are two valid but different
+		 * default passwords
+		 */
+		if (!PKCS12_parse(p12, NULL, priv, cert, NULL) &&
+		    !PKCS12_parse(p12,   "", priv, cert, NULL)) {
+			pb_log("%s: Error parsing OpenSSL PKCS12:\n", __func__);
+			ERR_print_errors_cb(&pb_log_print_errors_cb, NULL);
+		} else
+			ok = 1;
+
+		PKCS12_free(p12);
+	}
+
+	return ok;
+}
+
+static X509 *get_cert(FILE *keyfile)
+{
+	EVP_PKEY *priv = NULL;
+	X509 *cert = NULL;
+
+	if (get_pkcs12(keyfile, &cert, &priv)) {
+		EVP_PKEY_free(priv);
+	} else {
+		rewind(keyfile);
+		ERR_clear_error();
+		cert = PEM_read_X509(keyfile, NULL, NULL, NULL);
+	}
+
+	return cert;
+}
+
+static STACK_OF(X509) *get_cert_stack(FILE *keyfile)
+{
+	STACK_OF(X509) *certs = sk_X509_new_null();
+	X509 *cert = NULL;
+
+	if (certs) {
+		cert = get_cert(keyfile);
+		if (cert)
+			sk_X509_push(certs, get_cert(keyfile));
+	} else {
+		pb_log("%s: Error allocating OpenSSL X509 stack:\n", __func__);
+		ERR_print_errors_cb(&pb_log_print_errors_cb, NULL);
+	}
+
+	return certs;
+}
+
+
+static EVP_PKEY *get_public_key(FILE *keyfile)
+{
+	EVP_PKEY *pkey = NULL;
+	X509 *cert = NULL;
+
+	/*
+	 * walk through supported file types looking for a public key:
+	 *
+	 * 1. PKCS12
+	 * 2. PEM encoded X509
+	 * 3. PEM encoded raw public key
+	 *
+	 * someday in the future maybe utilize the keyring_path
+	 * as an input for X509_STORE_load_locations for certificate
+	 * validity checking
+	 */
+
+	cert = get_cert(keyfile);
+	if (cert) {
+		pkey = X509_get_pubkey(cert);
+		X509_free(cert);
+	} else {
+		rewind(keyfile);
+		ERR_clear_error();
+		pkey = PEM_read_PUBKEY(keyfile, NULL, NULL, NULL);
+	}
+
+	/* handles both cases */
+	if (!pkey) {
+		pb_log("%s: Error loading OpenSSL public key:\n", __func__);
+		ERR_print_errors_cb(&pb_log_print_errors_cb, NULL);
+	}
+
+	return pkey;
+}
+
+int decrypt_file(const char *filename,
+		 FILE *authorized_signatures_handle,
+		 const char *keyring_path __attribute__((unused)))
+{
+	BIO *content_bio = NULL, *file_bio = NULL, *out_bio = NULL;
+	STACK_OF(X509) *certs = NULL;
+	CMS_ContentInfo *cms = NULL;
+	EVP_PKEY *priv = NULL;
+	X509 *cert = NULL;
+	int nok = -1;
+	char *outptr;
+	long outl;
+	int bytes;
+
+	if (!get_pkcs12(authorized_signatures_handle, &cert, &priv)) {
+		pb_log("%s: Error opening OpenSSL decrypt authorization file:\n",
+		       __func__);
+		ERR_print_errors_cb(&pb_log_print_errors_cb, NULL);
+		goto out;
+	}
+
+	file_bio = BIO_new_file(filename, "r");
+	if (!file_bio) {
+		pb_log("%s: Error opening OpenSSL decrypt cipher file '%s':\n",
+		       __func__, filename);
+		ERR_print_errors_cb(&pb_log_print_errors_cb, NULL);
+		goto out;
+	}
+
+	out_bio = BIO_new(BIO_s_mem());
+	if (!out_bio) {
+		pb_log("%s: Error allocating OpenSSL decrypt output buffer:\n",
+		       __func__);
+		ERR_print_errors_cb(&pb_log_print_errors_cb, NULL);
+		goto out;
+	}
+
+	/* right now only support signed-envelope CMS */
+
+	cms = SMIME_read_CMS(file_bio, &content_bio);
+	if (!cms) {
+		pb_log("%s: Error parsing OpenSSL CMS decrypt '%s'\n",
+		       __func__, filename);
+		ERR_print_errors_cb(&pb_log_print_errors_cb, NULL);
+		goto out;
+	}
+
+	BIO_free(content_bio);
+	content_bio = BIO_new(BIO_s_mem());
+	if (!content_bio) {
+		pb_log("%s: Error allocating OpenSSL decrypt content buffer:\n",
+		       __func__);
+		ERR_print_errors_cb(&pb_log_print_errors_cb, NULL);
+		goto out;
+	}
+
+	if (!CMS_decrypt(cms, priv, cert, NULL, out_bio, 0)) {
+		pb_log("%s: Error in OpenSSL CMS decrypt '%s'\n",
+		       __func__, filename);
+		ERR_print_errors_cb(&pb_log_print_errors_cb, NULL);
+		goto out;
+	}
+
+	certs = sk_X509_new_null();
+	if (!certs) {
+		pb_log("%s: Error allocating OpenSSL X509 stack:\n", __func__);
+		ERR_print_errors_cb(&pb_log_print_errors_cb, NULL);
+		goto out;
+	}
+
+	sk_X509_push(certs, cert);
+
+	CMS_ContentInfo_free(cms);
+
+	cms = SMIME_read_CMS(out_bio, &content_bio);
+	if (!cms) {
+		pb_log("%s: Error parsing OpenSSL CMS decrypt verify:\n",
+		       __func__);
+		ERR_print_errors_cb(&pb_log_print_errors_cb, NULL);
+		goto out;
+	}
+
+	/* this is a mem BIO so failure is 0 or -1 */
+	if (BIO_reset(out_bio) < 1) {
+		pb_log("%s: Error resetting OpenSSL decrypt output buffer:\n",
+		       __func__);
+		ERR_print_errors_cb(&pb_log_print_errors_cb, NULL);
+		goto out;
+	}
+
+	/* in this mode its attached content */
+	if (!CMS_verify(cms, certs, NULL, content_bio, out_bio,
+			CMS_NO_SIGNER_CERT_VERIFY | CMS_BINARY)) {
+		pb_log("%s: Failed OpenSSL CMS decrypt verify:\n", __func__);
+		ERR_print_errors_cb(&pb_log_print_errors_cb, NULL);
+		goto out;
+	}
+
+	/* reopen the file so we force a truncation */
+	BIO_free(file_bio);
+	file_bio = BIO_new_file(filename, "w");
+	if (!file_bio) {
+		pb_log("%s: Error opening OpenSSL decrypt output file '%s'\n",
+		       __func__, filename);
+		ERR_print_errors_cb(&pb_log_print_errors_cb, NULL);
+		goto out;
+	}
+
+	outl = BIO_get_mem_data(out_bio, &outptr);
+
+	while (outl) {
+		bytes = BIO_write(file_bio, outptr, outl);
+		if (bytes > 0) {
+			outl -= (long)bytes;
+			outptr += bytes;
+
+		} else if (bytes < 0) {
+			pb_log("%s: OpenSSL decrypt output write failure on file '%s':\n",
+				       __func__, filename);
+			ERR_print_errors_cb(&pb_log_print_errors_cb, NULL);
+			goto out;
+		}
+	}
+
+	if (!outl)
+		nok = 0;
+
+out:
+	if (cms)
+		CMS_ContentInfo_free(cms);
+	BIO_free(file_bio);
+	BIO_free(content_bio);
+	BIO_free(out_bio);
+	X509_free(cert);
+	sk_X509_free(certs);
+	EVP_PKEY_free(priv);
+	return nok;
+}
+
+int verify_file_signature(const char *plaintext_filename,
+			  const char *signature_filename,
+			  FILE *authorized_signatures_handle,
+			  const char *keyring_path __attribute__((unused)))
+{
+	BIO *signature_bio = NULL, *plaintext_bio = NULL, *content_bio = NULL;
+	STACK_OF(X509) *certs = NULL;
+	CMS_ContentInfo *cms = NULL;
+	ssize_t bytes_read = -1;
+	EVP_MD_CTX *ctx = NULL;
+	EVP_PKEY *pkey = NULL;
+	char *sigbuf = NULL;
+	char rdbuf[8192];
+	int nok = -1;
+	int siglen;
+
+	plaintext_bio = BIO_new_file(plaintext_filename, "r");
+	if (!plaintext_bio) {
+		pb_log("%s: Error opening OpenSSL verify plaintext file '%s'\n",
+		       __func__, plaintext_filename);
+		ERR_print_errors_cb(&pb_log_print_errors_cb, NULL);
+		goto out;
+	}
+
+	signature_bio = BIO_new_file(signature_filename, "r");
+	if (!signature_bio) {
+		pb_log("%s: Error opening OpenSSL verify signature file '%s'\n",
+		       __func__, signature_filename);
+		ERR_print_errors_cb(&pb_log_print_errors_cb, NULL);
+		goto out;
+	}
+
+	/* first check CMS */
+	cms = SMIME_read_CMS(signature_bio, &content_bio);
+	if (cms) {
+		certs = get_cert_stack(authorized_signatures_handle);
+
+		/*
+		 * this has to always be detached, which means we always
+		 * ignore content_bio and we have to set the NO_SIGNER_CERT_VERIFY
+		 * until such time we implement the keyring_path as a X509_STORE
+		 */
+
+		if (!CMS_verify(cms, certs, NULL, plaintext_bio, NULL,
+				CMS_DETACHED | CMS_NO_SIGNER_CERT_VERIFY | CMS_BINARY)) {
+			pb_log("%s: Failed OpenSSL CMS verify:\n", __func__);
+			ERR_print_errors_cb(&pb_log_print_errors_cb, NULL);
+			goto out;
+		}
+
+		nok = 0;
+
+	} else {
+
+		/* for explicit dgst mode we need an explicit md defined */
+		if (!s_verify_md)
+			goto out;
+
+		ctx = EVP_MD_CTX_create();
+
+		if (!ctx) {
+			pb_log("%s: Error allocating OpenSSL MD ctx:\n", __func__);
+			ERR_print_errors_cb(&pb_log_print_errors_cb, NULL);
+			goto out;
+		}
+
+		pkey = get_public_key(authorized_signatures_handle);
+		if (!pkey)
+			goto out;
+
+		if (EVP_DigestVerifyInit(ctx, NULL, s_verify_md, NULL, pkey) < 1) {
+			pb_log("%s: Error initializing OpenSSL verify:\n", __func__);
+			ERR_print_errors_cb(&pb_log_print_errors_cb, NULL);
+			goto out;
+		}
+
+		while (bytes_read) {
+			bytes_read = BIO_read(plaintext_bio, rdbuf, 8192);
+			if (bytes_read > 0) {
+				if (EVP_DigestVerifyUpdate(ctx, rdbuf, (size_t)(bytes_read)) < 1) {
+					pb_log("%s: OpenSSL digest update failure on file '%s':\n",
+					       __func__, plaintext_filename);
+					ERR_print_errors_cb(&pb_log_print_errors_cb, NULL);
+					goto out;
+				}
+			} else if (bytes_read < 0) {
+				pb_log("%s: OpenSSL read failure on file '%s':\n",
+				       __func__, plaintext_filename);
+				ERR_print_errors_cb(&pb_log_print_errors_cb, NULL);
+				goto out;
+			}
+		}
+
+		/*
+		 * can't do signature buffer as an update so have to read in whole file
+		 * would be handy if there was some sort of BIO_read_all but there
+		 * doesn't seem to be so rather than reinvent the wheel close it and
+		 * use the existing support
+		 */
+		BIO_free(signature_bio);
+		signature_bio = NULL;
+
+		if (read_file(NULL, signature_filename, &sigbuf, &siglen)) {
+			pb_log("%s: Error reading OpenSSL signature file '%s'\n",
+			       __func__, signature_filename);
+			goto out;
+		}
+
+		if (EVP_DigestVerifyFinal(ctx, (unsigned char*)sigbuf, siglen))
+			nok = 0;
+		else {
+			pb_log("%s: Error finalizing OpenSSL verify:\n", __func__);
+			ERR_print_errors_cb(&pb_log_print_errors_cb, NULL);
+		}
+	}
+
+out:
+	if (cms)
+		CMS_ContentInfo_free(cms);
+	talloc_free(sigbuf);
+	sk_X509_free(certs);
+	BIO_free(plaintext_bio);
+	BIO_free(signature_bio);
+	BIO_free(content_bio);
+	EVP_PKEY_free(pkey);
+	EVP_MD_CTX_destroy(ctx);
+	return nok;
+}
+
+int lockdown_status(void)
+{
+	/*
+	 * if it's a PKCS12 then we're in decrypt mode since we have the
+	 * private key, otherwise it's sign mode
+	 *
+	 * someday add in support for runtime determination based on what
+	 * files come back in the async sig file load?
+	 */
+	FILE *authorized_signatures_handle = NULL;
+	int ret = PB_LOCKDOWN_SIGN;
+	PKCS12 *p12 = NULL;
+
+	if (access(LOCKDOWN_FILE, F_OK) == -1)
+		return PB_LOCKDOWN_NONE;
+
+	/* determine lockdown type */
+
+	authorized_signatures_handle = fopen(LOCKDOWN_FILE, "r");
+	if (authorized_signatures_handle) {
+		p12 = d2i_PKCS12_fp(authorized_signatures_handle, NULL);
+		if (p12) {
+			ret = PB_LOCKDOWN_DECRYPT;
+			PKCS12_free(p12);
+		}
+		fclose(authorized_signatures_handle);
+	}
+
+    return ret;
+}
+
diff --git a/lib/security/security.h b/lib/security/security.h
new file mode 100644
index 0000000..9b1ae57
--- /dev/null
+++ b/lib/security/security.h
@@ -0,0 +1,46 @@
+/*
+ *  Copyright (C) 2016 Raptor Engineering, LLC
+ *  Copyright (C) 2018 Opengear, Inc
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#ifndef _PB_SECURITY_H
+#define _PB_SECURITY_H
+
+#include <discover/boot.h>
+
+enum {
+	PB_LOCKDOWN_NONE	= 0,
+	PB_LOCKDOWN_SIGN	= 1,
+	PB_LOCKDOWN_DECRYPT	= 2
+};
+
+
+int lockdown_status(void);
+
+struct pb_url * get_signature_url(void *ctx, struct pb_url *base_file);
+
+int verify_file_signature(const char *plaintext_filename,
+	const char *signature_filename, FILE *authorized_signatures_handle,
+	const char *keyring_path);
+
+int decrypt_file(const char *filename,
+	FILE * authorized_signatures_handle, const char * keyring_path);
+
+int validate_boot_files(struct boot_task *boot_task);
+
+void validate_boot_files_cleanup(struct boot_task *boot_task);
+
+#endif // _PB_SECURITY_H
+
