summaryrefslogtreecommitdiffstats
path: root/comm/third_party/libotr/tests/unit/test_privkey.c
diff options
context:
space:
mode:
Diffstat (limited to 'comm/third_party/libotr/tests/unit/test_privkey.c')
-rw-r--r--comm/third_party/libotr/tests/unit/test_privkey.c264
1 files changed, 264 insertions, 0 deletions
diff --git a/comm/third_party/libotr/tests/unit/test_privkey.c b/comm/third_party/libotr/tests/unit/test_privkey.c
new file mode 100644
index 0000000000..9e2db46189
--- /dev/null
+++ b/comm/third_party/libotr/tests/unit/test_privkey.c
@@ -0,0 +1,264 @@
+/*
+ * Copyright (C) 2014 - Julien Voisin <julien.voisin@dustri.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License, version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * 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., 51
+ * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <gcrypt.h>
+#include <pthread.h>
+#include <unistd.h>
+
+#include <privkey.h>
+#include <proto.h>
+
+#include <tap/tap.h>
+
+GCRY_THREAD_OPTION_PTHREAD_IMPL;
+
+#define NUM_TESTS 13
+
+static OtrlUserState us = NULL;
+static char filename[] = "/tmp/libotr-testing-XXXXXX";
+static FILE* f = NULL;
+
+/*
+ * Create a public key block from a private key
+ */
+static void make_pubkey(unsigned char **pubbufp, size_t *publenp,
+ gcry_sexp_t privkey)
+{
+ gcry_mpi_t p,q,g,y;
+ gcry_sexp_t dsas,ps,qs,gs,ys;
+ size_t np,nq,ng,ny;
+ enum gcry_mpi_format format = GCRYMPI_FMT_USG;
+
+ *pubbufp = NULL;
+ *publenp = 0;
+
+ /* Extract the public parameters */
+ dsas = gcry_sexp_find_token(privkey, "dsa", 0);
+ ps = gcry_sexp_find_token(dsas, "p", 0);
+ qs = gcry_sexp_find_token(dsas, "q", 0);
+ gs = gcry_sexp_find_token(dsas, "g", 0);
+ ys = gcry_sexp_find_token(dsas, "y", 0);
+ gcry_sexp_release(dsas);
+
+ p = gcry_sexp_nth_mpi(ps, 1, GCRYMPI_FMT_USG);
+ gcry_sexp_release(ps);
+ q = gcry_sexp_nth_mpi(qs, 1, GCRYMPI_FMT_USG);
+ gcry_sexp_release(qs);
+ g = gcry_sexp_nth_mpi(gs, 1, GCRYMPI_FMT_USG);
+ gcry_sexp_release(gs);
+ y = gcry_sexp_nth_mpi(ys, 1, GCRYMPI_FMT_USG);
+ gcry_sexp_release(ys);
+
+ *publenp = 0;
+ gcry_mpi_print(format, NULL, 0, &np, p);
+ *publenp += np + 4;
+ gcry_mpi_print(format, NULL, 0, &nq, q);
+ *publenp += nq + 4;
+ gcry_mpi_print(format, NULL, 0, &ng, g);
+ *publenp += ng + 4;
+ gcry_mpi_print(format, NULL, 0, &ny, y);
+ *publenp += ny + 4;
+
+ *pubbufp = malloc(*publenp);
+
+ gcry_mpi_release(p);
+ gcry_mpi_release(q);
+ gcry_mpi_release(g);
+ gcry_mpi_release(y);
+}
+
+static void test_otrl_privkey_generate_FILEp(void)
+{
+ int fd = mkstemp(filename);
+ f = fdopen(fd, "w+b");
+
+ unlink(filename); // The file will be removed on close
+ us = otrl_userstate_create();
+ ok(otrl_privkey_generate_FILEp(us, f, "alice", "irc")
+ == gcry_error(GPG_ERR_NO_ERROR) &&
+ us->privkey_root != NULL,
+ "key generated");
+}
+
+static void test_otrl_privkey_hash_to_human(void)
+{
+ int i;
+ char human[OTRL_PRIVKEY_FPRINT_HUMAN_LEN];
+ unsigned char hash[20];
+
+ for(i = 0; i < 20; i++) {
+ hash[i] = 'A' + i;
+ }
+
+ otrl_privkey_hash_to_human(human, hash);
+ ok(strcmp("41424344 45464748 494A4B4C 4D4E4F50 51525354", human) == 0,
+ "Hash to human ok");
+}
+
+static void test_otrl_privkey_fingerprint(void)
+{
+ char fingerprint[OTRL_PRIVKEY_FPRINT_HUMAN_LEN] = {0};
+ char expected_fingerprint[OTRL_PRIVKEY_FPRINT_HUMAN_LEN] = {0};
+ unsigned char hash[20] = {0};
+ char *fp = otrl_privkey_fingerprint(us, fingerprint, "alice", "irc");
+ const OtrlPrivKey *p = otrl_privkey_find(us, "alice", "irc");
+
+ gcry_md_hash_buffer(GCRY_MD_SHA1, hash, p->pubkey_data, p->pubkey_datalen);
+ otrl_privkey_hash_to_human(expected_fingerprint, hash);
+
+ ok(fp == fingerprint &&
+ memcmp(fingerprint, expected_fingerprint,
+ OTRL_PRIVKEY_FPRINT_HUMAN_LEN) == 0,
+ "Privkey fingerprint ok");
+}
+
+static void test_otrl_privkey_fingerprint_raw(void)
+{
+ unsigned char hash[20] = {0};
+ unsigned char expected_hash[20] = {0};
+ unsigned char *h = otrl_privkey_fingerprint_raw(us, hash, "alice", "irc");
+
+ const OtrlPrivKey *p = otrl_privkey_find(us, "alice", "irc");
+ gcry_md_hash_buffer(GCRY_MD_SHA1, expected_hash, p->pubkey_data,
+ p->pubkey_datalen);
+
+ ok(h == hash && memcmp(hash, expected_hash, 20) == 0,
+ "Raw privkey fingerprint ok");
+}
+
+static void test_otrl_privkey_find(void)
+{
+ OtrlPrivKey *p = NULL;
+
+ ok(otrl_privkey_find(us, "bob", "xmpp") == NULL,
+ "Privkey not found");
+
+ ok(otrl_privkey_find(us, "alice", "xmpp") == NULL,
+ "Privkey not found because of wrong protocol");
+
+ ok(otrl_privkey_find(us, "bob", "irc") == NULL,
+ "Privkey not found because of wrong name");
+
+ p = otrl_privkey_find(us, "alice", "irc");
+ ok(p != NULL && strcmp(p->accountname, "alice") == 0 &&
+ strcmp(p->protocol, "irc") == 0,
+ "Privkey found");
+}
+
+static void test_otrl_privkey_sign(void)
+{
+ unsigned char *sig = NULL;
+ size_t siglen;
+ const char *data = "Some data to sign.";
+ size_t len = strlen(data);
+ OtrlPrivKey *p = otrl_privkey_find(us, "alice", "irc");
+
+ p->pubkey_type = OTRL_PUBKEY_TYPE_DSA + 1;
+
+ ok(otrl_privkey_sign(&sig, &siglen, p,
+ (unsigned char *) data, len) == gcry_error(GPG_ERR_INV_VALUE),
+ "Wrong pubkey type detected");
+ free(sig);
+
+ p->pubkey_type = OTRL_PUBKEY_TYPE_DSA;
+
+ ok(otrl_privkey_sign(&sig, &siglen, p,
+ (unsigned char *) data, len) == gcry_error(GPG_ERR_NO_ERROR),
+ "data signed");
+ free(sig);
+
+ ok(otrl_privkey_sign(&sig, &siglen, p, (unsigned char*)data, 0) ==
+ gcry_error(GPG_ERR_NO_ERROR), "data with len 0 signed");
+ free(sig);
+}
+
+static void test_otrl_privkey_verify(void)
+{
+ unsigned char *sigbuf = NULL;
+ size_t siglen;
+ const char *data = "Some data to sign.";
+ OtrlPrivKey *privkey = otrl_privkey_find(us, "alice", "irc");
+ gcry_mpi_t p,q,g,y;
+ gcry_sexp_t dsas, ps, qs, gs, ys;
+ gcry_sexp_t pubs = NULL;
+ gcry_error_t ret;
+
+ /* Extract pubkey */
+ dsas = gcry_sexp_find_token(privkey->privkey, "dsa", 0);
+ ps = gcry_sexp_find_token(dsas, "p", 0);
+ qs = gcry_sexp_find_token(dsas, "q", 0);
+ gs = gcry_sexp_find_token(dsas, "g", 0);
+ ys = gcry_sexp_find_token(dsas, "y", 0);
+ gcry_sexp_release(dsas);
+ p = gcry_sexp_nth_mpi(ps, 1, GCRYMPI_FMT_USG);
+ q = gcry_sexp_nth_mpi(qs, 1, GCRYMPI_FMT_USG);
+ g = gcry_sexp_nth_mpi(gs, 1, GCRYMPI_FMT_USG);
+ y = gcry_sexp_nth_mpi(ys, 1, GCRYMPI_FMT_USG);
+ gcry_sexp_release(ps);
+ gcry_sexp_release(qs);
+ gcry_sexp_release(gs);
+ gcry_sexp_release(ys);
+
+ gcry_sexp_build(&pubs, NULL, "(public-key (dsa (p %m)(q %m)(g %m)(y %m)))",
+ p, q, g, y);
+
+ gcry_mpi_release(p);
+ gcry_mpi_release(q);
+ gcry_mpi_release(g);
+ gcry_mpi_release(y);
+
+ otrl_privkey_sign(&sigbuf, &siglen, privkey, (unsigned char*)data,
+ strlen(data));
+
+ ok(otrl_privkey_verify(sigbuf, siglen, OTRL_PUBKEY_TYPE_DSA, pubs,
+ (unsigned char *) data, strlen(data)) == 0, "Signature ok");
+
+ ret = otrl_privkey_verify(sigbuf, siglen, OTRL_PUBKEY_TYPE_DSA, pubs,
+ (unsigned char *) data + 1, strlen(data) - 1);
+ ok(gcry_error(ret) == gcry_error(GPG_ERR_BAD_SIGNATURE),
+ "Wrong signature");
+
+ free(sigbuf);
+}
+
+int main(int argc, char **argv)
+{
+ OtrlPrivKey *p;
+ plan_tests(NUM_TESTS);
+
+ gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
+ OTRL_INIT;
+
+ /* Set to quick random so we don't wait on /dev/random. */
+ gcry_control(GCRYCTL_ENABLE_QUICK_RANDOM, 0);
+
+ test_otrl_privkey_generate_FILEp(); //This must be the first one
+ p = otrl_privkey_find(us, "alice", "irc");
+ make_pubkey(&(p->pubkey_data), &(p->pubkey_datalen), p->privkey);
+
+ test_otrl_privkey_hash_to_human();
+ test_otrl_privkey_fingerprint();
+ test_otrl_privkey_fingerprint_raw();
+ test_otrl_privkey_sign();
+ test_otrl_privkey_verify();
+ test_otrl_privkey_find();
+
+ fclose(f);
+ otrl_userstate_free(us);
+
+ return 0;
+}