From patchwork Tue May 10 01:30:55 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Arne Schwabe X-Patchwork-Id: 2442 Return-Path: Delivered-To: patchwork@openvpn.net Delivered-To: patchwork@openvpn.net Received: from director12.mail.ord1d.rsapps.net ([172.30.191.6]) by backend41.mail.ord1d.rsapps.net with LMTP id sHiHO0ZNemK2KwAAqwncew (envelope-from ) for ; Tue, 10 May 2022 07:32:22 -0400 Received: from proxy2.mail.ord1d.rsapps.net ([172.30.191.6]) by director12.mail.ord1d.rsapps.net with LMTP id +AHrFUdNemIqXQAAIasKDg (envelope-from ) for ; Tue, 10 May 2022 07:32:23 -0400 Received: from smtp37.gate.ord1c ([172.30.191.6]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) by proxy2.mail.ord1d.rsapps.net with LMTPS id yHRxFUdNemKkWgAAfawv4w (envelope-from ) for ; Tue, 10 May 2022 07:32:23 -0400 X-Spam-Threshold: 95 X-Spam-Score: 0 X-Spam-Flag: NO X-Virus-Scanned: OK X-Orig-To: openvpnslackdevel@openvpn.net X-Originating-Ip: [216.105.38.7] Authentication-Results: smtp37.gate.ord1c.rsapps.net; iprev=pass policy.iprev="216.105.38.7"; spf=pass smtp.mailfrom="openvpn-devel-bounces@lists.sourceforge.net" smtp.helo="lists.sourceforge.net"; dkim=fail (signature verification failed) header.d=sourceforge.net; dkim=fail (signature verification failed) header.d=sf.net; dmarc=none (p=nil; dis=none) header.from=rfc2549.org X-Suspicious-Flag: YES X-Classification-ID: db7885fe-d054-11ec-b19c-525400e8d833-1-1 Received: from [216.105.38.7] ([216.105.38.7:52044] helo=lists.sourceforge.net) by smtp37.gate.ord1c.rsapps.net (envelope-from ) (ecelerity 4.2.38.62370 r(:)) with ESMTPS (cipher=DHE-RSA-AES256-GCM-SHA384) id 15/A6-25020-64D4A726; Tue, 10 May 2022 07:32:22 -0400 Received: from [127.0.0.1] (helo=sfs-ml-4.v29.lw.sourceforge.com) by sfs-ml-4.v29.lw.sourceforge.com with esmtp (Exim 4.94.2) (envelope-from ) id 1noO5D-0001EH-0h; Tue, 10 May 2022 11:31:13 +0000 Received: from [172.30.20.202] (helo=mx.sourceforge.net) by sfs-ml-4.v29.lw.sourceforge.com with esmtps (TLS1.2) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1noO5A-0001EA-Tu for openvpn-devel@lists.sourceforge.net; Tue, 10 May 2022 11:31:11 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sourceforge.net; s=x; h=Content-Transfer-Encoding:MIME-Version:Message-Id: Date:Subject:To:From:Sender:Reply-To:Cc:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:In-Reply-To:References:List-Id:List-Help:List-Unsubscribe: List-Subscribe:List-Post:List-Owner:List-Archive; bh=a8CO++yimulwRGdzh2CToKfaFnT5TejgcyWp5v39HZ4=; b=P5a5dGkQckiFiTaCTpnOQVM0uk CntGCSkiGyXLw3lVGvEk0SPhBg5pIj1r0Iu17ddoNKkM4GmWqSKxj0ZHla0XGu2QO+/RYybKoaQ4Q QwW/+2j0R2vlRZFyydOFUYsuGiKb78ApR2PnH0n4te/26QX7ED6jp2DzEcP197lhqfXA=; DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sf.net; s=x ; h=Content-Transfer-Encoding:MIME-Version:Message-Id:Date:Subject:To:From: Sender:Reply-To:Cc:Content-Type:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:In-Reply-To: References:List-Id:List-Help:List-Unsubscribe:List-Subscribe:List-Post: List-Owner:List-Archive; bh=a8CO++yimulwRGdzh2CToKfaFnT5TejgcyWp5v39HZ4=; b=m UOma2oNBH6XgSrLYzZQ2OdepPfFzizVshtgHDwdf2xmMos0rxsn+Pk8va7Pu5UhzwZQK7kQKhmjp8 PsUQyEaa28w7KpiVwP+6/g9EljWVvtWzvXdll91zRBgeWZ8ZAcpPeaKKlHNHPwyuvpv58kKsbj+o1 rTs/PzRza4j0MGpQ=; Received: from mail.blinkt.de ([192.26.174.232]) by sfi-mx-2.v28.lw.sourceforge.com with esmtps (TLS1.2:ECDHE-RSA-AES256-GCM-SHA384:256) (Exim 4.94.2) id 1noO55-0003zB-DI for openvpn-devel@lists.sourceforge.net; Tue, 10 May 2022 11:31:11 +0000 Received: from kamera.blinkt.de ([2001:638:502:390:20c:29ff:fec8:535c]) by mail.blinkt.de with smtp (Exim 4.95 (FreeBSD)) (envelope-from ) id 1noO4u-000Hfa-CX for openvpn-devel@lists.sourceforge.net; Tue, 10 May 2022 13:30:56 +0200 Received: (nullmailer pid 1829312 invoked by uid 10006); Tue, 10 May 2022 11:30:55 -0000 From: Arne Schwabe To: openvpn-devel@lists.sourceforge.net Date: Tue, 10 May 2022 13:30:55 +0200 Message-Id: <20220510113055.1829260-1-arne@rfc2549.org> X-Mailer: git-send-email 2.25.1 MIME-Version: 1.0 X-Spam-Report: Spam detection software, running on the system "util-spamd-1.v13.lw.sourceforge.com", has NOT identified this incoming email as spam. The original message has been attached to this so you can view it or label similar future email. If you have any questions, see the administrator of that system for details. Content preview: OpenSSL's implementation of ED448 and ED25519 has a few idiosyncrasies. Instead of belonging to the eliptic curve type or to a common Edwards curve type, ED448 and ED25519 have each their own type. Also, OpenSSL excepts singatures using these curves to be done with the EVP_DigestSign API instead of the EVP_Sign API but using md=NULL. Content analysis details: (0.3 points, 6.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record 0.2 HEADER_FROM_DIFFERENT_DOMAINS From and EnvelopeFrom 2nd level mail domains are different 0.0 SPF_NONE SPF: sender does not publish an SPF Record X-Headers-End: 1noO55-0003zB-DI Subject: [Openvpn-devel] [PATCH] Implement ED448 and ED25519 support in xkey_provider X-BeenThere: openvpn-devel@lists.sourceforge.net X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: openvpn-devel-bounces@lists.sourceforge.net X-getmail-retrieved-from-mailbox: Inbox OpenSSL's implementation of ED448 and ED25519 has a few idiosyncrasies. Instead of belonging to the eliptic curve type or to a common Edwards curve type, ED448 and ED25519 have each their own type. Also, OpenSSL excepts singatures using these curves to be done with the EVP_DigestSign API instead of the EVP_Sign API but using md=NULL. This has been tested using a "fake" external key that used a normal software key instead of a hardware implementation but that makes no difference from the perspective of xkey_provider/managment interface. --- src/openvpn/xkey_helper.c | 4 + src/openvpn/xkey_provider.c | 121 +++++++++++++++++++++-- tests/unit_tests/openvpn/test_provider.c | 21 ++-- 3 files changed, 134 insertions(+), 12 deletions(-) diff --git a/src/openvpn/xkey_helper.c b/src/openvpn/xkey_helper.c index ecc7b1204..d59b16858 100644 --- a/src/openvpn/xkey_helper.c +++ b/src/openvpn/xkey_helper.c @@ -206,6 +206,10 @@ xkey_management_sign(void *unused, unsigned char *sig, size_t *siglen, openvpn_snprintf(alg_str, sizeof(alg_str), "ECDSA,hashalg=%s", alg.mdname); } } + else if(!strcmp(alg.keytype, "ED448") || !strcmp(alg.keytype, "ED25519")) + { + strncpynt(alg_str, alg.keytype, sizeof(alg_str)); + } /* else assume RSA key */ else if (!strcmp(alg.padmode, "pkcs1") && (flags & MF_EXTERNAL_KEY_PKCS1PAD)) { diff --git a/src/openvpn/xkey_provider.c b/src/openvpn/xkey_provider.c index 46e57e0fe..e8ac3904b 100644 --- a/src/openvpn/xkey_provider.c +++ b/src/openvpn/xkey_provider.c @@ -99,12 +99,28 @@ typedef struct int refcount; /**< reference count */ } XKEY_KEYDATA; -static int -KEYTYPE(const XKEY_KEYDATA *key) +static inline const char * +get_keytype(const XKEY_KEYDATA *key) { - return key->pubkey ? EVP_PKEY_get_id(key->pubkey) : 0; + int keytype = key->pubkey ? EVP_PKEY_get_id(key->pubkey) : 0; + + switch (keytype) + { + case EVP_PKEY_RSA: + return "RSA"; + + case EVP_PKEY_ED448: + return "ED448"; + + case EVP_PKEY_ED25519: + return "ED25519"; + + default: + return "EC"; + } } + static int KEYSIZE(const XKEY_KEYDATA *key) { @@ -310,6 +326,22 @@ ec_keymgmt_import(void *keydata, int selection, const OSSL_PARAM params[]) return keymgmt_import(keydata, selection, params, "EC"); } +static int +ed448_keymgmt_import(void *keydata, int selection, const OSSL_PARAM params[]) +{ + xkey_dmsg(D_XKEY, "entry"); + + return keymgmt_import(keydata, selection, params, "ED448"); +} + +static int +ed25519_keymgmt_import(void *keydata, int selection, const OSSL_PARAM params[]) +{ + xkey_dmsg(D_XKEY, "entry"); + + return keymgmt_import(keydata, selection, params, "ED25519"); +} + /* This function has to exist for key import to work * though we do not support import of individual params * like n or e. We simply return an empty list here for @@ -449,7 +481,7 @@ keymgmt_import_helper(XKEY_KEYDATA *key, const OSSL_PARAM *params) ASSERT(pkey); int id = EVP_PKEY_get_id(pkey); - if (id != EVP_PKEY_RSA && id != EVP_PKEY_EC) + if (id != EVP_PKEY_RSA && id != EVP_PKEY_EC && id != EVP_PKEY_ED25519 && id != EVP_PKEY_ED448) { msg(M_WARN, "Error: xkey keymgmt_import: unknown key type (%d)", id); return 0; @@ -556,6 +588,40 @@ ec_keymgmt_name(int id) return "EC"; } +static const char * +ed448_keymgmt_name(int id) +{ + xkey_dmsg(D_XKEY, "entry"); + + /* though we do not implement keyexch we could be queried for + * keyexch mechanism supported by EC keys + */ + if (id == OSSL_OP_SIGNATURE || id == OSSL_OP_KEYEXCH) + { + return "ED448"; + } + + msg(D_XKEY, "xkey ed448_keymgmt_name called with op_id != SIGNATURE or KEYEXCH id=%d", id); + return "EC"; +} + +static const char * +ed25519_keymgmt_name(int id) +{ + xkey_dmsg(D_XKEY, "entry"); + + /* though we do not implement keyexch we could be queried for + * keyexch mechanism supported by EC keys + */ + if (id == OSSL_OP_SIGNATURE || id == OSSL_OP_KEYEXCH) + { + return "ED25519"; + } + + msg(D_XKEY, "xkey ed448_keymgmt_name called with op_id != SIGNATURE or KEYEXCH id=%d", id); + return "EC"; +} + static const OSSL_DISPATCH rsa_keymgmt_functions[] = { {OSSL_FUNC_KEYMGMT_NEW, (void (*)(void))keymgmt_new}, {OSSL_FUNC_KEYMGMT_FREE, (void (*)(void))keymgmt_free}, @@ -588,10 +654,45 @@ static const OSSL_DISPATCH ec_keymgmt_functions[] = { {0, NULL } }; +static const OSSL_DISPATCH ed448_keymgmt_functions[] = { + {OSSL_FUNC_KEYMGMT_NEW, (void (*)(void))keymgmt_new}, + {OSSL_FUNC_KEYMGMT_FREE, (void (*)(void))keymgmt_free}, + {OSSL_FUNC_KEYMGMT_LOAD, (void (*)(void))keymgmt_load}, + {OSSL_FUNC_KEYMGMT_HAS, (void (*)(void))keymgmt_has}, + {OSSL_FUNC_KEYMGMT_MATCH, (void (*)(void))keymgmt_match}, + {OSSL_FUNC_KEYMGMT_IMPORT, (void (*)(void))ed448_keymgmt_import}, + {OSSL_FUNC_KEYMGMT_IMPORT_TYPES, (void (*)(void))keymgmt_import_types}, + {OSSL_FUNC_KEYMGMT_GETTABLE_PARAMS, (void (*)(void))keymgmt_gettable_params}, + {OSSL_FUNC_KEYMGMT_GET_PARAMS, (void (*)(void))keymgmt_get_params}, + {OSSL_FUNC_KEYMGMT_SET_PARAMS, (void (*)(void))keymgmt_set_params}, + {OSSL_FUNC_KEYMGMT_SETTABLE_PARAMS, (void (*)(void))keymgmt_gettable_params}, /* same as gettable */ + {OSSL_FUNC_KEYMGMT_QUERY_OPERATION_NAME, (void (*)(void))ed448_keymgmt_name}, + {0, NULL } +}; + +static const OSSL_DISPATCH ed25519_keymgmt_functions[] = { + {OSSL_FUNC_KEYMGMT_NEW, (void (*)(void))keymgmt_new}, + {OSSL_FUNC_KEYMGMT_FREE, (void (*)(void))keymgmt_free}, + {OSSL_FUNC_KEYMGMT_LOAD, (void (*)(void))keymgmt_load}, + {OSSL_FUNC_KEYMGMT_HAS, (void (*)(void))keymgmt_has}, + {OSSL_FUNC_KEYMGMT_MATCH, (void (*)(void))keymgmt_match}, + {OSSL_FUNC_KEYMGMT_IMPORT, (void (*)(void))ed25519_keymgmt_import}, + {OSSL_FUNC_KEYMGMT_IMPORT_TYPES, (void (*)(void))keymgmt_import_types}, + {OSSL_FUNC_KEYMGMT_GETTABLE_PARAMS, (void (*)(void))keymgmt_gettable_params}, + {OSSL_FUNC_KEYMGMT_GET_PARAMS, (void (*)(void))keymgmt_get_params}, + {OSSL_FUNC_KEYMGMT_SET_PARAMS, (void (*)(void))keymgmt_set_params}, + {OSSL_FUNC_KEYMGMT_SETTABLE_PARAMS, (void (*)(void))keymgmt_gettable_params}, /* same as gettable */ + {OSSL_FUNC_KEYMGMT_QUERY_OPERATION_NAME, (void (*)(void))ed25519_keymgmt_name}, + {0, NULL } +}; + + const OSSL_ALGORITHM keymgmts[] = { {"RSA:rsaEncryption", XKEY_PROV_PROPS, rsa_keymgmt_functions, "OpenVPN xkey RSA Key Manager"}, {"RSA-PSS:RSASSA-PSS", XKEY_PROV_PROPS, rsa_keymgmt_functions, "OpenVPN xkey RSA-PSS Key Manager"}, {"EC:id-ecPublicKey", XKEY_PROV_PROPS, ec_keymgmt_functions, "OpenVPN xkey EC Key Manager"}, + {"ED448", XKEY_PROV_PROPS, ed448_keymgmt_functions, "OpenVPN xkey ED448 Key Manager"}, + {"ED25519", XKEY_PROV_PROPS, ed25519_keymgmt_functions, "OpenVPN xkey ED25519 Key Manager"}, {NULL, NULL, NULL, NULL} }; @@ -835,7 +936,7 @@ signature_sign_init(void *ctx, void *provkey, const OSSL_PARAM params[]) } sctx->keydata = provkey; sctx->keydata->refcount++; /* we are keeping a copy */ - sctx->sigalg.keytype = KEYTYPE(sctx->keydata) == EVP_PKEY_RSA ? "RSA" : "EC"; + sctx->sigalg.keytype = get_keytype(sctx->keydata); signature_set_ctx_params(sctx, params); @@ -929,13 +1030,19 @@ signature_digest_sign_init(void *ctx, const char *mdname, } sctx->keydata = provkey; /* used by digest_sign */ sctx->keydata->refcount++; - sctx->sigalg.keytype = KEYTYPE(sctx->keydata) == EVP_PKEY_RSA ? "RSA" : "EC"; + sctx->sigalg.keytype = get_keytype(sctx->keydata); signature_set_ctx_params(ctx, params); if (mdname) { sctx->sigalg.mdname = xkey_mdname(mdname); /* get a string literal pointer */ } + else if (!strcmp(sctx->sigalg.keytype, "ED448") || !strcmp(sctx->sigalg.keytype, "ED25519")) + { + /* EdDSA requires NULL as digest for the DigestSign API instead + * of using the normal Sign API */ + sctx->sigalg.mdname = "none"; + } else { msg(M_WARN, "xkey digest_sign_init: mdname is NULL."); @@ -1073,6 +1180,8 @@ static const OSSL_DISPATCH signature_functions[] = { const OSSL_ALGORITHM signatures[] = { {"RSA:rsaEncryption", XKEY_PROV_PROPS, signature_functions, "OpenVPN xkey RSA Signature"}, {"ECDSA", XKEY_PROV_PROPS, signature_functions, "OpenVPN xkey ECDSA Signature"}, + {"ED448", XKEY_PROV_PROPS, signature_functions, "OpenVPN xkey Ed448 Signature"}, + {"ED25519", XKEY_PROV_PROPS, signature_functions, "OpenVPN xkey Ed25519 Signature"}, {NULL, NULL, NULL, NULL} }; diff --git a/tests/unit_tests/openvpn/test_provider.c b/tests/unit_tests/openvpn/test_provider.c index 0b0952ee2..e29252838 100644 --- a/tests/unit_tests/openvpn/test_provider.c +++ b/tests/unit_tests/openvpn/test_provider.c @@ -66,7 +66,11 @@ static const char *const pubkey2 = "-----BEGIN PUBLIC KEY-----\n" "u95ff1JiUaJIkYNIkZA+hwIPFVH5aJcSCv3SPIeDS2VUAESNKHZJBQ==\n" "-----END PUBLIC KEY-----\n"; -static const char *pubkeys[] = {pubkey1, pubkey2}; +static const char *const pubkey3 = "-----BEGIN PUBLIC KEY-----\n" + "MCowBQYDK2VwAyEA+q5xjF5hGyyqYZidJdz/0saEQabL3N4wIZJBxNGbgJE=\n" + "-----END PUBLIC KEY-----"; + +static const char *pubkeys[] = {pubkey1, pubkey2, pubkey3}; static const char *prov_name = "ovpn.xkey"; @@ -158,12 +162,17 @@ management_query_pk_sig(struct management *man, const char *b64_data, if (strstr(algorithm, "data=message")) { expected_tbs = test_msg_b64; - assert_non_null(strstr(algorithm, "hashalg=SHA256")); + /* ED25519 does not have a hash algorithm even though it goes via + * the DigestSign path (data=message) */ + if (!strstr(algorithm, "ED25519")) + { + assert_non_null(strstr(algorithm, "hashalg=SHA256")); + } } assert_string_equal(b64_data, expected_tbs); - /* We test using ECDSA or PSS with saltlen = digest */ - if (!strstr(algorithm, "ECDSA")) + /* We test using ED25519, ECDSA or PSS with saltlen = digest */ + if (!strstr(algorithm, "ECDSA") && !strstr(algorithm, "ED25519")) { assert_non_null(strstr(algorithm, "RSA_PKCS1_PSS_PADDING,hashalg=SHA256,saltlen=digest")); } @@ -328,13 +337,13 @@ xkey_sign(void *handle, unsigned char *sig, size_t *siglen, assert_memory_equal(tbs, test_digest, sizeof(test_digest)); } - /* For the test use sha256 and PSS padding for RSA */ + /* For the test use sha256 and PSS padding for RSA and none for EDDSA */ assert_int_equal(OBJ_sn2nid(s.mdname), NID_sha256); if (!strcmp(s.keytype, "RSA")) { assert_string_equal(s.padmode, "pss"); /* we use PSS for the test */ } - else if (strcmp(s.keytype, "EC")) + else if (strcmp(s.keytype, "EC") && strcmp(s.keytype,"ED25519")) { fail_msg("Unknown keytype: %s", s.keytype); }