ERR_get_error_line_data(NULL, NULL, data, flags)
#endif
-#define IS_XD_CURVE(nid) ((nid) == NID_X25519 || (nid) == NID_X448)
+#define IS_XD_CURVE(nid) \
+ ((nid) == NID_X25519 || (nid) == NID_X448)
+#define IS_ED_CURVE(nid) \
+ ((nid) == NID_ED25519 || (nid) == NID_ED448)
struct dcrypt_context_symmetric {
pool_t pool;
*error_r = t_strdup_printf("Unknown EC curve %s", curve);
return FALSE;
}
- if (IS_XD_CURVE(nid)) {
- if (!dcrypt_openssl_generate_xd_key(curve, &pkey,
- error_r))
+ if (IS_XD_CURVE(nid) || IS_ED_CURVE(nid)) {
+ if (!dcrypt_openssl_generate_xd_key(curve, &pkey, error_r))
return dcrypt_openssl_error(error_r);
} else if (!dcrypt_openssl_generate_ec_key(nid, &pkey,
error_r)) {
*key_r = i_new(struct dcrypt_private_key, 1);
(*key_r)->key = pkey;
(*key_r)->ref++;
- } else if (IS_XD_CURVE(nid)) {
- EVP_PKEY *pkey = EVP_PKEY_new_raw_private_key(
- nid, NULL, key_data->data, key_data->used);
+ } else if (IS_XD_CURVE(nid) || IS_ED_CURVE(nid)) {
+ EVP_PKEY *pkey =
+ EVP_PKEY_new_raw_private_key(nid, NULL, key_data->data,
+ key_data->used);
if (pkey == NULL)
return dcrypt_openssl_error(error_r);
ptr = buffer_append_space_unsafe(buf, len);
BN_bn2mpi(pk, ptr);
BN_free(pk);
- } else if (IS_XD_CURVE(EVP_PKEY_base_id(pkey))) {
+ } else if (IS_XD_CURVE(EVP_PKEY_base_id(pkey)) ||
+ IS_ED_CURVE(EVP_PKEY_base_id(pkey))) {
size_t len;
unsigned char *ptr = buffer_append_space_unsafe(buf, 64);
EVP_PKEY_get_octet_string_param(pkey, OSSL_PKEY_PARAM_PRIV_KEY,
int id = EVP_PKEY_base_id(priv);
if (id == EVP_PKEY_RSA)
return DCRYPT_KEY_RSA;
- else if (id == EVP_PKEY_EC || IS_XD_CURVE(id))
+ else if (id == EVP_PKEY_EC || IS_XD_CURVE(id) || IS_ED_CURVE(id))
return DCRYPT_KEY_EC;
else i_unreached();
}
int id = EVP_PKEY_base_id(pub);
if (id == EVP_PKEY_RSA)
return DCRYPT_KEY_RSA;
- else if (id == EVP_PKEY_EC || IS_XD_CURVE(id))
+ else if (id == EVP_PKEY_EC || IS_XD_CURVE(id) || IS_ED_CURVE(id))
return DCRYPT_KEY_EC;
else i_unreached();
}
if (pad == -1)
return FALSE;
+ if (IS_ED_CURVE(EVP_PKEY_base_id(key->key)))
+ algorithm = NULL;
+
EVP_MD_CTX *dctx = EVP_MD_CTX_create();
/* do not preallocate - will cause memory leak */
EVP_PKEY_CTX *pctx = NULL;
if (pad == -1)
return FALSE;
+ if (IS_ED_CURVE(EVP_PKEY_base_id(key->key)))
+ algorithm = NULL;
+
EVP_MD_CTX *dctx = EVP_MD_CTX_create();
/* do not preallocate, causes memory leak */
EVP_PKEY_CTX *pctx = NULL;
+ if (IS_ED_CURVE(EVP_PKEY_base_id(key->key)))
+ algorithm = NULL;
+
/* NB! Padding is set only on RSA signatures
ECDSA signatures use whatever is default */
if (EVP_DigestVerifyInit_ex(dctx, &pctx, algorithm, NULL, NULL,
}
#ifdef HAVE_X25519
+static void test_sign_verify_ed25519(void)
+{
+ const char *error = NULL;
+ bool valid, ret;
+ struct dcrypt_keypair pair;
+ buffer_t *signature =
+ buffer_create_dynamic(pool_datastack_create(), 128);
+ const char *data = "signed data";
+
+ test_begin("sign and verify (ed25519)");
+
+ ret = dcrypt_keypair_generate(&pair, DCRYPT_KEY_EC, 0, "ED25519", &error);
+ if (!ret)
+ i_panic("%s", error);
+
+ test_assert(dcrypt_sign(pair.priv, "sha256", DCRYPT_SIGNATURE_FORMAT_DSS,
+ data, strlen(data), signature, 0, &error));
+ /* verify signature */
+ test_assert(dcrypt_verify(pair.pub, "sha256", DCRYPT_SIGNATURE_FORMAT_DSS,
+ data, strlen(data),
+ signature->data, signature->used, &valid, 0, &error) && valid);
+
+ dcrypt_keypair_unref(&pair);
+
+ test_end();
+}
+
+static void test_static_verify_ed25519(void)
+{
+ const char *error = NULL;
+ bool valid, ret;
+ struct dcrypt_public_key *pub;
+ const char *data = "signed data";
+ const unsigned char sig[] = {
+ 0xf6,0xc5,0xf9,0x6e,0x6c,0x42,0x6d,0xa8,0xbc,0x9f,0xc8,0xbe,
+ 0x87,0x17,0x38,0x40,0xd9,0x5b,0x4b,0xee,0xba,0x64,0x1a,0xba,
+ 0xb2,0xac,0x94,0x8c,0x25,0xd5,0x2b,0x1f,0x98,0x73,0x98,0x40,
+ 0x85,0x33,0xfa,0xb9,0x40,0xd6,0x75,0x61,0x29,0xaa,0xcb,0xf7,
+ 0x69,0xa4,0x93,0x21,0xa2,0x64,0x9b,0xc2,0xcd,0x62,0x95,0x42,
+ 0xea,0x93,0x6f,0x07,
+ };
+ const char *key =
+"-----BEGIN PUBLIC KEY-----\n"
+"MCowBQYDK2VwAyEAPfeu6ItbVmVPUV/nYYHvV/aVheD7iVUWO9/POgcCyYM=\n"
+"-----END PUBLIC KEY-----";
+ test_begin("static verify (ed25519)");
+
+ ret = dcrypt_key_load_public(&pub, key, &error);
+ if (!ret)
+ i_panic("%s", error);
+
+ /* verify signature */
+ test_assert(dcrypt_verify(pub, "sha256", DCRYPT_SIGNATURE_FORMAT_DSS,
+ data, strlen(data),
+ sig, sizeof(sig), &valid, 0, &error) && valid);
+ dcrypt_key_unref_public(&pub);
+
+ test_end();
+}
+
+static void test_static_verify_ed448(void)
+{
+ const char *error = NULL;
+ bool valid, ret;
+ struct dcrypt_public_key *pub;
+ const char *data = "signed data";
+ const unsigned char sig[] = {
+ 0x9d,0x90,0x9b,0xe9,0x40,0xf5,0xee,0x4e,0x42,0x34,0xa5,0x90,
+ 0x85,0x0d,0x6a,0xea,0x60,0xae,0xd2,0x49,0x39,0x5f,0x61,0x64,
+ 0x16,0x22,0x36,0xa4,0x14,0x8b,0x61,0x4e,0x4e,0xfa,0x74,0x45,
+ 0xcb,0xf8,0x8b,0x15,0xc1,0x59,0x99,0xaa,0x26,0x20,0x45,0x32,
+ 0x8a,0xa0,0xed,0x21,0xce,0x39,0xa4,0x06,0x00,0x75,0xb1,0x70,
+ 0x6e,0xe6,0xb6,0x89,0x94,0x72,0xcb,0x3a,0xe8,0x1d,0xaf,0x18,
+ 0x01,0xde,0x58,0xbe,0x1f,0x72,0x5b,0x0c,0xc4,0x98,0xfb,0xba,
+ 0x51,0x26,0x89,0x01,0xc3,0xea,0xa7,0xe6,0xb2,0xf6,0xe5,0xee,
+ 0xa2,0x5a,0x72,0x84,0xc4,0xfc,0x81,0x1f,0x48,0x45,0x9f,0xd1,
+ 0x44,0x1f,0x77,0x5c,0x3b,0x00,
+ };
+ const char *key =
+"-----BEGIN PUBLIC KEY-----\n"
+"MEMwBQYDK2VxAzoAnWMyXj/1VTCDWIyx0IKbezYsUI0dl80fAkQ3IK+U5+SqR2gw\n"
+"zhHZ7ewPFgiEiP/KY3qKLWJHSDcA\n"
+"-----END PUBLIC KEY-----";
+ test_begin("static verify (ed448)");
+
+ ret = dcrypt_key_load_public(&pub, key, &error);
+ if (!ret)
+ i_panic("%s", error);
+
+ /* verify signature */
+ test_assert(dcrypt_verify(pub, "sha256", DCRYPT_SIGNATURE_FORMAT_DSS,
+ data, strlen(data),
+ sig, sizeof(sig), &valid, 0, &error) && valid);
+ dcrypt_key_unref_public(&pub);
+
+ test_end();
+}
+
+static void test_sign_verify_ed448(void)
+{
+ const char *error = NULL;
+ bool valid, ret;
+ struct dcrypt_keypair pair;
+ buffer_t *signature =
+ buffer_create_dynamic(pool_datastack_create(), 128);
+ const char *data = "signed data";
+
+ test_begin("sign and verify (ed448)");
+
+ ret = dcrypt_keypair_generate(&pair, DCRYPT_KEY_EC, 0, "ED448", &error);
+ if (!ret)
+ i_panic("%s", error);
+
+ test_assert(dcrypt_sign(pair.priv, "sha256", DCRYPT_SIGNATURE_FORMAT_DSS,
+ data, strlen(data), signature, 0, &error));
+ /* verify signature */
+ test_assert(dcrypt_verify(pair.pub, "sha256", DCRYPT_SIGNATURE_FORMAT_DSS,
+ data, strlen(data),
+ signature->data, signature->used, &valid, 0, &error) && valid);
+
+ dcrypt_keypair_unref(&pair);
+
+ test_end();
+}
+
static void test_xd25519_keypair(void)
{
test_begin("X25519 key exchange");
test_static_verify_rsa,
test_static_verify_ecdsa_x962,
#ifdef HAVE_X25519
+ test_sign_verify_ed25519,
+ test_sign_verify_ed448,
+ test_static_verify_ed25519,
+ test_static_verify_ed448,
test_xd25519_keypair,
test_xd448_keypair,
#endif