From: Aki Tuomi Date: Thu, 7 Dec 2023 09:40:18 +0000 (+0200) Subject: lib-dcrypt: Support ED448 and ED25519 signatures X-Git-Tag: 2.4.0~1830 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0fa4382844bccb599b651aeb36fed6dfe1870568;p=thirdparty%2Fdovecot%2Fcore.git lib-dcrypt: Support ED448 and ED25519 signatures --- diff --git a/src/lib-dcrypt/dcrypt-openssl1.c b/src/lib-dcrypt/dcrypt-openssl1.c index da603ff6be..1a5ccf2cb7 100644 --- a/src/lib-dcrypt/dcrypt-openssl1.c +++ b/src/lib-dcrypt/dcrypt-openssl1.c @@ -124,6 +124,8 @@ # define HAVE_X25519 # define IS_XD_CURVE(nid) \ ((nid) == NID_X25519 || (nid) == NID_X448) +# define IS_ED_CURVE(nid) \ + ((nid) == NID_ED25519 || (nid) == NID_ED448) #endif struct dcrypt_context_symmetric { @@ -1029,9 +1031,8 @@ dcrypt_openssl_generate_keypair(struct dcrypt_keypair *pair_r, return FALSE; } #ifdef HAVE_X25519 - if (IS_XD_CURVE(nid)) { - if (!dcrypt_openssl_generate_xd_key(nid, &pkey, - error_r)) + if (IS_XD_CURVE(nid) || IS_ED_CURVE(nid)) { + if (!dcrypt_openssl_generate_xd_key(nid, &pkey, error_r)) return dcrypt_openssl_error(error_r); } else #endif @@ -1471,7 +1472,7 @@ dcrypt_openssl_load_private_key_dovecot_v2(struct dcrypt_private_key **key_r, (*key_r)->key = pkey; (*key_r)->ref++; #ifdef HAVE_X25519 - } else if (IS_XD_CURVE(nid)) { + } else if (IS_XD_CURVE(nid) || IS_ED_CURVE(nid)) { size_t len; const unsigned char *ptr = buffer_get_data(key_data, &len); EVP_PKEY *pkey = @@ -3094,7 +3095,7 @@ dcrypt_openssl_private_to_public_key(struct dcrypt_private_key *priv_key, EVP_PKEY_set1_RSA(pk, rsa); RSA_free(rsa); #ifdef HAVE_X25519 - } else if (IS_XD_CURVE(nid)) { + } else if (IS_XD_CURVE(nid) || IS_ED_CURVE(nid)) { unsigned char buffer[128]; size_t len = 128; EVP_PKEY_get_raw_public_key(pkey, buffer, &len); @@ -3727,6 +3728,12 @@ dcrypt_openssl_sign(struct dcrypt_private_key *key, const char *algorithm, return FALSE; } +#ifdef HAVE_X25519 + if (EVP_PKEY_base_id(key->key) == NID_ED25519 || + EVP_PKEY_base_id(key->key) == NID_ED448) + md = NULL; +#endif + dctx = EVP_MD_CTX_create(); /* NB! Padding is set only on RSA signatures @@ -3845,6 +3852,12 @@ dcrypt_openssl_verify(struct dcrypt_public_key *key, const char *algorithm, return FALSE; } +#ifdef HAVE_X25519 + if (EVP_PKEY_base_id(key->key) == NID_ED25519 || + EVP_PKEY_base_id(key->key) == NID_ED448) + md = NULL; +#endif + dctx = EVP_MD_CTX_create(); /* NB! Padding is set only on RSA signatures diff --git a/src/lib-dcrypt/dcrypt-openssl3.c b/src/lib-dcrypt/dcrypt-openssl3.c index e230568376..3f9842cb15 100644 --- a/src/lib-dcrypt/dcrypt-openssl3.c +++ b/src/lib-dcrypt/dcrypt-openssl3.c @@ -96,7 +96,10 @@ 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; @@ -1086,9 +1089,8 @@ dcrypt_openssl_generate_keypair(struct dcrypt_keypair *pair_r, *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)) { @@ -1477,9 +1479,10 @@ dcrypt_openssl_load_private_key_dovecot_v2(struct dcrypt_private_key **key_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); @@ -2665,7 +2668,8 @@ dcrypt_openssl_store_private_key_dovecot(struct dcrypt_private_key *key, 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, @@ -3305,7 +3309,7 @@ dcrypt_openssl_private_key_type(struct dcrypt_private_key *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(); } @@ -3318,7 +3322,7 @@ dcrypt_openssl_public_key_type(struct dcrypt_public_key *key) 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(); } @@ -3521,6 +3525,9 @@ dcrypt_openssl_sign(struct dcrypt_private_key *key, const char *algorithm, 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; @@ -3594,10 +3601,16 @@ dcrypt_openssl_verify(struct dcrypt_public_key *key, const char *algorithm, 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, diff --git a/src/lib-dcrypt/test-crypto.c b/src/lib-dcrypt/test-crypto.c index 3b21d9ac45..ff86cd0925 100644 --- a/src/lib-dcrypt/test-crypto.c +++ b/src/lib-dcrypt/test-crypto.c @@ -1725,6 +1725,131 @@ static void test_static_verify_ecdsa_x962(void) } #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"); @@ -1821,6 +1946,10 @@ int main(void) 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