From patchwork Wed Feb 1 23:03:40 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Selva Nair X-Patchwork-Id: 3038 Return-Path: Delivered-To: patchwork@openvpn.net Received: by 2002:a05:7300:c95:b0:82:e4b3:40a0 with SMTP id p21csp797852dyk; Wed, 1 Feb 2023 15:04:50 -0800 (PST) X-Google-Smtp-Source: AK7set9cm8sb+ria+atadZbWH8e1Sb0UDGa6/cmK+GtsWep6I4ybKOKih+sAOpjDXLZVxerrilai X-Received: by 2002:a17:903:283:b0:198:96d2:9181 with SMTP id j3-20020a170903028300b0019896d29181mr331583plr.56.1675292689912; Wed, 01 Feb 2023 15:04:49 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1675292689; cv=none; d=google.com; s=arc-20160816; b=wfvBRdezMec7WYIx5r89B5uah5hNgEIQ4zdCPO0W4u4KOlDe4djW0PDtKsop6W1S/f ZanRbEwrH49GEXnnV6RsKgWVFLt7rmpSrOr7Uwa6qxrURo/Hkd9c6ETWWgln9p8to7iD kl1GUYP0vn8IDVb06pv7iD7VJhFWGWAYuFSH1jqM+/PrMr+GIzRPnHq3XUDjwk5Wioew cryzij4vN/ftTlOWNBMYr4wPv3hP9iBz6xK0D+td0VLo0d14wooclJcawJJWsbIqq5h7 PkN32q61YdVz+5OkB4VcxGFcME3tGcna066DSuh4BdFurV9BXlhKKtcG5bgGPJGwg+rn IIwA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=errors-to:content-transfer-encoding:list-subscribe:list-help :list-post:list-archive:list-unsubscribe:list-id:precedence:subject :mime-version:references:in-reply-to:message-id:date:to:from :dkim-signature:dkim-signature:dkim-signature; bh=LpGFKrfpGScqLA68Qw2bklQj58cwB04PnBlFPWm+A2k=; b=nCNtJFNUoJMO4QrsDx0yfEA70wrGFDQ1+LV49hY1YAF/N6XXw0L3PBZlKsvSGvi3F7 5V0rm49edAuUbQie4jVjvW8ovQxP6qP3CEunGIW66DcksrC6eUBM++vGzQc0y0OwW38w 8/IrwS7MAfuDqjy3l1X8sIp7wEJ/s/yAJyo/GEBsdri+nKPFzDmlj8ew+fLUKs+S162T xVc/JlmjfW8z3MtL+muTul2eKW2lcE/QG0WgzsqP2F95Kt4UMuXT9LyzgvictzI2RVgD 2msFaNL2TAhguA2psCwIpPt0iI60KQ0AvZxYRhJXtGK3DDNJr/Oh5wnUyYaqDyiXmRCM 3v7g== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@sourceforge.net header.s=x header.b=DzbtEBt7; dkim=neutral (body hash did not verify) header.i=@sf.net header.s=x header.b=Jowfwg3g; dkim=neutral (body hash did not verify) header.i=@gmail.com header.s=20210112 header.b="Bx49/uiM"; spf=pass (google.com: domain of openvpn-devel-bounces@lists.sourceforge.net designates 216.105.38.7 as permitted sender) smtp.mailfrom=openvpn-devel-bounces@lists.sourceforge.net; dmarc=fail (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: from lists.sourceforge.net (lists.sourceforge.net. [216.105.38.7]) by mx.google.com with ESMTPS id e6-20020a17090301c600b00194a0da96a5si23420471plh.170.2023.02.01.15.04.49 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Wed, 01 Feb 2023 15:04:49 -0800 (PST) Received-SPF: pass (google.com: domain of openvpn-devel-bounces@lists.sourceforge.net designates 216.105.38.7 as permitted sender) client-ip=216.105.38.7; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@sourceforge.net header.s=x header.b=DzbtEBt7; dkim=neutral (body hash did not verify) header.i=@sf.net header.s=x header.b=Jowfwg3g; dkim=neutral (body hash did not verify) header.i=@gmail.com header.s=20210112 header.b="Bx49/uiM"; spf=pass (google.com: domain of openvpn-devel-bounces@lists.sourceforge.net designates 216.105.38.7 as permitted sender) smtp.mailfrom=openvpn-devel-bounces@lists.sourceforge.net; dmarc=fail (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: from [127.0.0.1] (helo=sfs-ml-1.v29.lw.sourceforge.com) by sfs-ml-1.v29.lw.sourceforge.com with esmtp (Exim 4.95) (envelope-from ) id 1pNM8v-0005BV-H3; Wed, 01 Feb 2023 23:03:52 +0000 Received: from [172.30.20.202] (helo=mx.sourceforge.net) by sfs-ml-1.v29.lw.sourceforge.com with esmtps (TLS1.2) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.95) (envelope-from ) id 1pNM8u-0005BP-PQ for openvpn-devel@lists.sourceforge.net; Wed, 01 Feb 2023 23:03:52 +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:References: In-Reply-To:Message-Id:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type: Content-ID:Content-Description:Resent-Date:Resent-From:Resent-Sender: Resent-To:Resent-Cc:Resent-Message-ID:List-Id:List-Help:List-Unsubscribe: List-Subscribe:List-Post:List-Owner:List-Archive; bh=VesC6tehME+lntd4tCbga6oCIJWZqz4qU7N0Bzfe8UU=; b=DzbtEBt79rjuI0k9b9v1yKBk/7 HupINqV16XvA9xfR1uNwInCmJaL67DuRnUTSWykwu7hTx6x31RmF4qKQfYmGIe1pTIDXSaXbcivpg zaqslFLTEFH2A9DB9XFlQF2Xoerhpan3R6vpC6MHX29kprpk6NnfSIW/MZkB/IzcPQII=; DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sf.net; s=x ; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To:Message-Id: Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive; bh=VesC6tehME+lntd4tCbga6oCIJWZqz4qU7N0Bzfe8UU=; b=Jowfwg3gdHXRii8BA/r/4cGNlI gBP+HGXyyFFCxqI5DBn8edhcOO3l2rCYkmgWdtqQjwqvcAn4O3g31m3sXfDpfsZCrgVs3SW+3jynF TagXfD1vB719IqzYJfmELIquSzUlduxRtOLG2NcyYveV8jfQ0XKY58M5XG3YFAwVvvmU=; Received: from mail-il1-f180.google.com ([209.85.166.180]) by sfi-mx-1.v28.lw.sourceforge.com with esmtps (TLS1.2:ECDHE-RSA-AES128-GCM-SHA256:128) (Exim 4.95) id 1pNM8s-007qZp-0M for openvpn-devel@lists.sourceforge.net; Wed, 01 Feb 2023 23:03:51 +0000 Received: by mail-il1-f180.google.com with SMTP id h18so111151ilj.6 for ; Wed, 01 Feb 2023 15:03:49 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=VesC6tehME+lntd4tCbga6oCIJWZqz4qU7N0Bzfe8UU=; b=Bx49/uiMnSXr0ujpombUQksaazbhnHmAqMlFiLl+DLZIsAR7KV/uZn0Lbt9UfUoBm/ pTCdXzWKJ+5C6vkrRFel2hckk36uuxoZtUi/xHXpr7OD8yosNzQFSJ7GJpVM30aCPi5k 4pg75oGdzAMKT5uobAouoM/Y1PG1LVZ8ZbwjDKDNDocx0MEVvRXjDefJhFoB+gWmsNqZ vrEsuk10VNIJlZcI+CGl3stj0oKLaA21NxRxOf1Idx80JZ1O9CqGK+IcnU99QzMmrekO UwcUfyncGYsn1VKFthfP7YuEXq3YGeDhrBD6ehSK8FxriqgL1q/u58sQX7+K8GL748jh 4Zgw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=VesC6tehME+lntd4tCbga6oCIJWZqz4qU7N0Bzfe8UU=; b=ZT+eCReuzV4qmYP5XAeb1NTS7LO7hIOieUQpEgVC2yk9oC2ZxdSlLyHv5MSc/qT6N8 JZuf7kqOG5/fIk51625qF/ndjudtA+3Gk/+aQ4Jem5V/62bGPaS/I4stoI1xXjZCsurT IBTCyUBy0ktgR8XxovJMqUAV0ZI5pX/DbqmXlGiJ9NeVIz9HdmJC1lBI/F3QI34+ZVaT ScA50+V++qn0ayEecHMan8fSeTjPzVAxuWGknvnOi00XziczmxJjys1j0ESrbOCmP+Bl Rz0HKhVqvu26cBF5tZ3oZD0fpAtYPJ087dHWTlY25Avpb9RtlL7nJJrUuta+2GFKbRue wMpg== X-Gm-Message-State: AO0yUKWyv+zjFI2YKgGYNkdCunyr4hWMejxOLlTkuruQKSogZyk17Tu6 4kabXX/wctKdqLt0q+BUT3hFJPfh7q8= X-Received: by 2002:a92:d150:0:b0:311:1949:dd99 with SMTP id t16-20020a92d150000000b003111949dd99mr2355820ilg.3.1675292623877; Wed, 01 Feb 2023 15:03:43 -0800 (PST) Received: from uranus.sansel.ca (bras-vprn-tnhlon4053w-lp130-01-70-51-222-66.dsl.bell.ca. [70.51.222.66]) by smtp.gmail.com with ESMTPSA id u11-20020a056638134b00b003b974c563c6sm233139jad.162.2023.02.01.15.03.42 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 01 Feb 2023 15:03:43 -0800 (PST) From: selva.nair@gmail.com To: openvpn-devel@lists.sourceforge.net Date: Wed, 1 Feb 2023 18:03:40 -0500 Message-Id: <20230201230340.2268781-1-selva.nair@gmail.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230128223421.2207802-4-selva.nair@gmail.com> References: <20230128223421.2207802-4-selva.nair@gmail.com> MIME-Version: 1.0 X-Spam-Score: -0.2 (/) X-Spam-Report: Spam detection software, running on the system "util-spamd-2.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: From: Selva Nair - Require xkey-provider (thus OpenSSL 3.01+) for --cryptoapicert Note: Ideally we should also make ENABLE_CRYPTOAPI conditional on HAVE_XKEY_PROVIDER but that looks hard unless we can agree to move HAVE_XKEY_PROVIDER to configure/config.h. Content analysis details: (-0.2 points, 6.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record -0.0 SPF_PASS SPF: sender matches SPF record 0.0 FREEMAIL_FROM Sender email is commonly abused enduser mail provider [selva.nair[at]gmail.com] -0.0 RCVD_IN_DNSWL_NONE RBL: Sender listed at https://www.dnswl.org/, no trust [209.85.166.180 listed in list.dnswl.org] -0.0 RCVD_IN_MSPIKE_H2 RBL: Average reputation (+2) [209.85.166.180 listed in wl.mailspike.net] -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature -0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from envelope-from domain 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain X-Headers-End: 1pNM8s-007qZp-0M Subject: [Openvpn-devel] [PATCH v2 3/4] cryptoapi.c: remove pre OpenSSL-3.01 support 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 X-GMAIL-THRID: =?utf-8?q?1756307480657846923?= X-GMAIL-MSGID: =?utf-8?q?1756671707253551994?= From: Selva Nair - Require xkey-provider (thus OpenSSL 3.01+) for --cryptoapicert Note: Ideally we should also make ENABLE_CRYPTOAPI conditional on HAVE_XKEY_PROVIDER but that looks hard unless we can agree to move HAVE_XKEY_PROVIDER to configure/config.h. v2: use "binary" instead of "version" in the error message Signed-off-by: Selva Nair Acked-by: Gert Doering --- src/openvpn/cryptoapi.c | 555 +--------------------------------------- src/openvpn/options.c | 2 +- 2 files changed, 11 insertions(+), 546 deletions(-) diff --git a/src/openvpn/cryptoapi.c b/src/openvpn/cryptoapi.c index e3c0bc99..eafef1b1 100644 --- a/src/openvpn/cryptoapi.c +++ b/src/openvpn/cryptoapi.c @@ -55,17 +55,17 @@ #include "xkey_common.h" #ifndef HAVE_XKEY_PROVIDER -/* index for storing external data in EC_KEY: < 0 means uninitialized */ -static int ec_data_idx = -1; -/* Global EVP_PKEY_METHOD used to override the sign operation */ -static EVP_PKEY_METHOD *pmethod; -static int (*default_pkey_sign_init) (EVP_PKEY_CTX *ctx); -static int (*default_pkey_sign) (EVP_PKEY_CTX *ctx, unsigned char *sig, - size_t *siglen, const unsigned char *tbs, size_t tbslen); -#else /* ifndef HAVE_XKEY_PROVIDER */ +int +SSL_CTX_use_CryptoAPI_certificate(SSL_CTX *ssl_ctx, const char *cert_prop) +{ + msg(M_NONFATAL, "ERROR: this binary was built without cryptoapicert support"); + return 0; +} + +#else /* HAVE_XKEY_PROVIDER */ + static XKEY_EXTERNAL_SIGN_fn xkey_cng_sign; -#endif /* HAVE_XKEY_PROVIDER */ typedef struct _CAPI_DATA { const CERT_CONTEXT *cert_context; @@ -146,127 +146,6 @@ CAPI_DATA_free(CAPI_DATA *cd) free(cd); } -#ifndef HAVE_XKEY_PROVIDER - -/* Translate OpenSSL padding type to CNG padding type - * Returns 0 for unknown/unsupported padding. - */ -static DWORD -cng_padding_type(int padding) -{ - DWORD pad = 0; - - switch (padding) - { - case RSA_NO_PADDING: - break; - - case RSA_PKCS1_PADDING: - pad = BCRYPT_PAD_PKCS1; - break; - - case RSA_PKCS1_PSS_PADDING: - pad = BCRYPT_PAD_PSS; - break; - - default: - msg(M_WARN|M_INFO, "cryptoapicert: unknown OpenSSL padding type %d.", - padding); - } - - return pad; -} - -/** - * Sign the hash in 'from' using NCryptSignHash(). This requires an NCRYPT - * key handle in cd->crypt_prov. On return the signature is in 'to'. Returns - * the length of the signature or 0 on error. - * This is used only for RSA and padding should be BCRYPT_PAD_PKCS1 or - * BCRYPT_PAD_PSS. - * If the hash_algo is not NULL, PKCS #1 DigestInfo header gets added - * to |from|, else it is signed as is. Use NULL for MD5 + SHA1 hash used - * in TLS 1.1 and earlier. - * In case of PSS padding, |saltlen| should specify the size of salt to use. - * If |to| is NULL returns the required buffer size. - */ -static int -priv_enc_CNG(const CAPI_DATA *cd, const wchar_t *hash_algo, const unsigned char *from, - int flen, unsigned char *to, int tlen, DWORD padding, DWORD saltlen) -{ - NCRYPT_KEY_HANDLE hkey = cd->crypt_prov; - DWORD len = 0; - ASSERT(cd->key_spec == CERT_NCRYPT_KEY_SPEC); - - DWORD status; - - msg(D_LOW, "Signing hash using CNG: data size = %d padding = %lu", flen, padding); - - if (padding == BCRYPT_PAD_PKCS1) - { - BCRYPT_PKCS1_PADDING_INFO padinfo = {hash_algo}; - status = NCryptSignHash(hkey, &padinfo, (BYTE *)from, flen, - to, tlen, &len, padding); - } - else if (padding == BCRYPT_PAD_PSS) - { - BCRYPT_PSS_PADDING_INFO padinfo = {hash_algo, saltlen}; - status = NCryptSignHash(hkey, &padinfo, (BYTE *)from, flen, - to, tlen, &len, padding); - } - else - { - msg(M_NONFATAL, "Error in cryptoapicert: Unknown padding type"); - return 0; - } - - if (status != ERROR_SUCCESS) - { - SetLastError(status); - msg(M_NONFATAL|M_ERRNO, "Error in cryptoapicert: NCryptSignHash failed"); - len = 0; - } - - /* Unlike CAPI, CNG signature is in big endian order. No reversing needed. */ - return len; -} - -/* called at RSA_free */ -static int -rsa_finish(RSA *rsa) -{ - const RSA_METHOD *rsa_meth = RSA_get_method(rsa); - CAPI_DATA *cd = (CAPI_DATA *) RSA_meth_get0_app_data(rsa_meth); - - if (cd == NULL) - { - return 0; - } - CAPI_DATA_free(cd); - RSA_meth_free((RSA_METHOD *) rsa_meth); - return 1; -} - -static EC_KEY_METHOD *ec_method = NULL; - -/** EC_KEY_METHOD callback: called when the key is freed */ -static void -ec_finish(EC_KEY *ec) -{ - EC_KEY_METHOD_free(ec_method); - ec_method = NULL; - CAPI_DATA *cd = EC_KEY_get_ex_data(ec, ec_data_idx); - CAPI_DATA_free(cd); - EC_KEY_set_ex_data(ec, ec_data_idx, NULL); -} - -/** EC_KEY_METHOD callback sign_setup(): we do nothing here */ -static int -ecdsa_sign_setup(EC_KEY *eckey, BN_CTX *ctx_in, BIGNUM **kinvp, BIGNUM **rp) -{ - return 1; -} -#endif /* HAVE_XKEY_PROVIDER */ - /** * Helper to convert ECDSA signature returned by NCryptSignHash * to an ECDSA_SIG structure. @@ -301,141 +180,6 @@ err: return NULL; } -#ifndef HAVE_XKEY_PROVIDER - -/** EC_KEY_METHOD callback sign_sig(): sign and return an ECDSA_SIG pointer. */ -static ECDSA_SIG * -ecdsa_sign_sig(const unsigned char *dgst, int dgstlen, - const BIGNUM *in_kinv, const BIGNUM *in_r, EC_KEY *ec) -{ - ECDSA_SIG *ecsig = NULL; - CAPI_DATA *cd = (CAPI_DATA *)EC_KEY_get_ex_data(ec, ec_data_idx); - - ASSERT(cd->key_spec == CERT_NCRYPT_KEY_SPEC); - - NCRYPT_KEY_HANDLE hkey = cd->crypt_prov; - BYTE buf[512]; /* large enough buffer for signature to avoid malloc */ - DWORD len = _countof(buf); - - msg(D_LOW, "Cryptoapi: signing hash using EC key: data size = %d", dgstlen); - - DWORD status = NCryptSignHash(hkey, NULL, (BYTE *)dgst, dgstlen, (BYTE *)buf, len, &len, 0); - if (status != ERROR_SUCCESS) - { - SetLastError(status); - msg(M_NONFATAL|M_ERRNO, "Error in cryptoapticert: NCryptSignHash failed"); - } - else - { - /* NCryptSignHash returns r, s concatenated in buf[] */ - ecsig = ecdsa_bin2sig(buf, len); - } - return ecsig; -} - -/** EC_KEY_METHOD callback sign(): sign and return a DER encoded signature */ -static int -ecdsa_sign(int type, const unsigned char *dgst, int dgstlen, unsigned char *sig, - unsigned int *siglen, const BIGNUM *kinv, const BIGNUM *r, EC_KEY *ec) -{ - ECDSA_SIG *s; - - *siglen = 0; - s = ecdsa_sign_sig(dgst, dgstlen, NULL, NULL, ec); - if (s == NULL) - { - return 0; - } - - /* convert internal signature structure 's' to DER encoded byte array in sig */ - int len = i2d_ECDSA_SIG(s, NULL); - if (len > ECDSA_size(ec)) - { - ECDSA_SIG_free(s); - msg(M_NONFATAL, "Error in cryptoapicert: DER encoded ECDSA signature is too long (%d bytes)", len); - return 0; - } - *siglen = i2d_ECDSA_SIG(s, &sig); - ECDSA_SIG_free(s); - - return 1; -} - -static int -ssl_ctx_set_eckey(SSL_CTX *ssl_ctx, CAPI_DATA *cd, EVP_PKEY *pkey) -{ - EC_KEY *ec = NULL; - EVP_PKEY *privkey = NULL; - - /* create a method struct with default callbacks filled in */ - ec_method = EC_KEY_METHOD_new(EC_KEY_OpenSSL()); - if (!ec_method) - { - goto err; - } - - /* We only need to set finish among init methods, and sign methods */ - EC_KEY_METHOD_set_init(ec_method, NULL, ec_finish, NULL, NULL, NULL, NULL); - EC_KEY_METHOD_set_sign(ec_method, ecdsa_sign, ecdsa_sign_setup, ecdsa_sign_sig); - - ec = EC_KEY_dup(EVP_PKEY_get0_EC_KEY(pkey)); - if (!ec) - { - goto err; - } - if (!EC_KEY_set_method(ec, ec_method)) - { - goto err; - } - - /* get an index to store cd as external data */ - if (ec_data_idx < 0) - { - ec_data_idx = EC_KEY_get_ex_new_index(0, "cryptapicert ec key", NULL, NULL, NULL); - if (ec_data_idx < 0) - { - goto err; - } - } - EC_KEY_set_ex_data(ec, ec_data_idx, cd); - - /* cd assigned to ec as ex_data, increase its refcount */ - cd->ref_count++; - - privkey = EVP_PKEY_new(); - if (!EVP_PKEY_assign_EC_KEY(privkey, ec)) - { - EC_KEY_free(ec); - goto err; - } - /* from here on ec will get freed with privkey */ - - if (!SSL_CTX_use_PrivateKey(ssl_ctx, privkey)) - { - goto err; - } - EVP_PKEY_free(privkey); /* this will dn_ref or free ec as well */ - return 1; - -err: - if (privkey) - { - EVP_PKEY_free(privkey); - } - else if (ec) - { - EC_KEY_free(ec); - } - if (ec_method) /* do always set ec_method = NULL after freeing it */ - { - EC_KEY_METHOD_free(ec_method); - ec_method = NULL; - } - return 0; -} - -#endif /* !HAVE_XKEY_PROVIDER */ - static const CERT_CONTEXT * find_certificate_in_store(const char *cert_prop, HCERTSTORE cert_store) { @@ -541,254 +285,6 @@ out: return rv; } -#ifndef HAVE_XKEY_PROVIDER - -static const CAPI_DATA * -retrieve_capi_data(EVP_PKEY *pkey) -{ - const CAPI_DATA *cd = NULL; - - if (pkey && EVP_PKEY_id(pkey) == EVP_PKEY_RSA) - { - RSA *rsa = EVP_PKEY_get0_RSA(pkey); - if (rsa) - { - cd = (CAPI_DATA *)RSA_meth_get0_app_data(RSA_get_method(rsa)); - } - } - return cd; -} - -static int -pkey_rsa_sign_init(EVP_PKEY_CTX *ctx) -{ - msg(D_LOW, "cryptoapicert: enter pkey_rsa_sign_init"); - - EVP_PKEY *pkey = EVP_PKEY_CTX_get0_pkey(ctx); - - if (pkey && retrieve_capi_data(pkey)) - { - return 1; /* Return success */ - } - else if (default_pkey_sign_init) /* Not our key. Call the default method */ - { - return default_pkey_sign_init(ctx); - } - return 1; -} - -/** - * Implementation of EVP_PKEY_sign() using CNG: sign the digest in |tbs| - * and save the the signature in |sig| and its size in |*siglen|. - * If |sig| is NULL the required buffer size is returned in |*siglen|. - * Returns value is 1 on success, 0 or a negative integer on error. - */ -static int -pkey_rsa_sign(EVP_PKEY_CTX *ctx, unsigned char *sig, size_t *siglen, - const unsigned char *tbs, size_t tbslen) -{ - EVP_PKEY *pkey = NULL; - const CAPI_DATA *cd = NULL; - EVP_MD *md = NULL; - const wchar_t *alg = NULL; - - int padding = 0; - int hashlen = 0; - int saltlen = 0; - - pkey = EVP_PKEY_CTX_get0_pkey(ctx); - if (pkey) - { - cd = retrieve_capi_data(pkey); - } - - /* - * We intercept all sign requests, not just the one's for our key. - * Check the key and call the saved OpenSSL method for unknown keys. - */ - if (!pkey || !cd) - { - if (default_pkey_sign) - { - return default_pkey_sign(ctx, sig, siglen, tbs, tbslen); - } - else /* This should not happen */ - { - msg(M_FATAL, "Error in cryptoapicert: Unknown key and no default sign operation to fallback on"); - return -1; - } - } - - if (!EVP_PKEY_CTX_get_rsa_padding(ctx, &padding)) - { - padding = RSA_PKCS1_PADDING; /* Default padding for RSA */ - } - - if (EVP_PKEY_CTX_get_signature_md(ctx, &md)) - { - hashlen = EVP_MD_size(md); - alg = cng_hash_algo(EVP_MD_type(md)); - - /* - * alg == NULL indicates legacy MD5+SHA1 hash, else alg should be a valid - * digest algorithm. - */ - if (alg && wcscmp(alg, L"UNKNOWN") == 0) - { - msg(M_NONFATAL, "Error in cryptoapicert: Unknown hash algorithm <%d>", EVP_MD_type(md)); - return -1; - } - } - else - { - msg(M_NONFATAL, "Error in cryptoapicert: could not determine the signature digest algorithm"); - return -1; - } - - if (tbslen != (size_t)hashlen) - { - msg(M_NONFATAL, "Error in cryptoapicert: data size does not match hash"); - return -1; - } - - /* If padding is PSS, determine parameters to pass to CNG */ - if (padding == RSA_PKCS1_PSS_PADDING) - { - /* - * Ensure the digest type for signature and mask generation match. - * In CNG there is no option to specify separate hash functions for - * the two, but OpenSSL supports it. However, I have not seen the - * two being different in practice. Also the recommended practice is - * to use the same for both (rfc 8017 sec 8.1). - */ - EVP_MD *mgf1md; - if (!EVP_PKEY_CTX_get_rsa_mgf1_md(ctx, &mgf1md) - || EVP_MD_type(mgf1md) != EVP_MD_type(md)) - { - msg(M_NONFATAL, "Error in cryptoapicert: Unknown MGF1 digest type or does" - " not match the signature digest type."); - return -1; - } - - if (!EVP_PKEY_CTX_get_rsa_pss_saltlen(ctx, &saltlen)) - { - msg(M_WARN|M_INFO, "cryptoapicert: unable to get the salt length from context." - " Using the default value."); - saltlen = -1; - } - - /* - * In OpenSSL saltlen = -1 indicates to use the size of the digest as - * size of the salt. A value of -2 or -3 indicates maximum salt length - * that will fit. See RSA_padding_add_PKCS1_PSS_mgf1() of OpenSSL. - */ - if (saltlen == -1) - { - saltlen = hashlen; - } - else if (saltlen < 0) - { - const RSA *rsa = EVP_PKEY_get0_RSA(pkey); - saltlen = RSA_size(rsa) - hashlen - 2; /* max salt length for RSASSA-PSS */ - if (RSA_bits(rsa) &0x7) /* number of bits in the key not a multiple of 8 */ - { - saltlen--; - } - } - - if (saltlen < 0) - { - msg(M_NONFATAL, "Error in cryptoapicert: invalid salt length (%d). Digest too large for keysize?", saltlen); - return -1; - } - msg(D_LOW, "cryptoapicert: PSS padding using saltlen = %d", saltlen); - } - - msg(D_LOW, "cryptoapicert: calling priv_enc_CNG with alg = %ls", alg); - *siglen = priv_enc_CNG(cd, alg, tbs, (int)tbslen, sig, (int)*siglen, - cng_padding_type(padding), (DWORD)saltlen); - - return (*siglen == 0) ? 0 : 1; -} - -static int -ssl_ctx_set_rsakey(SSL_CTX *ssl_ctx, CAPI_DATA *cd, EVP_PKEY *pkey) -{ - RSA *rsa = NULL; - RSA_METHOD *my_rsa_method = NULL; - EVP_PKEY *privkey = NULL; - int ret = 0; - - my_rsa_method = RSA_meth_new("Microsoft Cryptography API RSA Method", - RSA_METHOD_FLAG_NO_CHECK); - check_malloc_return(my_rsa_method); - RSA_meth_set_finish(my_rsa_method, rsa_finish); /* we use this callback to cleanup CAPI_DATA */ - RSA_meth_set0_app_data(my_rsa_method, cd); - - /* pmethod is global -- initialize only if NULL */ - if (!pmethod) - { - pmethod = EVP_PKEY_meth_new(EVP_PKEY_RSA, 0); - if (!pmethod) - { - msg(M_NONFATAL, "Error in cryptoapicert: failed to create EVP_PKEY_METHOD"); - return 0; - } - const EVP_PKEY_METHOD *default_pmethod = EVP_PKEY_meth_find(EVP_PKEY_RSA); - EVP_PKEY_meth_copy(pmethod, default_pmethod); - - /* We want to override only sign_init() and sign() */ - EVP_PKEY_meth_set_sign(pmethod, pkey_rsa_sign_init, pkey_rsa_sign); - EVP_PKEY_meth_add0(pmethod); - - /* Keep a copy of the default sign and sign_init methods */ - - EVP_PKEY_meth_get_sign(default_pmethod, &default_pkey_sign_init, - &default_pkey_sign); - } - - rsa = EVP_PKEY_get1_RSA(pkey); - - RSA_set_flags(rsa, RSA_flags(rsa) | RSA_FLAG_EXT_PKEY); - if (!RSA_set_method(rsa, my_rsa_method)) - { - goto cleanup; - } - my_rsa_method = NULL; /* we do not want to free it in cleanup */ - cd->ref_count++; /* with method, cd gets assigned to the key as well */ - - privkey = EVP_PKEY_new(); - if (!EVP_PKEY_assign_RSA(privkey, rsa)) - { - goto cleanup; - } - rsa = NULL; /* privkey has taken ownership */ - - if (!SSL_CTX_use_PrivateKey(ssl_ctx, privkey)) - { - goto cleanup; - } - ret = 1; - -cleanup: - if (rsa) - { - RSA_free(rsa); - } - if (my_rsa_method) - { - RSA_meth_free(my_rsa_method); - } - if (privkey) - { - EVP_PKEY_free(privkey); - } - - return ret; -} - -#else /* HAVE_XKEY_PROVIDER */ - /** Sign hash in tbs using EC key in cd and NCryptSignHash */ static int xkey_cng_ec_sign(CAPI_DATA *cd, unsigned char *sig, size_t *siglen, const unsigned char *tbs, @@ -937,8 +433,6 @@ xkey_cng_sign(void *handle, unsigned char *sig, size_t *siglen, const unsigned c } } -#endif /* HAVE_XKEY_PROVIDER */ - static char * get_cert_name(const CERT_CONTEXT *cc, struct gc_arena *gc) { @@ -1043,45 +537,16 @@ SSL_CTX_use_CryptoAPI_certificate(SSL_CTX *ssl_ctx, const char *cert_prop) X509_free(cert); cert = NULL; -#ifdef HAVE_XKEY_PROVIDER - EVP_PKEY *privkey = xkey_load_generic_key(tls_libctx, cd, pkey, xkey_cng_sign, (XKEY_PRIVKEY_FREE_fn *) CAPI_DATA_free); SSL_CTX_use_PrivateKey(ssl_ctx, privkey); gc_free(&gc); return 1; /* do not free cd -- its kept by xkey provider */ -#else /* ifdef HAVE_XKEY_PROVIDER */ - - if (EVP_PKEY_id(pkey) == EVP_PKEY_RSA) - { - if (!ssl_ctx_set_rsakey(ssl_ctx, cd, pkey)) - { - goto err; - } - } - else if (EVP_PKEY_id(pkey) == EVP_PKEY_EC) - { - if (!ssl_ctx_set_eckey(ssl_ctx, cd, pkey)) - { - goto err; - } - } - else - { - msg(M_WARN|M_INFO, "WARNING: cryptoapicert: key type <%d> not supported", - EVP_PKEY_id(pkey)); - goto err; - } - CAPI_DATA_free(cd); /* this will do a ref_count-- */ - gc_free(gc); - return 1; - -#endif /* HAVE_XKEY_PROVIDER */ - err: CAPI_DATA_free(cd); gc_free(&gc); return 0; } +#endif /* HAVE_XKEY_PROVIDER */ #endif /* _WIN32 */ diff --git a/src/openvpn/options.c b/src/openvpn/options.c index f24af3d7..e18b3b39 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -8864,7 +8864,7 @@ add_option(struct options *options, listend->next = newlist; } } -#ifdef ENABLE_CRYPTOAPI +#if defined(ENABLE_CRYPTOAPI) && defined(HAVE_XKEY_PROVIDER) else if (streq(p[0], "cryptoapicert") && p[1] && !p[2]) { VERIFY_PERMISSION(OPT_P_GENERAL);