diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 09:51:24 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 09:51:24 +0000 |
commit | f7548d6d28c313cf80e6f3ef89aed16a19815df1 (patch) | |
tree | a3f6f2a3f247293bee59ecd28e8cd8ceb6ca064a /src/lib-dcrypt/test-crypto.c | |
parent | Initial commit. (diff) | |
download | dovecot-f7548d6d28c313cf80e6f3ef89aed16a19815df1.tar.xz dovecot-f7548d6d28c313cf80e6f3ef89aed16a19815df1.zip |
Adding upstream version 1:2.3.19.1+dfsg1.upstream/1%2.3.19.1+dfsg1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | src/lib-dcrypt/test-crypto.c | 1314 |
1 files changed, 1314 insertions, 0 deletions
diff --git a/src/lib-dcrypt/test-crypto.c b/src/lib-dcrypt/test-crypto.c new file mode 100644 index 0000000..ce43791 --- /dev/null +++ b/src/lib-dcrypt/test-crypto.c @@ -0,0 +1,1314 @@ +/* Copyright (c) 2016-2018 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "array.h" +#include "buffer.h" +#include "str.h" +#include "dcrypt.h" +#include "dcrypt-iostream.h" +#include "ostream.h" +#include "ostream-encrypt.h" +#include "istream.h" +#include "iostream-temp.h" +#include "randgen.h" +#include "test-common.h" +#include "hex-binary.h" +#include "json-parser.h" +#include <fcntl.h> +#include <sys/stat.h> +#include <stdio.h> + +static void test_cipher_test_vectors(void) +{ + static const struct { + const char *key; + const char *iv; + const char *pt; + const char *ct; + } vectors[] = { + { + "2b7e151628aed2a6abf7158809cf4f3c", + "000102030405060708090a0b0c0d0e0f", + "6bc1bee22e409f96e93d7e117393172a", + "7649abac8119b246cee98e9b12e9197d" + }, { + "2b7e151628aed2a6abf7158809cf4f3c", + "7649ABAC8119B246CEE98E9B12E9197D", + "ae2d8a571e03ac9c9eb76fac45af8e51", + "5086cb9b507219ee95db113a917678b2" + } + }; + + + test_begin("test_cipher_test_vectors"); + + buffer_t *key,*iv,*pt,*ct,*res_enc,*res_dec; + + key = t_buffer_create(16); + iv = t_buffer_create(16); + pt = t_buffer_create(16); + ct = t_buffer_create(16); + + res_enc = t_buffer_create(32); + res_dec = t_buffer_create(32); + + for(size_t i = 0; i < N_ELEMENTS(vectors); i++) { + struct dcrypt_context_symmetric *ctx; + + buffer_set_used_size(key, 0); + buffer_set_used_size(iv, 0); + buffer_set_used_size(pt, 0); + buffer_set_used_size(ct, 0); + buffer_set_used_size(res_enc, 0); + buffer_set_used_size(res_dec, 0); + + hex_to_binary(vectors[i].key, key); + hex_to_binary(vectors[i].iv, iv); + hex_to_binary(vectors[i].pt, pt); + hex_to_binary(vectors[i].ct, ct); + + if (!dcrypt_ctx_sym_create("AES-128-CBC", DCRYPT_MODE_ENCRYPT, + &ctx, NULL)) { + test_assert_failed("dcrypt_ctx_sym_create", + __FILE__, __LINE__-1); + continue; + } + + dcrypt_ctx_sym_set_padding(ctx, FALSE); + + dcrypt_ctx_sym_set_key(ctx, key->data, key->used); + dcrypt_ctx_sym_set_iv(ctx, iv->data, iv->used); + + test_assert_idx(dcrypt_ctx_sym_init(ctx, NULL), i); + + test_assert_idx(dcrypt_ctx_sym_update(ctx, + pt->data, pt->used, res_enc, NULL), i); + test_assert_idx(dcrypt_ctx_sym_final(ctx, res_enc, NULL), i); + + test_assert_idx(buffer_cmp(ct, res_enc), i); + + dcrypt_ctx_sym_destroy(&ctx); + + if (!dcrypt_ctx_sym_create("AES-128-CBC", DCRYPT_MODE_DECRYPT, + &ctx, NULL)) { + test_assert_failed("dcrypt_ctx_sym_create", + __FILE__, __LINE__-1); + continue; + } + + dcrypt_ctx_sym_set_padding(ctx, FALSE); + + dcrypt_ctx_sym_set_key(ctx, key->data, key->used); + dcrypt_ctx_sym_set_iv(ctx, iv->data, iv->used); + + test_assert_idx(dcrypt_ctx_sym_init(ctx, NULL), i); + test_assert_idx(dcrypt_ctx_sym_update(ctx, + res_enc->data, res_enc->used, res_dec, NULL), i); + test_assert_idx(dcrypt_ctx_sym_final(ctx, res_dec, NULL), i); + + test_assert_idx(buffer_cmp(pt, res_dec), i); + + dcrypt_ctx_sym_destroy(&ctx); + } + + test_end(); +} + +static void test_cipher_aead_test_vectors(void) +{ + struct dcrypt_context_symmetric *ctx; + const char *error = NULL; + + test_begin("test_cipher_aead_test_vectors"); + + if (!dcrypt_ctx_sym_create("aes-128-gcm", DCRYPT_MODE_ENCRYPT, + &ctx, &error)) { + test_assert_failed("dcrypt_ctx_sym_create", + __FILE__, __LINE__-1); + return; + } + + buffer_t *key, *iv, *aad, *pt, *ct, *tag, *tag_res, *res; + + key = t_buffer_create(16); + iv = t_buffer_create(16); + aad = t_buffer_create(16); + pt = t_buffer_create(16); + ct = t_buffer_create(16); + tag = t_buffer_create(16); + res = t_buffer_create(16); + tag_res = t_buffer_create(16); + + hex_to_binary("feffe9928665731c6d6a8f9467308308", key); + hex_to_binary("cafebabefacedbaddecaf888", iv); + hex_to_binary("d9313225f88406e5a55909c5aff5269a" + "86a7a9531534f7da2e4c303d8a318a72" + "1c3c0c95956809532fcf0e2449a6b525" + "b16aedf5aa0de657ba637b391aafd255", pt); + hex_to_binary("42831ec2217774244b7221b784d0d49c" + "e3aa212f2c02a4e035c17e2329aca12e" + "21d514b25466931c7d8f6a5aac84aa05" + "1ba30b396a0aac973d58e091473f5985", ct); + hex_to_binary("4d5c2af327cd64a62cf35abd2ba6fab4", tag); + + dcrypt_ctx_sym_set_key(ctx, key->data, key->used); + dcrypt_ctx_sym_set_iv(ctx, iv->data, iv->used); + dcrypt_ctx_sym_set_aad(ctx, aad->data, aad->used); + test_assert(dcrypt_ctx_sym_init(ctx, &error)); + test_assert(dcrypt_ctx_sym_update(ctx, pt->data, pt->used, res, &error)); + test_assert(dcrypt_ctx_sym_final(ctx, res, &error)); + test_assert(dcrypt_ctx_sym_get_tag(ctx, tag_res)); + + test_assert(buffer_cmp(ct, res) == TRUE); + test_assert(buffer_cmp(tag, tag_res) == TRUE); + + dcrypt_ctx_sym_destroy(&ctx); + + if (!dcrypt_ctx_sym_create("aes-128-gcm", DCRYPT_MODE_DECRYPT, + &ctx, &error)) { + test_assert_failed("dcrypt_ctx_sym_create", + __FILE__, __LINE__-1); + } else { + + buffer_set_used_size(res, 0); + + dcrypt_ctx_sym_set_key(ctx, key->data, key->used); + dcrypt_ctx_sym_set_iv(ctx, iv->data, iv->used); + dcrypt_ctx_sym_set_aad(ctx, aad->data, aad->used); + dcrypt_ctx_sym_set_tag(ctx, tag->data, tag->used); + test_assert(dcrypt_ctx_sym_init(ctx, &error)); + test_assert(dcrypt_ctx_sym_update(ctx, + ct->data, ct->used, res, &error)); + test_assert(dcrypt_ctx_sym_final(ctx, res, &error)); + + test_assert(buffer_cmp(pt, res) == TRUE); + + dcrypt_ctx_sym_destroy(&ctx); + } + + test_end(); +} + +static void test_hmac_test_vectors(void) +{ + test_begin("test_hmac_test_vectors"); + + buffer_t *pt, *ct, *key, *res; + pt = t_buffer_create(50); + key = t_buffer_create(20); + ct = t_buffer_create(32); + res = t_buffer_create(32); + + hex_to_binary("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", key); + hex_to_binary("dddddddddddddddddddddddddddddddddddddddddddddddddd" + "dddddddddddddddddddddddddddddddddddddddddddddddddd", pt); + hex_to_binary("773ea91e36800e46854db8ebd09181a7" + "2959098b3ef8c122d9635514ced565fe", res); + + struct dcrypt_context_hmac *hctx; + if (!dcrypt_ctx_hmac_create("sha256", &hctx, NULL)) { + test_assert_failed("dcrypt_ctx_hmac_create", + __FILE__, __LINE__-1); + } else { + dcrypt_ctx_hmac_set_key(hctx, key->data, key->used); + test_assert(dcrypt_ctx_hmac_init(hctx, NULL)); + test_assert(dcrypt_ctx_hmac_update(hctx, + pt->data, pt->used, NULL)); + test_assert(dcrypt_ctx_hmac_final(hctx, ct, NULL)); + test_assert(buffer_cmp(ct, res)); + dcrypt_ctx_hmac_destroy(&hctx); + } + + test_end(); +} + +static void test_load_v1_keys(void) +{ + test_begin("test_load_v1_keys"); + + const char *error = NULL; + const char *data1 = + "1\t716\t1\t0567e6bf9579813ae967314423b0fceb14bda24" + "749303923de9a9bb9370e0026f995901a57e63113eeb2baf0c" + "940e978d00686cbb52bd5014bc318563375876255\t0300E46" + "DA2125427BE968EB3B649910CDC4C405E5FFDE18D433A97CAB" + "FEE28CEEFAE9EE356C792004FFB80981D67E741B8CC036A342" + "35A8D2E1F98D1658CFC963D07EB\td0cfaca5d335f9edc41c8" + "4bb47465184cb0e2ec3931bebfcea4dd433615e77a0\t7c9a1" + "039ea2e4fed73e81dd3ffc3fa22ea4a28352939adde7bf8ea8" + "58b00fa4f"; + + enum dcrypt_key_format format; + enum dcrypt_key_version version; + enum dcrypt_key_kind kind; + enum dcrypt_key_encryption_type encryption_type; + const char *encryption_key_hash = NULL; + const char *key_hash = NULL; + + bool ret = dcrypt_key_string_get_info(data1, &format, &version, + &kind, &encryption_type, &encryption_key_hash, + &key_hash, &error); + + test_assert(ret == TRUE); + test_assert(error == NULL); + test_assert(format == DCRYPT_FORMAT_DOVECOT); + test_assert(version == DCRYPT_KEY_VERSION_1); + test_assert(kind == DCRYPT_KEY_KIND_PRIVATE); + test_assert(encryption_type == DCRYPT_KEY_ENCRYPTION_TYPE_KEY); + test_assert(strcmp(encryption_key_hash, + "d0cfaca5d335f9edc41c84bb47465184" + "cb0e2ec3931bebfcea4dd433615e77a0") == 0); + test_assert(strcmp(key_hash, + "7c9a1039ea2e4fed73e81dd3ffc3fa22" + "ea4a28352939adde7bf8ea858b00fa4f") == 0); + + const char* data2 = + "1\t716\t0301EB00973C4EFC8FCECA4EA33E941F50B561199A" + "5159BCB6C2EED9DD1D62D65E38A254979D89E28F0C28883E71" + "EE2AD264CD16B863FA094A8F6F69A56B62E8918040\t7c9a10" + "39ea2e4fed73e81dd3ffc3fa22ea4a28352939adde7bf8ea85" + "8b00fa4f"; + + error = NULL; + encryption_key_hash = NULL; + key_hash = NULL; + + ret = dcrypt_key_string_get_info(data2, &format, &version, + &kind, &encryption_type, &encryption_key_hash, + &key_hash, &error); + + test_assert(ret == TRUE); + test_assert(error == NULL); + test_assert(format == DCRYPT_FORMAT_DOVECOT); + test_assert(version == DCRYPT_KEY_VERSION_1); + test_assert(kind == DCRYPT_KEY_KIND_PUBLIC); + test_assert(encryption_type == DCRYPT_KEY_ENCRYPTION_TYPE_NONE); + test_assert(encryption_key_hash == NULL); + test_assert(strcmp(key_hash, + "7c9a1039ea2e4fed73e81dd3ffc3fa22" + "ea4a28352939adde7bf8ea858b00fa4f") == 0); + + /* This is the key that should be able to decrypt key1 */ + const char *data3 = + "1\t716\t0\t048FD04FD3612B22D32790C592CF21CEF417EFD" + "2EA34AE5F688FA5B51BED29E05A308B68DA78E16E90B47A11E" + "133BD9A208A2894FD01B0BEE865CE339EA3FB17AC\td0cfaca" + "5d335f9edc41c84bb47465184cb0e2ec3931bebfcea4dd4336" + "15e77a0"; + + error = NULL; + encryption_key_hash = NULL; + key_hash = NULL; + + ret = dcrypt_key_string_get_info(data3, &format, &version, + &kind, &encryption_type, &encryption_key_hash, + &key_hash, &error); + test_assert(ret == TRUE); + test_assert(error == NULL); + test_assert(format == DCRYPT_FORMAT_DOVECOT); + test_assert(version == DCRYPT_KEY_VERSION_1); + test_assert(kind == DCRYPT_KEY_KIND_PRIVATE); + test_assert(encryption_type == DCRYPT_KEY_ENCRYPTION_TYPE_NONE); + test_assert(encryption_key_hash == NULL); + test_assert(strcmp(key_hash, + "d0cfaca5d335f9edc41c84bb47465184" + "cb0e2ec3931bebfcea4dd433615e77a0") == 0); + + /* key3's key_hash should and does match key1's encryption_key_hash */ + struct dcrypt_private_key *pkey = NULL; + struct dcrypt_private_key *pkey2 = NULL; + pkey = NULL; + error = NULL; + + ret = dcrypt_key_load_private(&pkey2, data3, NULL, NULL, &error); + test_assert(ret == TRUE); + test_assert(error == NULL); + + ret = dcrypt_key_load_private(&pkey, data1, NULL, pkey2, &error); + test_assert(ret == TRUE); + test_assert(error == NULL); + + dcrypt_key_unref_private(&pkey2); + dcrypt_key_unref_private(&pkey); + + test_end(); +} + +static void test_load_v1_key(void) +{ + test_begin("test_load_v1_key"); + + buffer_t *key_1 = t_buffer_create(128); + + struct dcrypt_private_key *pkey = NULL, *pkey2 = NULL; + const char *error = NULL; + + test_assert(dcrypt_key_load_private(&pkey, + "1\t716\t0\t048FD04FD3612B22D32790C592CF21CEF417EFD" + "2EA34AE5F688FA5B51BED29E05A308B68DA78E16E90B47A11E" + "133BD9A208A2894FD01B0BEE865CE339EA3FB17AC\td0cfaca" + "5d335f9edc41c84bb47465184cb0e2ec3931bebfcea4dd4336" + "15e77a0", NULL, NULL, &error)); + if (pkey != NULL) { + buffer_set_used_size(key_1, 0); + /* check that key_id matches */ + struct dcrypt_public_key *pubkey = NULL; + dcrypt_key_convert_private_to_public(pkey, &pubkey); + test_assert(dcrypt_key_store_public(pubkey, + DCRYPT_FORMAT_DOVECOT, key_1, NULL)); + buffer_set_used_size(key_1, 0); + dcrypt_key_id_public(pubkey, "sha256", key_1, &error); + test_assert(strcmp("792caad4d38c9eb2134a0cbc844eae38" + "6116de096a0ccafc98479825fc99b6a1", + binary_to_hex(key_1->data, key_1->used)) + == 0); + + dcrypt_key_unref_public(&pubkey); + pkey2 = NULL; + + test_assert(dcrypt_key_load_private(&pkey2, + "1\t716\t1\t0567e6bf9579813ae967314423b0fceb14" + "bda24749303923de9a9bb9370e0026f995901a57e6311" + "3eeb2baf0c940e978d00686cbb52bd5014bc318563375" + "876255\t0300E46DA2125427BE968EB3B649910CDC4C4" + "05E5FFDE18D433A97CABFEE28CEEFAE9EE356C792004F" + "FB80981D67E741B8CC036A34235A8D2E1F98D1658CFC9" + "63D07EB\td0cfaca5d335f9edc41c84bb47465184cb0e" + "2ec3931bebfcea4dd433615e77a0\t7c9a1039ea2e4fe" + "d73e81dd3ffc3fa22ea4a28352939adde7bf8ea858b00" + "fa4f", NULL, pkey, &error)); + if (pkey2 != NULL) { + buffer_set_used_size(key_1, 0); + /* check that key_id matches */ + struct dcrypt_public_key *pubkey = NULL; + dcrypt_key_convert_private_to_public(pkey2, &pubkey); + test_assert(dcrypt_key_store_public(pubkey, + DCRYPT_FORMAT_DOVECOT, key_1, NULL)); + buffer_set_used_size(key_1, 0); + test_assert(dcrypt_key_id_public_old(pubkey, + key_1, &error)); + test_assert(strcmp( + "7c9a1039ea2e4fed73e81dd3ffc3fa22" + "ea4a28352939adde7bf8ea858b00fa4f", + binary_to_hex(key_1->data, key_1->used)) == 0); + + dcrypt_key_unref_public(&pubkey); + dcrypt_key_unref_private(&pkey2); + } + dcrypt_key_unref_private(&pkey); + } + + test_end(); +} + +static void test_load_v1_public_key(void) +{ + test_begin("test_load_v1_public_key"); + + const char* data1 = + "1\t716\t030131D8A5FD5167947A0AE9CB112ADED652665463" + "5AA5887051EE2364414B60FF32EBA8FA0BBE9485DBDE8794BB" + "BCB44BBFC0D662A4287A848BA570D4E5E45A11FE0F\td0cfac" + "a5d335f9edc41c84bb47465184cb0e2ec3931bebfcea4dd433" + "615e77a0"; + + const char* error = NULL; + const char* key_hash = NULL; + const char* encryption_key_hash = NULL; + + enum dcrypt_key_format format; + enum dcrypt_key_version version; + enum dcrypt_key_kind kind; + enum dcrypt_key_encryption_type encryption_type; + + bool ret = dcrypt_key_string_get_info(data1, &format, &version, + &kind, &encryption_type, &encryption_key_hash, + &key_hash, &error); + + test_assert(ret == TRUE); + test_assert(error == NULL); + test_assert(format == DCRYPT_FORMAT_DOVECOT); + test_assert(version == DCRYPT_KEY_VERSION_1); + test_assert(kind == DCRYPT_KEY_KIND_PUBLIC); + test_assert(encryption_type == DCRYPT_KEY_ENCRYPTION_TYPE_NONE); + test_assert(key_hash != NULL && + strcmp(key_hash, "d0cfaca5d335f9edc41c84bb47465184" + "cb0e2ec3931bebfcea4dd433615e77a0") == 0); + test_assert(encryption_key_hash == NULL); + + struct dcrypt_public_key *pub_key = NULL; + ret = dcrypt_key_load_public(&pub_key, data1, &error); + test_assert(ret == TRUE); + test_assert(error == NULL); + + test_assert(dcrypt_key_type_public(pub_key) == DCRYPT_KEY_EC); + + dcrypt_key_unref_public(&pub_key); + test_assert(pub_key == NULL); + + test_end(); +} + +static void test_load_v2_key(void) +{ + const char *keys[] = { + "-----BEGIN PRIVATE KEY-----\n" + "MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgtu" + "QJA+uboZWVwgHc\n" + "DciyVdrovAPwlMqshDK3s78IDDuhRANCAAQm0VEdzLB9PtD0HA" + "8JK1zifWnj8M00\n" + "FQzedfp9SQsWyA8dzs5/NFR5MTe6Xbh/ndKEs1zZH3vZ4FlNri" + "lZc0st\n" + "-----END PRIVATE KEY-----\n", + "2:1.2.840.10045.3.1.7:0:0000002100b6e40903eb9ba195" + "95c201dc0dc8b255dae8bc03f094caac8432b7b3bf080c3b:a" + "b13d251976dedab546b67354e7678821740dd534b749c2857f" + "66bf62bbaddfd", + "2:1.2.840.10045.3.1.7:2:aes-256-ctr:483bd74fd3d917" + "63:sha256:2048:d44ae35d3af7a2febcb15cde0c3693e7ed9" + "8595665ed655a97fa918d346d5c661a6e2339f4:ab13d25197" + "6dedab546b67354e7678821740dd534b749c2857f66bf62bba" + "ddfd", + "2:1.2.840.10045.3.1.7:1:aes-256-ctr:2574c10be28a4c" + "09:sha256:2048:a750ec9dea91999f108f943485a20f273f4" + "0f75c37fc9bcccdedda514c8243e550d69ce1bd:02237a199d" + "7d945aa6492275a02881071eceec5749caf2485da8c64fb601" + "229098:ab13d251976dedab546b67354e7678821740dd534b7" + "49c2857f66bf62bbaddfd:ab13d251976dedab546b67354e76" + "78821740dd534b749c2857f66bf62bbaddfd" + }; + + test_begin("test_load_v2_key"); + const char *error = NULL; + buffer_t *tmp = buffer_create_dynamic(default_pool, 256); + + struct dcrypt_private_key *priv,*priv2; + + test_assert_idx(dcrypt_key_load_private(&priv2, + keys[0], NULL, NULL, &error), 0); + test_assert_idx(dcrypt_key_store_private(priv2, + DCRYPT_FORMAT_PEM, NULL, tmp, NULL, NULL, &error), 0); + test_assert_idx(strcmp(str_c(tmp), keys[0])==0, 0); + buffer_set_used_size(tmp, 0); + + test_assert_idx(dcrypt_key_load_private(&priv, + keys[1], NULL, NULL, &error), 1); + test_assert_idx(dcrypt_key_store_private(priv, + DCRYPT_FORMAT_DOVECOT, NULL, tmp, NULL, NULL, &error), 1); + test_assert_idx(strcmp(str_c(tmp), keys[1])==0, 1); + buffer_set_used_size(tmp, 0); + dcrypt_key_unref_private(&priv); + + test_assert_idx(dcrypt_key_load_private(&priv, + keys[2], "This Is Sparta", NULL, &error), 2); + test_assert_idx(dcrypt_key_store_private(priv, + DCRYPT_FORMAT_DOVECOT, "aes-256-ctr", tmp, + "This Is Sparta", NULL, &error), 2); + buffer_set_used_size(tmp, 0); + dcrypt_key_unref_private(&priv); + + struct dcrypt_public_key *pub = NULL; + dcrypt_key_convert_private_to_public(priv2, &pub); + test_assert_idx(dcrypt_key_load_private(&priv, + keys[3], NULL, priv2, &error), 3); + test_assert_idx(dcrypt_key_store_private(priv, + DCRYPT_FORMAT_DOVECOT, "ecdh-aes-256-ctr", tmp, + NULL, pub, &error), 3); + buffer_set_used_size(tmp, 0); + dcrypt_key_unref_private(&priv2); + dcrypt_key_unref_private(&priv); + dcrypt_key_unref_public(&pub); + + buffer_free(&tmp); + + if (error != NULL) error = NULL; + + test_end(); +} + +static void test_load_v2_public_key(void) +{ + struct dcrypt_public_key *pub = NULL; + const char *error; + + test_begin("test_load_v2_public_key"); + const char *key = + "2:3058301006072a8648ce3d020106052b810400230344000" + "301c50954e734dd8b410a607764a7057065a45510da52f2c6" + "e28e0cb353b9c389fa8cb786943ae991fce9befed78fb162f" + "bbc615415f06af06c8cc80c37f4e94ff6c7:185a721254278" + "2e239111f9c19d126ad55b18ddaf4883d66afe8d9627c3607" + "d8"; + + test_assert(dcrypt_key_load_public(&pub, key, &error)); + + buffer_t *tmp = buffer_create_dynamic(default_pool, 256); + + if (pub != NULL) { + test_assert(dcrypt_key_store_public(pub, + DCRYPT_FORMAT_DOVECOT, tmp, &error)); + test_assert(strcmp(key, str_c(tmp))==0); + buffer_free(&tmp); + dcrypt_key_unref_public(&pub); + } + + test_end(); +} + +static void test_get_info_v2_key(void) +{ + test_begin("test_get_info_v2_key"); + + const char *key = + "2:305e301006072a8648ce3d020106052b81040026034a0002" + "03fcc90034fa03d6fb79a0fc8b3b43c3398f68e76029307360" + "cdcb9e27bb7e84b3c19dfb7244763bc4d442d216f09b7b7945" + "ed9d182f3156550e9ee30b237a0217dbf79d28975f31:86706" + "b69d1f640011a65d26a42f2ba20a619173644e1cc7475eb1d9" + "0966e84dc"; + enum dcrypt_key_format format; + enum dcrypt_key_version version = DCRYPT_KEY_VERSION_NA; + enum dcrypt_key_kind kind; + enum dcrypt_key_encryption_type encryption_type; + const char *encryption_key_hash = NULL; + const char *key_hash = NULL; + const char *error = NULL; + + test_assert(dcrypt_key_string_get_info(key, &format, &version, + &kind, &encryption_type, &encryption_key_hash, + &key_hash, &error)); + test_assert(error == NULL); + test_assert(format == DCRYPT_FORMAT_DOVECOT); + test_assert(version == DCRYPT_KEY_VERSION_2); + + test_assert(kind == DCRYPT_KEY_KIND_PUBLIC); + test_assert(encryption_type == DCRYPT_KEY_ENCRYPTION_TYPE_NONE); + test_assert(encryption_key_hash == NULL); + test_assert(key_hash != NULL && strcmp(key_hash, + "86706b69d1f640011a65d26a42f2ba20" + "a619173644e1cc7475eb1d90966e84dc") == 0); + + test_end(); +} + +static void test_gen_and_get_info_rsa_pem(void) +{ + test_begin("test_gen_and_get_info_rsa_pem"); + + const char *error = NULL; + bool ret = FALSE; + struct dcrypt_keypair pair; + string_t* buf = str_new(default_pool, 4096); + + ret = dcrypt_keypair_generate(&pair, DCRYPT_KEY_RSA, 1024, NULL, NULL); + test_assert(ret == TRUE); + + /* test public key */ + enum dcrypt_key_format format; + enum dcrypt_key_version version; + enum dcrypt_key_kind kind; + enum dcrypt_key_encryption_type encryption_type; + const char *encryption_key_hash; + const char *key_hash; + + ret = dcrypt_key_store_public(pair.pub, DCRYPT_FORMAT_PEM, buf, + &error); + test_assert(ret == TRUE); + + ret = dcrypt_key_string_get_info(str_c(buf), &format, &version, + &kind, &encryption_type, &encryption_key_hash, + &key_hash, &error); + test_assert(ret == TRUE); + test_assert(format == DCRYPT_FORMAT_PEM); + test_assert(version == DCRYPT_KEY_VERSION_NA); + + test_assert(kind == DCRYPT_KEY_KIND_PUBLIC); + test_assert(encryption_type == DCRYPT_KEY_ENCRYPTION_TYPE_NONE); + test_assert(encryption_key_hash == NULL); + test_assert(key_hash == NULL); + + /* test private key */ + buffer_set_used_size(buf, 0); + ret = dcrypt_key_store_private(pair.priv, DCRYPT_FORMAT_PEM, NULL, + buf, NULL, NULL, &error); + + test_assert(ret == TRUE); + + ret = dcrypt_key_string_get_info(str_c(buf), &format, &version, + &kind, &encryption_type, &encryption_key_hash, + &key_hash, &error); + + test_assert(ret == TRUE); + test_assert(format == DCRYPT_FORMAT_PEM); + test_assert(version == DCRYPT_KEY_VERSION_NA); + + test_assert(kind == DCRYPT_KEY_KIND_PRIVATE); + + test_assert(encryption_type == DCRYPT_KEY_ENCRYPTION_TYPE_NONE); + test_assert(encryption_key_hash == NULL); + test_assert(key_hash == NULL); + + dcrypt_keypair_unref(&pair); + buffer_free(&buf); + + test_end(); +} + +static void test_get_info_rsa_private_key(void) +{ + test_begin("test_get_info_rsa_private_key"); + + const char *key = "-----BEGIN RSA PRIVATE KEY-----\n" +"MIICXQIBAAKBgQC89q02I9NezBLQ+otn5XLYE7S+GsKUz59ogr45DA/6MI9jey0W\n" +"56SeWQ1FJD1vDhAx/TRBMfOmhcIPsBjc5sakYOawPdoiqLjOIlO+iHwnbbmLuMsq\n" +"ue09vgvZsKjuTr2F5DOFQY43Bq/Nd+4bjHJItdOM58+xwA2I/8vDbtI8jwIDAQAB\n" +"AoGBAJCUrTMfdjqyKjN7f+6ewKBTc5eBIiB6O53ba3B6qj7jqNKVDIrZ8jq2KFEe\n" +"yWKPgBS/h5vafHKNJU6bjmp2qMUJPB7PTA876eDo0cq9PplUqihiTlXJFwNQYtF+\n" +"o27To5t25+5qdSAj657+lQfFT9Xn9fzYHDmotURxH10FgFkBAkEA+7Ny6lBTeb3W\n" +"LnP0UPfPzQLilEr8u81PLWe69RGtsEaMQHGpHOl4e+bvvVYbG1cgxwxI1m01uR9r\n" +"qpD3qLUdrQJBAMAw6UvN8R+opYTZzwqK7Nliil2QZMPmXM04SV1iFq26NM60w2Fm\n" +"HqOOh0EbpSWsFtIgxJFWoZOtrguxqCJuUqsCQF3EoXf3StHczhDqM8eCOpD2lTCH\n" +"qxXPy8JvlW+9EUbNUWykq0rRE4idJQ0VKe4KjHR6+Buh/dSkhvi5Hvpj1tUCQHRv\n" +"LWeXZLVhXqWVrzEb6VHpuRnmGKX2MdLCfu/sNQEbBlMUgCnJzFYaSybOsMaZ81lq\n" +"MKw8Z7coSYEcKFhzrfECQQD7l+4Bhy8Zuz6VoGGIZwIhxkJrImBFmaUwx8N6jg20\n" +"sgDRYwCoGkGd7B8uIHZLJoWzSSutHiu5i5PYUy5VT1yT\n" +"-----END RSA PRIVATE KEY-----\n"; + + const char *error = NULL; + + test_assert(!dcrypt_key_string_get_info(key, NULL, NULL, + NULL, NULL, NULL, NULL, &error)); + test_assert(error != NULL && strstr(error, "pkey") != NULL); + + test_end(); +} + +static void test_get_info_invalid_keys(void) +{ + test_begin("test_get_info_invalid_keys"); + + const char *key = + "1:716:030131D8A5FD5167947A0AE9CB112ADED6526654635A" + "A5887051EE2364414B60FF32EBA8FA0BBE9485DBDE8794BBBC" + "B44BBFC0D662A4287A848BA570D4E5E45A11FE0F:d0cfaca5d" + "335f9edc41c84bb47465184cb0e2ec3931bebfcea4dd433615" + "e77a0"; + const char *error = NULL; + + test_assert(dcrypt_key_string_get_info(key, NULL, NULL, + NULL, NULL, NULL, NULL, &error) == FALSE); + test_assert(error != NULL && strstr(error, "tab") != NULL); + + key = + "2\t305e301006072a8648ce3d020106052b81040026034a000" + "203fcc90034fa03d6fb79a0fc8b3b43c3398f68e7602930736" + "0cdcb9e27bb7e84b3c19dfb7244763bc4d442d216f09b7b794" + "5ed9d182f3156550e9ee30b237a0217dbf79d28975f31\t867" + "06b69d1f640011a65d26a42f2ba20a619173644e1cc7475eb1" + "d90966e84dc"; + error = NULL; + + test_assert(dcrypt_key_string_get_info(key, NULL, NULL, + NULL, NULL, NULL, NULL, &error) == FALSE); + test_assert(error != NULL && strstr(error, "colon") != NULL); + + key = "2"; + error = NULL; + + test_assert(dcrypt_key_string_get_info(key, NULL, NULL, + NULL, NULL, NULL, NULL, &error) == FALSE); + test_assert(error != NULL && strstr(error, "Unknown") != NULL); + + test_end(); +} + +static void test_get_info_key_encrypted(void) +{ + test_begin("test_get_info_key_encrypted"); + + struct dcrypt_keypair p1, p2; + const char *error = NULL; + bool ret = dcrypt_keypair_generate(&p1, + DCRYPT_KEY_EC, 0, "secp521r1", &error); + test_assert(ret == TRUE); + ret = dcrypt_keypair_generate(&p2, + DCRYPT_KEY_EC, 0, "secp521r1", &error); + test_assert(ret == TRUE); + + string_t* buf = t_str_new(4096); + + buffer_set_used_size(buf, 0); + ret = dcrypt_key_store_private(p1.priv, + DCRYPT_FORMAT_DOVECOT, "ecdh-aes-256-ctr", buf, + NULL, p2.pub, &error); + test_assert(ret == TRUE); + + enum dcrypt_key_format format; + enum dcrypt_key_version version; + enum dcrypt_key_kind kind; + enum dcrypt_key_encryption_type enc_type; + const char *enc_hash; + const char *key_hash; + + ret = dcrypt_key_string_get_info(str_c(buf), &format, &version, + &kind, &enc_type, &enc_hash, &key_hash, &error); + test_assert(ret == TRUE); + test_assert(format == DCRYPT_FORMAT_DOVECOT); + test_assert(version == DCRYPT_KEY_VERSION_2); + test_assert(kind == DCRYPT_KEY_KIND_PRIVATE); + test_assert(enc_type == DCRYPT_KEY_ENCRYPTION_TYPE_KEY); + test_assert(enc_hash != NULL); + test_assert(key_hash != NULL); + + dcrypt_keypair_unref(&p1); + dcrypt_keypair_unref(&p2); + + test_end(); +} + +static void test_get_info_pw_encrypted(void) +{ + test_begin("test_get_info_pw_encrypted"); + + struct dcrypt_keypair p1; + i_zero(&p1); + const char *error; + bool ret = dcrypt_keypair_generate(&p1, + DCRYPT_KEY_EC, 0, "secp521r1", &error); + test_assert(ret == TRUE); + + string_t* buf = t_str_new(4096); + ret = dcrypt_key_store_private(p1.priv, + DCRYPT_FORMAT_DOVECOT, "aes-256-ctr", buf, "pw", NULL, &error); + test_assert(ret == TRUE); + + enum dcrypt_key_format format; + enum dcrypt_key_version version; + enum dcrypt_key_kind kind; + enum dcrypt_key_encryption_type enc_type; + const char *enc_hash; + const char *key_hash; + + ret = dcrypt_key_string_get_info(str_c(buf), &format, &version, + &kind, &enc_type, &enc_hash, &key_hash, &error); + test_assert(ret == TRUE); + test_assert(format == DCRYPT_FORMAT_DOVECOT); + test_assert(version == DCRYPT_KEY_VERSION_2); + test_assert(kind == DCRYPT_KEY_KIND_PRIVATE); + test_assert(enc_type == DCRYPT_KEY_ENCRYPTION_TYPE_PASSWORD); + test_assert(enc_hash == NULL); + test_assert(key_hash != NULL); + + dcrypt_keypair_unref(&p1); + + test_end(); +} + +static void test_password_change(void) +{ + test_begin("test_password_change"); + + const char *pw1 = "first password"; + struct dcrypt_keypair orig; + const char *error = NULL; + + bool ret = dcrypt_keypair_generate(&orig, + DCRYPT_KEY_EC, 0, "secp521r1", &error); + test_assert(ret == TRUE); + + string_t *buf = t_str_new(4096); + ret = dcrypt_key_store_private(orig.priv, + DCRYPT_FORMAT_DOVECOT, "aes-256-ctr", buf, pw1, NULL, &error); + test_assert(ret == TRUE); + + /* load the pw-encrypted key */ + struct dcrypt_private_key *k1_priv = NULL; + ret = dcrypt_key_load_private(&k1_priv, str_c(buf), pw1, NULL, &error); + test_assert(ret == TRUE); + + /* encrypt a key with the pw-encrypted key k1 */ + struct dcrypt_keypair k2; + ret = dcrypt_keypair_generate(&k2, + DCRYPT_KEY_EC, 0, "secp521r1", &error); + test_assert(ret == TRUE); + + string_t *buf2 = t_str_new(4096); + struct dcrypt_public_key *k1_pub = NULL; + dcrypt_key_convert_private_to_public(k1_priv, &k1_pub); + ret = dcrypt_key_store_private(k2.priv, + DCRYPT_FORMAT_DOVECOT, "ecdh-aes-256-ctr", buf2, + NULL, k1_pub, &error); + test_assert(ret == TRUE); + + /* change the password */ + const char *pw2 = "second password"; + string_t *buf3 = t_str_new(4096); + + /* encrypt k1 with pw2 */ + ret = dcrypt_key_store_private(k1_priv, + DCRYPT_FORMAT_DOVECOT, "aes-256-ctr", buf3, pw2, NULL, &error); + test_assert(ret == TRUE); + + /* load the pw2 encrypted key */ + struct dcrypt_private_key *k2_priv = NULL; + ret = dcrypt_key_load_private(&k2_priv, str_c(buf3), pw2, NULL, &error); + test_assert(ret == TRUE); + + /* load the key that was encrypted with pw1 using the pw2 encrypted key */ + struct dcrypt_private_key *k3_priv = NULL; + ret = dcrypt_key_load_private(&k3_priv, + str_c(buf2), NULL, k2_priv, &error); + test_assert(ret == TRUE); + + dcrypt_key_unref_private(&k1_priv); + dcrypt_key_unref_public(&k1_pub); + dcrypt_key_unref_private(&k2_priv); + dcrypt_key_unref_private(&k3_priv); + dcrypt_keypair_unref(&orig); + dcrypt_keypair_unref(&k2); + + test_end(); +} + +static void test_load_invalid_keys(void) +{ + test_begin("test_load_invalid_keys"); + + const char *error = NULL; + const char *key = + "1:716:0301EB00973C4EFC8FCECA4EA33E941F50B561199A51" + "59BCB6C2EED9DD1D62D65E38A254979D89E28F0C28883E71EE" + "2AD264CD16B863FA094A8F6F69A56B62E8918040:7c9a1039e" + "a2e4fed73e81dd3ffc3fa22ea4a28352939adde7bf8ea858b0" + "0fa4f"; + struct dcrypt_public_key *pub_key = NULL; + + bool ret = dcrypt_key_load_public(&pub_key, key, &error); + test_assert(ret == FALSE); + test_assert(error != NULL); + + error = NULL; + key = + "2:305e301006072a8648ce3d020106052b81040026034a0002" + "03fcc90034fa03d6fb79a0fc8b3b43c3398f68e76029307360" + "cdcb9e27bb7e84b3c19dfb7244763bc4d442d216f09b7b7945" + "ed9d182f3156550e9ee30b237a0217dbf79d28975f31:86706" + "b69d1f640011a65d26a42f2ba20a619173644e1cc7475eb1d9" + "0966e84dc"; + struct dcrypt_private_key *priv_key = NULL; + + ret = dcrypt_key_load_private(&priv_key, key, NULL, NULL, &error); + test_assert(ret == FALSE); + test_assert(error != NULL); + + test_end(); +} + +static void test_raw_keys(void) +{ + + test_begin("test_raw_keys"); + + ARRAY_TYPE(dcrypt_raw_key) priv_key; + ARRAY_TYPE(dcrypt_raw_key) pub_key; + pool_t pool = pool_datastack_create(); + + enum dcrypt_key_type t; + + p_array_init(&priv_key, pool, 2); + p_array_init(&pub_key, pool, 2); + + /* generate ECC key */ + struct dcrypt_keypair pair; + i_assert(dcrypt_keypair_generate(&pair, DCRYPT_KEY_EC, 0, "prime256v1", NULL)); + + /* store it */ + test_assert(dcrypt_key_store_private_raw(pair.priv, pool, &t, &priv_key, + NULL)); + test_assert(dcrypt_key_store_public_raw(pair.pub, pool, &t, &pub_key, + NULL)); + dcrypt_keypair_unref(&pair); + + /* load it */ + test_assert(dcrypt_key_load_private_raw(&pair.priv, t, &priv_key, + NULL)); + test_assert(dcrypt_key_load_public_raw(&pair.pub, t, &pub_key, + NULL)); + + dcrypt_keypair_unref(&pair); + + /* test load known raw private key */ + const char *curve = "prime256v1"; + const unsigned char priv_key_data[] = { + 0x16, 0x9e, 0x62, 0x36, 0xaf, 0x9c, 0xae, 0x0e, 0x71, 0xda, + 0xf2, 0x63, 0xe2, 0xe0, 0x5d, 0xf1, 0xd5, 0x35, 0x8c, 0x2b, + 0x68, 0xf0, 0x2a, 0x69, 0xc4, 0x5d, 0x3d, 0x1c, 0xde, 0xa1, + 0x9b, 0xd3 + }; + + /* create buffers */ + struct dcrypt_raw_key *item; + ARRAY_TYPE(dcrypt_raw_key) static_key; + t_array_init(&static_key, 2); + + /* Add OID */ + buffer_t *buf = t_buffer_create(32); + test_assert(dcrypt_name2oid(curve, buf, NULL)); + item = array_append_space(&static_key); + item->parameter = buf->data; + item->len = buf->used; + + /* Add key data */ + item = array_append_space(&static_key); + item->parameter = priv_key_data; + item->len = sizeof(priv_key_data); + + /* Try load it */ + test_assert(dcrypt_key_load_private_raw(&pair.priv, t, + &static_key, NULL)); + + /* See what we got */ + buf = t_buffer_create(128); + test_assert(dcrypt_key_store_private(pair.priv, DCRYPT_FORMAT_DOVECOT, + NULL, buf, NULL, NULL, NULL)); + test_assert_strcmp(str_c(buf), + "2:1.2.840.10045.3.1.7:0:00000020169e6236af9cae0e71d" + "af263e2e05df1d5358c2b68f02a69c45d3d1cdea19bd3:21d11" + "6b7b3e5c52e81f0437a10b0116cfafc467fb1b96e48926d0216" + "68fc1bea"); + + /* try to load public key, too */ + const unsigned char pub_key_data[] = { + 0x04, 0xe8, 0x7c, 0x6d, 0xa0, 0x29, 0xfe, 0x5d, 0x16, 0x1a, + 0xd6, 0x6a, 0xc6, 0x1c, 0x78, 0x8a, 0x36, 0x0f, 0xfb, 0x64, + 0xe7, 0x7f, 0x58, 0x13, 0xb3, 0x80, 0x1f, 0x99, 0x45, 0xee, + 0xa9, 0x4a, 0xe2, 0xde, 0xf3, 0x88, 0xc6, 0x37, 0x72, 0x7f, + 0xbe, 0x97, 0x02, 0x94, 0xb2, 0x21, 0x60, 0xa4, 0x98, 0x4e, + 0xfb, 0x46, 0x19, 0x61, 0x4c, 0xc5, 0xe1, 0x9f, 0xe9, 0xb2, + 0xd2, 0x4d, 0xae, 0x83, 0x4b + }; + + array_clear(&static_key); + + /* Add OID */ + buf = t_buffer_create(32); + test_assert(dcrypt_name2oid(curve, buf, NULL)); + item = array_append_space(&static_key); + item->parameter = buf->data; + item->len = buf->used; + + /* Add key data */ + item = array_append_space(&static_key); + item->parameter = pub_key_data; + item->len = sizeof(pub_key_data); + + /* See what we got */ + test_assert(dcrypt_key_load_public_raw(&pair.pub, t, + &static_key, NULL)); + buf = t_buffer_create(128); + test_assert(dcrypt_key_store_public(pair.pub, DCRYPT_FORMAT_DOVECOT, + buf, NULL)); + test_assert_strcmp(str_c(buf), + "2:3039301306072a8648ce3d020106082a8648ce3d03010703220003e87c6d" + "a029fe5d161ad66ac61c788a360ffb64e77f5813b3801f9945eea94ae2:21d" + "116b7b3e5c52e81f0437a10b0116cfafc467fb1b96e48926d021668fc1bea"); + dcrypt_keypair_unref(&pair); + + test_end(); +} + +static void test_sign_verify_rsa(void) +{ + const char *error = NULL; + bool valid; + struct dcrypt_private_key *priv_key = NULL; + struct dcrypt_public_key *pub_key = NULL; + + buffer_t *signature = + buffer_create_dynamic(pool_datastack_create(), 128); + const char *data = "signed data"; + + test_begin("sign and verify (rsa)"); + const char *key = "-----BEGIN PRIVATE KEY-----\n" +"MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBALz2rTYj017MEtD6\n" +"i2flctgTtL4awpTPn2iCvjkMD/owj2N7LRbnpJ5ZDUUkPW8OEDH9NEEx86aFwg+w\n" +"GNzmxqRg5rA92iKouM4iU76IfCdtuYu4yyq57T2+C9mwqO5OvYXkM4VBjjcGr813\n" +"7huMcki104znz7HADYj/y8Nu0jyPAgMBAAECgYEAkJStMx92OrIqM3t/7p7AoFNz\n" +"l4EiIHo7ndtrcHqqPuOo0pUMitnyOrYoUR7JYo+AFL+Hm9p8co0lTpuOanaoxQk8\n" +"Hs9MDzvp4OjRyr0+mVSqKGJOVckXA1Bi0X6jbtOjm3bn7mp1ICPrnv6VB8VP1ef1\n" +"/NgcOai1RHEfXQWAWQECQQD7s3LqUFN5vdYuc/RQ98/NAuKUSvy7zU8tZ7r1Ea2w\n" +"RoxAcakc6Xh75u+9VhsbVyDHDEjWbTW5H2uqkPeotR2tAkEAwDDpS83xH6ilhNnP\n" +"Cors2WKKXZBkw+ZczThJXWIWrbo0zrTDYWYeo46HQRulJawW0iDEkVahk62uC7Go\n" +"Im5SqwJAXcShd/dK0dzOEOozx4I6kPaVMIerFc/Lwm+Vb70RRs1RbKSrStETiJ0l\n" +"DRUp7gqMdHr4G6H91KSG+Lke+mPW1QJAdG8tZ5dktWFepZWvMRvpUem5GeYYpfYx\n" +"0sJ+7+w1ARsGUxSAKcnMVhpLJs6wxpnzWWowrDxntyhJgRwoWHOt8QJBAPuX7gGH\n" +"Lxm7PpWgYYhnAiHGQmsiYEWZpTDHw3qODbSyANFjAKgaQZ3sHy4gdksmhbNJK60e\n" +"K7mLk9hTLlVPXJM=\n" +"-----END PRIVATE KEY-----"; + + test_assert(dcrypt_key_load_private(&priv_key, + key, NULL, NULL, &error)); + if (priv_key == NULL) + i_fatal("%s", error); + dcrypt_key_convert_private_to_public(priv_key, &pub_key); + test_assert(dcrypt_sign(priv_key, "sha256", DCRYPT_SIGNATURE_FORMAT_DSS, + data, strlen(data), signature, 0, &error)); + /* verify signature */ + test_assert(dcrypt_verify(pub_key, "sha256", DCRYPT_SIGNATURE_FORMAT_DSS, + data, strlen(data), + signature->data, signature->used, &valid, 0, &error) && valid); + + dcrypt_key_unref_public(&pub_key); + dcrypt_key_unref_private(&priv_key); + + test_end(); +} + +static void test_sign_verify_ecdsa(void) +{ + const char *error = NULL; + bool valid; + struct dcrypt_private_key *priv_key = NULL; + struct dcrypt_public_key *pub_key = NULL; + + buffer_t *signature = + buffer_create_dynamic(pool_datastack_create(), 128); + const char *data = "signed data"; + + test_begin("sign and verify (ecdsa)"); + const char *key = "-----BEGIN PRIVATE KEY-----\n" +"MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgZ4AMMyJ9XDl5lKM2\n" +"vusbT1OQ6VzBWBkB3/4syovaKtyhRANCAAQHTR+6L2qMh5fdcMZF+Y1rctBsq8Oy\n" +"7jZ4uV+MiuaoGNQ5sTxlcv6ETX/XrEDq4S/DUhFKzQ6u9VXYZImvRCT1\n" +"-----END PRIVATE KEY-----"; + + test_assert(dcrypt_key_load_private(&priv_key, + key, NULL, NULL, &error)); + if (priv_key == NULL) + i_fatal("%s", error); + dcrypt_key_convert_private_to_public(priv_key, &pub_key); + test_assert(dcrypt_sign(priv_key, "sha256", DCRYPT_SIGNATURE_FORMAT_DSS, + data, strlen(data), signature, 0, &error)); + /* verify signature */ + test_assert(dcrypt_verify(pub_key, "sha256", DCRYPT_SIGNATURE_FORMAT_DSS, + data, strlen(data), signature->data, + signature->used, &valid, 0, &error) && valid); + + dcrypt_key_unref_public(&pub_key); + dcrypt_key_unref_private(&priv_key); + + test_end(); +} + +static void test_static_verify_ecdsa(void) +{ + test_begin("static verify (ecdsa)"); + const char *input = "hello, world"; + const char *priv_key_pem = + "-----BEGIN PRIVATE KEY-----\n" + "MGcCAQAwEwYHKoZIzj0CAQYIKoZIzj0DAQcETTBLAgEBBCC25AkD65uhlZXCAdwN\n" + "yLJV2ui8A/CUyqyEMrezvwgMO6EkAyIAAybRUR3MsH0+0PQcDwkrXOJ9aePwzTQV\n" + "DN51+n1JCxbI\n" + "-----END PRIVATE KEY-----"; + const char *pub_key_pem = + "-----BEGIN PUBLIC KEY-----\n" + "MDkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDIgADJtFRHcywfT7Q9BwPCStc4n1p4/DN\n" + "NBUM3nX6fUkLFsg=\n" + "-----END PUBLIC KEY-----"; + + const unsigned char sig[] = { + 0x30,0x45,0x02,0x20,0x2c,0x76,0x20,0x5e,0xfc,0xa6,0x9e,0x16, + 0x44,0xb3,0xbc,0xbf,0xcc,0x43,0xc1,0x08,0x76,0x4a,0xe8,0x60, + 0xc5,0x9b,0x99,0x20,0x5b,0x44,0x33,0x5c,0x38,0x84,0x63,0xcb, + 0x02,0x21,0x00,0xa3,0x67,0xed,0x57,0xbf,0x59,0x46,0xb7,0x0c, + 0x7b,0xec,0x4f,0x78,0x14,0xec,0xfa,0x8d,0xa2,0x85,0x48,0xea, + 0xe1,0xaf,0x9e,0xbf,0x04,0xac,0x0e,0x41,0xfe,0x84,0x0e + }; + + struct dcrypt_keypair pair; + bool valid; + const char *error; + + i_zero(&pair); + /* static key test */ + test_assert(dcrypt_key_load_public(&pair.pub, pub_key_pem, NULL)); + test_assert(dcrypt_key_load_private(&pair.priv, priv_key_pem, NULL, NULL, NULL)); + /* validate signature */ + test_assert(dcrypt_verify(pair.pub, "sha256", DCRYPT_SIGNATURE_FORMAT_DSS, + input, strlen(input), + sig, sizeof(sig), &valid, 0, &error) && + valid == TRUE); + + dcrypt_keypair_unref(&pair); + + test_end(); +} + +static void test_jwk_keys(void) +{ + /* Make sure this matches what comes out from store private */ + const char *jwk_key_json = "{\"kty\":\"EC\"," + "\"crv\":\"P-256\"," + "\"x\":\"Kp0Y4-Wpt-D9t_2XenFIj0LmvaZByLG69yOisek4aMI\"," + "\"y\":\"wjEPB5BhH5SRPw1cCN5grWrLCphrW19fCFR8p7c9O5o\"," + "\"use\":\"sig\"," + "\"kid\":\"123\"," + "\"d\":\"Po2z9rs86J2Qb_xWprr4idsWNPlgKf3G8-mftnE2ync\"}"; + /* Acquired using another tool */ + const char *pem_key = + "-----BEGIN PUBLIC KEY-----\n" + "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEKp0Y4+Wpt+D9t/2XenFIj0LmvaZB\n" + "yLG69yOisek4aMLCMQ8HkGEflJE/DVwI3mCtassKmGtbX18IVHyntz07mg==\n" + "-----END PUBLIC KEY-----"; + test_begin("test_jwk_keys"); + struct dcrypt_keypair pair; + buffer_t *pem = t_buffer_create(256); + i_zero(&pair); + + test_assert(dcrypt_key_load_public(&pair.pub, jwk_key_json, NULL)); + test_assert(dcrypt_key_load_private(&pair.priv, jwk_key_json, NULL, NULL, NULL)); + + /* test accessors */ + test_assert_strcmp(dcrypt_key_get_id_public(pair.pub), "123"); + test_assert(dcrypt_key_get_usage_public(pair.pub) == DCRYPT_KEY_USAGE_SIGN); + + /* make sure we got the right key */ + test_assert(dcrypt_key_store_public(pair.pub, DCRYPT_FORMAT_PEM, pem, NULL)); + test_assert_strcmp(str_c(pem), pem_key); + + str_truncate(pem, 0); + test_assert(dcrypt_key_store_private(pair.priv, DCRYPT_FORMAT_JWK, NULL, pem, NULL, NULL, NULL)); + test_assert_strcmp(str_c(pem), jwk_key_json); + + dcrypt_keypair_unref(&pair); + + test_end(); +} + +static void test_static_verify_rsa(void) +{ + const char *error = NULL; + bool valid; + struct dcrypt_public_key *pub_key = NULL; + + test_begin("static verify (rsa)"); + const char *data = "test signature input\n"; + const unsigned char sig[] = { + 0x6f,0x1b,0xfb,0xdd,0xdb,0xb1,0xcd,0x6f,0xf1,0x1b, + 0xb8,0xad,0x71,0x75,0x6c,0x87,0x22,0x11,0xe4,0xc3, + 0xe7,0xca,0x15,0x04,0xda,0x98,0xab,0x07,0x27,0xcc, + 0x5a,0x4d,0xab,0xac,0x37,0x7a,0xff,0xd2,0xdf,0x37, + 0x58,0x37,0x53,0x46,0xd5,0x6d,0x9d,0x73,0x83,0x90, + 0xea,0x5e,0x2c,0xc7,0x51,0x9e,0xc4,0xda,0xc5,0x7d, + 0xa5,0xcd,0xb7,0xd7,0x41,0x23,0x6d,0xb9,0x6d,0xe0, + 0x99,0xa1,0x63,0x6b,0x60,0x5f,0x15,0x5b,0xda,0x21, + 0x17,0x4c,0x37,0x68,0x67,0x7f,0x8e,0x02,0x93,0xd2, + 0x86,0xdd,0xe5,0xa7,0xc3,0xd9,0x93,0x8b,0x0c,0x56, + 0x1d,0x5c,0x60,0x63,0x3e,0x8b,0xbe,0x1f,0xb2,0xe7, + 0x7f,0xe5,0x66,0x6f,0xcd,0x2b,0x0c,0x02,0x2a,0x12, + 0x96,0x86,0x66,0x00,0xff,0x12,0x8a,0x79 + }; + const char *key = "-----BEGIN PUBLIC KEY-----\n" +"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC89q02I9NezBLQ+otn5XLYE7S+\n" +"GsKUz59ogr45DA/6MI9jey0W56SeWQ1FJD1vDhAx/TRBMfOmhcIPsBjc5sakYOaw\n" +"PdoiqLjOIlO+iHwnbbmLuMsque09vgvZsKjuTr2F5DOFQY43Bq/Nd+4bjHJItdOM\n" +"58+xwA2I/8vDbtI8jwIDAQAB\n" +"-----END PUBLIC KEY-----"; + + test_assert(dcrypt_key_load_public(&pub_key, key, &error)); + if (pub_key == NULL) + i_fatal("%s", error); + test_assert(dcrypt_verify(pub_key, "sha256", DCRYPT_SIGNATURE_FORMAT_DSS, + data, strlen(data), + sig, sizeof(sig), &valid, DCRYPT_PADDING_RSA_PKCS1, &error) && + valid); + dcrypt_key_unref_public(&pub_key); + + test_end(); +} + +/* Sample values from RFC8292 */ +static void test_static_verify_ecdsa_x962(void) +{ + const char *error = NULL; + bool valid; + struct dcrypt_public_key *pub_key = NULL; + + test_begin("static verify (ecdsa x9.62)"); + const char *data = + "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiJ9.eyJhdWQiOiJodHRwczovL3B1c" + "2guZXhhbXBsZS5uZXQiLCJleHAiOjE0NTM1MjM3NjgsInN1YiI6Im1haWx0bzp" + "wdXNoQGV4YW1wbGUuY29tIn0"; + const unsigned char sig[] = { + 0x8b,0x70,0x98,0x6f,0xbb,0x78,0xc5,0xfc,0x42,0x0e,0xab, + 0xa9,0xb4,0x53,0x9e,0xa4,0x2f,0x46,0x02,0xef,0xc7,0x2c, + 0x69,0x0c,0x94,0xcb,0x82,0x19,0x22,0xb6,0xae,0x98,0x94, + 0x7e,0x72,0xbd,0xa2,0x31,0x70,0x0d,0x76,0xf5,0x26,0xb1, + 0x2b,0xb6,0x6c,0xac,0x6b,0x33,0x63,0x8e,0xf5,0xb6,0x2f, + 0xd3,0xa4,0x49,0x21,0xf3,0xbe,0x80,0xf5,0xa0 + }; + const char *key = +"-----BEGIN PUBLIC KEY-----\n" +"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEDUfHPKLVFQzVvnCPGyfucbECzPDa\n" +"7rWbXriLcysAjEcXpgrmHhINiJz51G5T9EI8J8Dlqr2iNLCTljYSYKUE+w==\n" +"-----END PUBLIC KEY-----"; + + test_assert(dcrypt_key_load_public(&pub_key, key, &error)); + if (pub_key == NULL) + i_fatal("%s", error); + test_assert(dcrypt_verify(pub_key, "sha256", DCRYPT_SIGNATURE_FORMAT_X962, + data, strlen(data), + sig, sizeof(sig), &valid, DCRYPT_PADDING_RSA_PKCS1, &error) && + valid); + dcrypt_key_unref_public(&pub_key); + + test_end(); +} + + +int main(void) +{ + struct dcrypt_settings set = { + .module_dir = ".libs" + }; + const char *error; + + if (!dcrypt_initialize(NULL, &set, &error)) { + i_error("No functional dcrypt backend found - " + "skipping tests: %s", error); + return 0; + } + + static void (*const test_functions[])(void) = { + test_cipher_test_vectors, + test_cipher_aead_test_vectors, + test_hmac_test_vectors, + test_load_v1_keys, + test_load_v1_key, + test_load_v1_public_key, + test_load_v2_key, + test_load_v2_public_key, + test_get_info_v2_key, + test_gen_and_get_info_rsa_pem, + test_get_info_rsa_private_key, + test_get_info_invalid_keys, + test_get_info_key_encrypted, + test_get_info_pw_encrypted, + test_password_change, + test_load_invalid_keys, + test_raw_keys, + test_jwk_keys, + test_sign_verify_rsa, + test_sign_verify_ecdsa, + test_static_verify_ecdsa, + test_static_verify_rsa, + test_static_verify_ecdsa_x962, + NULL + }; + + int ret = test_run(test_functions); + + dcrypt_deinitialize(); + + return ret; +} |