/* * Copyright (C) 2014 - Julien Voisin * * 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 #include #include #include #include #include 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; }