From: Dan Streetman Date: Fri, 7 Jul 2023 14:11:07 +0000 (-0400) Subject: openssl: add ecc_edch() X-Git-Tag: v255-rc1~389^2~1 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=779b80d8039ae3925ce6a52f97f9d53586ae931e;p=thirdparty%2Fsystemd.git openssl: add ecc_edch() Add function to perform ECC EDCH. --- diff --git a/src/shared/openssl-util.c b/src/shared/openssl-util.c index 58e4ab02e9e..0015aa5b98c 100644 --- a/src/shared/openssl-util.c +++ b/src/shared/openssl-util.c @@ -894,6 +894,48 @@ int ecc_pkey_new(int curve_id, EVP_PKEY **ret) { return 0; } +/* Perform ECDH to derive an ECC shared secret between the provided private key and public peer key. For two + * keys, this will result in the same shared secret in either direction; ECDH using Alice's private key and + * Bob's public (peer) key will result in the same shared secret as ECDH using Bob's private key and Alice's + * public (peer) key. On success, this returns 0 and provides the shared secret; otherwise this returns an + * error. */ +int ecc_ecdh(const EVP_PKEY *private_pkey, + const EVP_PKEY *peer_pkey, + void **ret_shared_secret, + size_t *ret_shared_secret_size) { + + assert(private_pkey); + assert(peer_pkey); + assert(ret_shared_secret); + assert(ret_shared_secret_size); + + _cleanup_(EVP_PKEY_CTX_freep) EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new((EVP_PKEY*) private_pkey, NULL); + if (!ctx) + return log_openssl_errors("Failed to create new EVP_PKEY_CTX"); + + if (EVP_PKEY_derive_init(ctx) <= 0) + return log_openssl_errors("Failed to initialize EVP_PKEY_CTX"); + + if (EVP_PKEY_derive_set_peer(ctx, (EVP_PKEY*) peer_pkey) <= 0) + return log_openssl_errors("Failed to set ECC derive peer"); + + size_t shared_secret_size; + if (EVP_PKEY_derive(ctx, NULL, &shared_secret_size) <= 0) + return log_openssl_errors("Failed to get ECC shared secret size"); + + _cleanup_free_ void *shared_secret = malloc(shared_secret_size); + if (!shared_secret) + return log_oom_debug(); + + if (EVP_PKEY_derive(ctx, (unsigned char*) shared_secret, &shared_secret_size) <= 0) + return log_openssl_errors("Failed to derive ECC shared secret"); + + *ret_shared_secret = TAKE_PTR(shared_secret); + *ret_shared_secret_size = shared_secret_size; + + return 0; +} + int pubkey_fingerprint(EVP_PKEY *pk, const EVP_MD *md, void **ret, size_t *ret_size) { _cleanup_(EVP_MD_CTX_freep) EVP_MD_CTX* m = NULL; _cleanup_free_ void *d = NULL, *h = NULL; diff --git a/src/shared/openssl-util.h b/src/shared/openssl-util.h index 9715545c1fb..a06ad5b388b 100644 --- a/src/shared/openssl-util.h +++ b/src/shared/openssl-util.h @@ -104,6 +104,8 @@ int ecc_pkey_to_curve_x_y(const EVP_PKEY *pkey, int *ret_curve_id, void **ret_x, int ecc_pkey_new(int curve_id, EVP_PKEY **ret); +int ecc_ecdh(const EVP_PKEY *private_pkey, const EVP_PKEY *peer_pkey, void **ret_shared_secret, size_t *ret_shared_secret_size); + int pubkey_fingerprint(EVP_PKEY *pk, const EVP_MD *md, void **ret, size_t *ret_size); int digest_and_sign(const EVP_MD *md, EVP_PKEY *privkey, const void *data, size_t size, void **ret, size_t *ret_size); diff --git a/src/test/test-openssl.c b/src/test/test-openssl.c index cb25b7a9c3e..586c090c030 100644 --- a/src/test/test-openssl.c +++ b/src/test/test-openssl.c @@ -424,4 +424,23 @@ TEST(openssl_cipher) { /* expected= */ NULL); } +TEST(ecc_ecdh) { + _cleanup_(EVP_PKEY_freep) EVP_PKEY *pkeyA = NULL, *pkeyB = NULL, *pkeyC = NULL; + _cleanup_free_ void *secretAB = NULL, *secretBA = NULL, *secretAC = NULL, *secretCA = NULL; + size_t secretAB_size, secretBA_size, secretAC_size, secretCA_size; + + assert_se(ecc_pkey_new(NID_X9_62_prime256v1, &pkeyA) >= 0); + assert_se(ecc_pkey_new(NID_X9_62_prime256v1, &pkeyB) >= 0); + assert_se(ecc_pkey_new(NID_X9_62_prime256v1, &pkeyC) >= 0); + + assert_se(ecc_ecdh(pkeyA, pkeyB, &secretAB, &secretAB_size) >= 0); + assert_se(ecc_ecdh(pkeyB, pkeyA, &secretBA, &secretBA_size) >= 0); + assert_se(ecc_ecdh(pkeyA, pkeyC, &secretAC, &secretAC_size) >= 0); + assert_se(ecc_ecdh(pkeyC, pkeyA, &secretCA, &secretCA_size) >= 0); + + assert_se(memcmp_nn(secretAB, secretAB_size, secretBA, secretBA_size) == 0); + assert_se(memcmp_nn(secretAC, secretAC_size, secretCA, secretCA_size) == 0); + assert_se(memcmp_nn(secretAC, secretAC_size, secretAB, secretAB_size) != 0); +} + DEFINE_TEST_MAIN(LOG_DEBUG);