unit: Add PBKDF2 tests from iwd

Test l_pkcs5_pbkdf2 using test data from iwd with the exception of the
test case that contained a \0 inside the password string.  ell
implementation treat the password as a C string so it can't have a \0 in
the middle, while the iwd version would take a length parameter.  We don't
have a use case for non-C-string passwords but RFC8018 doesn't exactly
prohibit them or define what is considered a password.

"Throughout this document, a password is considered to be an octet
string of arbitrary length whose interpretation as a text string is
unspecified.  In the interest of interoperability, however, it is
recommended that applications follow some common text encoding rules.
ASCII and UTF-8 [RFC3629] are two possibilities.  (ASCII is a subset
of UTF-8.)

Although the selection of passwords is outside the scope of this
document, guidelines have been published [NISTSP63] that may well be
taken into account."
diff --git a/.gitignore b/.gitignore
index 8d7c374..369bbe9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -53,6 +53,7 @@
 unit/test-pem
 unit/test-uuid
 unit/test-key
+unit/test-pbkdf2
 unit/cert-*.pem
 unit/cert-*.csr
 unit/cert-*.srl
diff --git a/Makefile.am b/Makefile.am
index 98c06ca..9b4ca06 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -133,7 +133,8 @@
 			unit/test-util \
 			unit/test-uintset \
 			unit/test-base64 \
-			unit/test-uuid
+			unit/test-uuid \
+			unit/test-pbkdf2
 
 dbus_tests = unit/test-hwdb \
 			unit/test-dbus \
@@ -234,6 +235,8 @@
 
 unit_test_base64_LDADD = ell/libell-private.la
 
+unit_test_pbkdf2_LDADD = ell/libell-private.la
+
 unit_test_pem_LDADD = ell/libell-private.la
 unit_test_pem_DEPENDENCIES = $(cert_files)
 
diff --git a/unit/test-pbkdf2.c b/unit/test-pbkdf2.c
new file mode 100644
index 0000000..c970abe
--- /dev/null
+++ b/unit/test-pbkdf2.c
@@ -0,0 +1,206 @@
+/*
+ *
+ *  Embedded Linux library
+ *
+ *  Copyright (C) 2017  Intel Corporation. All rights reserved.
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library 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
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <ell/ell.h>
+
+struct pbkdf2_data {
+	const char *password;
+	const char *salt;
+	unsigned int salt_len;
+	unsigned int count;
+	unsigned int key_len;
+	const char *key;
+};
+
+static void pbkdf2_test(const void *data)
+{
+	const struct pbkdf2_data *test = data;
+	unsigned int password_len;
+	unsigned int salt_len;
+	unsigned int key_len;
+	unsigned char output[25];
+	char key[50];
+	unsigned int i;
+	bool result;
+
+	password_len = strlen(test->password);
+	salt_len = test->salt_len ? : strlen(test->salt);
+
+	key_len = test->key_len ? : (strlen(test->key) / 2);
+
+	printf("Password = \"%s\" (%d octects)\n",
+					test->password, password_len);
+	printf("Salt     = \"%s\" (%d octects)\n",
+					test->salt, salt_len);
+	printf("Count    = %d\n", test->count);
+	printf("Key      = %s (%d octects)\n", test->key, key_len);
+
+	result = l_pkcs5_pbkdf2(L_CHECKSUM_SHA1, test->password,
+				(const uint8_t *) test->salt, salt_len,
+				test->count, output, key_len);
+
+	assert(result == true);
+
+	for (i = 0; i < key_len; i++)
+		sprintf(key + (i * 2), "%02x", output[i]);
+
+	printf("Result   = %s\n", key);
+
+	assert(strcmp(test->key, key) == 0);
+}
+
+static const struct pbkdf2_data pbkdf2_test_vector_1 = {
+	.password	= "password",
+	.salt		= "salt",
+	.count		= 1,
+	.key		= "0c60c80f961f0e71f3a9b524af6012062fe037a6",
+	.key_len	= 20,
+};
+
+static const struct pbkdf2_data pbkdf2_test_vector_2 = {
+	.password	= "password",
+	.salt		= "salt",
+	.count		= 2,
+	.key		= "ea6c014dc72d6f8ccd1ed92ace1d41f0d8de8957",
+	.key_len	= 20,
+};
+
+static const struct pbkdf2_data pbkdf2_test_vector_3 = {
+	.password	= "password",
+	.salt		= "salt",
+	.count		= 4096,
+	.key		= "4b007901b765489abead49d926f721d065a429c1",
+	.key_len	= 20,
+};
+
+static const struct pbkdf2_data pbkdf2_test_vector_4 = {
+	.password	= "password",
+	.salt		= "salt",
+	.count		= 16777216,
+	.key		= "eefe3d61cd4da4e4e9945b3d6ba2158c2634e984",
+	.key_len	= 20,
+};
+
+static const struct pbkdf2_data pbkdf2_test_vector_5 = {
+	.password	= "passwordPASSWORDpassword",
+	.salt		= "saltSALTsaltSALTsaltSALTsaltSALTsalt",
+	.count		= 4096,
+	.key		= "3d2eec4fe41c849b80c8d83662c0e44a8b291a964cf2f07038",
+	.key_len	= 25,
+};
+
+static const struct pbkdf2_data athena_test_vector_1 = {
+	.password	= "password",
+	.salt		= "ATHENA.MIT.EDUraeburn",
+	.count		= 1,
+	.key		= "cdedb5281bb2f801565a1122b2563515",
+};
+
+static const struct pbkdf2_data athena_test_vector_2 = {
+	.password	= "password",
+	.salt		= "ATHENA.MIT.EDUraeburn",
+	.count		= 2,
+	.key		= "01dbee7f4a9e243e988b62c73cda935d",
+};
+
+static const struct pbkdf2_data athena_test_vector_3 = {
+	.password	= "password",
+	.salt		= "ATHENA.MIT.EDUraeburn",
+	.count		= 1200,
+	.key		= "5c08eb61fdf71e4e4ec3cf6ba1f5512b",
+};
+
+static const struct pbkdf2_data athena_test_vector_4 = {
+	.password	= "password",
+	.salt		= "\x12\x34\x56\x78\x78\x56\x34\x12",
+	.count		= 5,
+	.key		= "d1daa78615f287e6a1c8b120d7062a49",
+};
+
+static const struct pbkdf2_data athena_test_vector_5 = {
+	.password	= "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
+			  "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
+	.salt		= "pass phrase equals block size",
+	.count		= 1200,
+	.key		= "139c30c0966bc32ba55fdbf212530ac9",
+};
+
+static const struct pbkdf2_data athena_test_vector_6 = {
+	.password	= "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
+			  "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
+	.salt		= "pass phrase exceeds block size",
+	.count		= 1200,
+	.key		= "9ccad6d468770cd51b10e6a68721be61",
+};
+
+static const struct pbkdf2_data athena_test_vector_7 = {
+	.password	= "\xf0\x9d\x84\x9e",	/* g-clef (0xf09d849e) */
+	.salt		= "EXAMPLE.COMpianist",
+	.count		= 50,
+	.key		= "6b9cf26d45455a43a5b8bb276a403b39",
+};
+
+int main(int argc, char *argv[])
+{
+	l_test_init(&argc, &argv);
+
+	if (!l_checksum_is_supported(L_CHECKSUM_SHA1, true)) {
+		printf("SHA1 support missing, skipping...\n");
+		goto done;
+	}
+
+	l_test_add("/pbkdf2-sha1/PBKDF2 Test vector 1",
+					pbkdf2_test, &pbkdf2_test_vector_1);
+	l_test_add("/pbkdf2-sha1/PBKDF2 Test vector 2",
+					pbkdf2_test, &pbkdf2_test_vector_2);
+	l_test_add("/pbkdf2-sha1/PBKDF2 Test vector 3",
+					pbkdf2_test, &pbkdf2_test_vector_3);
+	l_test_add("/pbkdf2-sha1/PBKDF2 Test vector 4",
+					pbkdf2_test, &pbkdf2_test_vector_4);
+	l_test_add("/pbkdf2-sha1/PBKDF2 Test vector 5",
+					pbkdf2_test, &pbkdf2_test_vector_5);
+
+	l_test_add("/pbkdf2-sha1/ATHENA Test vector 1",
+					pbkdf2_test, &athena_test_vector_1);
+	l_test_add("/pbkdf2-sha1/ATHENA Test vector 2",
+					pbkdf2_test, &athena_test_vector_2);
+	l_test_add("/pbkdf2-sha1/ATHENA Test vector 3",
+					pbkdf2_test, &athena_test_vector_3);
+	l_test_add("/pbkdf2-sha1/ATHENA Test vector 4",
+					pbkdf2_test, &athena_test_vector_4);
+	l_test_add("/pbkdf2-sha1/ATHENA Test vector 5",
+					pbkdf2_test, &athena_test_vector_5);
+	l_test_add("/pbkdf2-sha1/ATHENA Test vector 6",
+					pbkdf2_test, &athena_test_vector_6);
+	l_test_add("/pbkdf2-sha1/ATHENA Test vector 7",
+					pbkdf2_test, &athena_test_vector_7);
+
+done:
+	return l_test_run();
+}