diff --git a/.travis.yml b/.travis.yml
index 89f4fd7..3566d51 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -29,6 +29,7 @@ before_install:
     - sudo apt-get install -y autoconf-archive
     - sudo apt-get install -y linux-headers-$(uname -r)
     - sudo apt-get install -y libmbedtls-dev
+    - sudo apt-get install -y libcmocka-dev
 
 script:
     - sudo ln -sf /usr/lib/x86_64-linux-gnu/pkgconfig/lua5.2.pc /usr/lib/x86_64-linux-gnu/pkgconfig/lua.pc
@@ -75,4 +76,5 @@ script:
     - make
     - sudo make install
     - cd ..
-    - for i in configs/*;do echo $i;make `basename $i` && make || exit 1;done
+    - sudo ldconfig
+    - for i in configs/*;do echo $i;make `basename $i` && make || exit 1;make test || exit 1;done
diff --git a/Makefile b/Makefile
index 8060ff9..d60c58e 100644
--- a/Makefile
+++ b/Makefile
@@ -476,9 +476,9 @@ PHONY += suricatta-tests
 suricatta-tests: FORCE
 	$(Q)$(MAKE) $(build)=suricatta/test SWOBJS="$(swupdate-objs)" SWLIBS="$(swupdate-libs)" LDLIBS="$(LDLIBS)" tests
 
-PHONY += corelib-tests
-corelib-tests: FORCE
-	$(Q)$(MAKE) $(build)=corelib/test SWOBJS="$(swupdate-objs)" SWLIBS="$(swupdate-libs)" LDLIBS="$(LDLIBS)" tests
+PHONY += test
+test:
+	$(Q)$(MAKE) $(build)=test SWOBJS="$(swupdate-objs)" SWLIBS="$(swupdate-libs)" LDLIBS="$(LDLIBS)" tests
 
 # The actual objects are generated when descending,
 # make sure no implicit rule kicks in
diff --git a/corelib/test/Makefile b/test/Makefile
similarity index 70%
rename from corelib/test/Makefile
rename to test/Makefile
index b071177..81f8cf7 100644
--- a/corelib/test/Makefile
+++ b/test/Makefile
@@ -16,6 +16,10 @@
 ## Foundation, Inc.
 
 tests-$(CONFIG_ENCRYPTED_IMAGES) += test_crypt
+tests-$(CONFIG_HASH_VERIFY) += test_hash
+ifeq ($(CONFIG_SIGALG_RAWRSA),y)
+tests-$(CONFIG_SIGNED_IMAGES) += test_verify
+endif
 
 ccflags-y += -I$(src)/../
 
@@ -45,7 +49,7 @@ EXECUTE_TEST = echo "RUN $(subst $(obj)/,,$(var))"; CMOCKA_MESSAGE_OUTPUT=TAP $(
 
 PHONY += default
 default:
-	$(info please run 'make corelib-tests' in swupdate main directory)
+	$(info please run 'make test' in swupdate main directory)
 
 PHONY += tests
 ifneq "$(tests-y)" ""
@@ -57,8 +61,27 @@ tests:
 	@:
 endif
 
-$(obj)/%.lnk: $(objtree)/core/built-in.o
+$(obj)/%.lnk: $(obj)/%.o $(objtree)/core/built-in.o
 	$(Q)strip -N main -o $(objtree)/core/built-in.o.tmp $(objtree)/core/built-in.o
 	$(Q)$(call cmd,linktestexe)
 
+DATADIR := test/data
+
+$(obj)/test_verify.o: $(DATADIR)/signature $(DATADIR)/signing-pubkey.pem
+
+.INTERMEDIATE: $(DATADIR)/signature
+$(DATADIR)/signature: $(DATADIR)/to-be-signed $(DATADIR)/signing-secret.pem
+	$(if $(Q),@echo "  SIGN    $@")
+	$(Q)openssl dgst -sha256 -sign $(DATADIR)/signing-secret.pem $(DATADIR)/to-be-signed > $@
+
+.INTERMEDIATE: $(DATADIR)/signing-pubkey.pem
+$(DATADIR)/signing-pubkey.pem: $(DATADIR)/signing-secret.pem
+	$(if $(Q),@echo "  EXPORT  $@")
+	$(Q)openssl rsa -in $< -out $@ -outform PEM -pubout 2>/dev/null
+
+.INTERMEDIATE: $(DATADIR)/signing-secret.pem
+$(DATADIR)/signing-secret.pem:
+	$(if $(Q),@echo "  GEN     $@")
+	$(Q)openssl genrsa -out $@ 2>/dev/null
+
 .PHONY: $(PHONY)
diff --git a/test/data/to-be-signed b/test/data/to-be-signed
new file mode 100644
index 0000000..8baef1b
--- /dev/null
+++ b/test/data/to-be-signed
@@ -0,0 +1 @@
+abc
diff --git a/corelib/test/test_crypt.c b/test/test_crypt.c
similarity index 100%
rename from corelib/test/test_crypt.c
rename to test/test_crypt.c
diff --git a/test/test_hash.c b/test/test_hash.c
new file mode 100644
index 0000000..06475fd
--- /dev/null
+++ b/test/test_hash.c
@@ -0,0 +1,124 @@
+/*
+ * 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; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * 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.
+ */
+
+#include <stddef.h>
+#include <setjmp.h>
+#include <stdarg.h>
+#include <cmocka.h>
+#include <string.h>
+
+#include "sslapi.h"
+#include "util.h"
+
+struct testvector {
+	const char *input;
+	const char *sha1;
+	const char *sha256;
+};
+
+// https://www.di-mgt.com.au/sha_testvectors.html
+static const struct testvector testvectors[] = {
+	{
+		.input = "abc",
+		.sha1 = "a9993e364706816aba3e25717850c26c9cd0d89d",
+		.sha256 = "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad",
+	},
+	{
+		.input = "",
+		.sha1 = "da39a3ee5e6b4b0d3255bfef95601890afd80709",
+		.sha256 = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
+	},
+	{
+		.input = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
+		.sha1 = "84983e441c3bd26ebaae4aa1f95129e5e54670f1",
+		.sha256 = "248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1",
+	},
+	{
+		.input = "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu",
+		.sha1 = "a49b2446a02c645bf419f995b67091253a04a259",
+		.sha256 = "cf5b16a778af8380036ce59e7b0492370b249b11e8f07a51afac45037afee9d1",
+	},
+};
+
+static void hex2bin(unsigned char *dest, const unsigned char *source)
+{
+	unsigned int val;
+	for (unsigned int i = 0; i < strlen((const char *)source); i += 2) {
+		val = from_ascii((const char *)&source[i], 2, LG_16);
+		dest[i / 2] = val;
+	}
+}
+
+static void do_concrete_hash(const char* algo, const char* input, const char* expected_hex)
+{
+	int error;
+	uint8_t result[32] = {0};
+	unsigned len = 0;
+	uint8_t expected_bin[32] = {0};
+	struct swupdate_digest *dgst;
+
+	dgst = swupdate_HASH_init(algo);
+	assert_non_null(dgst);
+	error = swupdate_HASH_update(dgst, (uint8_t *)input, strlen(input));
+	assert_true(!error);
+
+	error = swupdate_HASH_final(dgst, result, &len);
+	assert_int_equal(error, 1);
+	assert_int_equal(len, strlen(expected_hex) / 2);
+
+	swupdate_HASH_cleanup(dgst);
+
+	hex2bin(expected_bin, (uint8_t *)expected_hex);
+	error = swupdate_HASH_compare(expected_bin, result);
+	assert_true(!error);
+}
+
+static void do_hash(const struct testvector *vector)
+{
+	do_concrete_hash("sha1", vector->input, vector->sha1);
+	do_concrete_hash("sha256", vector->input, vector->sha256);
+}
+
+static void test_hash_vectors(void **state)
+{
+	unsigned i;
+
+	(void)state;
+
+	for (i = 0; i < sizeof(testvectors) / sizeof(testvectors[0]); ++i) {
+		do_hash(testvectors + i);
+	}
+}
+
+static void test_hash_compare(void **state)
+{
+	(void)state;
+
+	static const uint8_t a[32] = {0};
+	static const uint8_t b[32] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1};
+
+	assert_int_equal(swupdate_HASH_compare(a, a), 0);
+	assert_int_equal(swupdate_HASH_compare(a, b), -1);
+}
+
+int main(void)
+{
+	static const struct CMUnitTest hash_tests[] = {
+		cmocka_unit_test(test_hash_compare),
+		cmocka_unit_test(test_hash_vectors),
+	};
+	return cmocka_run_group_tests_name("hash", hash_tests, NULL, NULL);
+}
diff --git a/test/test_verify.c b/test/test_verify.c
new file mode 100644
index 0000000..4bc3bd1
--- /dev/null
+++ b/test/test_verify.c
@@ -0,0 +1,57 @@
+/*
+ * 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; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * 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.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <cmocka.h>
+
+#include "sslapi.h"
+#include "util.h"
+
+#define DATADIR "test/data/"
+
+static void test_verify_pkcs15(void **state)
+{
+	int error;
+	struct swupdate_cfg config;
+
+	(void)state;
+
+	config.dgst = NULL;
+	error = swupdate_dgst_init(&config, DATADIR "signing-pubkey.pem");
+	assert_int_equal(error, 0);
+
+	error = swupdate_verify_file(config.dgst, DATADIR "signature",
+		DATADIR "to-be-signed", NULL);
+	assert_int_equal(error, 0);
+}
+
+int main(void)
+{
+	swupdate_crypto_init();
+	static const struct CMUnitTest verify_tests[] = {
+		cmocka_unit_test(test_verify_pkcs15),
+	};
+	return cmocka_run_group_tests_name("verify", verify_tests, NULL, NULL);
+}
