From patchwork Sat Jan 28 22:34:20 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Selva Nair X-Patchwork-Id: 3021 Return-Path: Delivered-To: patchwork@openvpn.net Received: by 2002:a05:7300:c95:b0:82:e4b3:40a0 with SMTP id p21csp2227028dyk; Sat, 28 Jan 2023 14:35:36 -0800 (PST) X-Google-Smtp-Source: AK7set+y7VtyWsk2ocDLL8VT0B9yfBVAioHqCJEiHN3MIK08Ic3sRPfX2oVMaZQP5H4nZ0xYkIBn X-Received: by 2002:a05:6a20:47e1:b0:bc:59c5:6a41 with SMTP id ey33-20020a056a2047e100b000bc59c56a41mr3105559pzb.36.1674945336144; Sat, 28 Jan 2023 14:35:36 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1674945336; cv=none; d=google.com; s=arc-20160816; b=T4SAWomeqH3uWH30rDskHwEuzAiAZCkDZ80gc0nFsDwMLm3jlEBoG3IjNYpqEMriU9 KG88kMEXJMuu2K6teYk7ebvfWrkUG37HCFGBDTqRCchkbSEPFsSue7DIsSkoJURD1QSs P6pHss+PX7VDySlpSJ4gVZyZCknuwwVEVpryVyAJgCOj/ScF4SzgAWiYTt1Jctw4mEQ+ Fp5qmfq8hinLVkgkHXQrqG7dGRz0PY4rzy3btp5/OdcfsxoAR5Bgo82y8Zxq+QXV66X1 aDQJHFp52B7+iG7ewKMbYmN9M5baZGU6Bfz/xuHpPggmrInT6FffMQnLAdyxH/vFa/58 o0Vw== 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=C5pjyn5OFzfS1pMDOHFj5U2PWveDvesUtgYLbbri+pI=; b=qo8ty7sAJiwhoU+mPsUqK5xnvMse0BV7eYFuCs9eCPGhJQizaHlKzDrZ33+ij0aO2u 46WJLuXFwcS0e1bcU0a3Wjfw+muV92971emrRTlz+Cap6Lriny5HKuJYKMijAI9nMLsc Q52FGqm0nKTIoalXbesEJSgHQGiUDHhJQi4U3xMtVZKv0mEtmQfS/xQnfFu1UdTD/pCO OgfP3+t3z+PhmNsjV83PhrQETsB+rjQg5NLOwOhAkLsmvrJxph9i3SOTmW/kMliMaKg0 ZYMnrGKSb/lWJLB5kjLuzHOLi/MrpWIXw0f8gjIP892iFuIbPa7jPoMvYn6VsxTFLRAh eRXA== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@sourceforge.net header.s=x header.b="dElSVj/S"; dkim=neutral (body hash did not verify) header.i=@sf.net header.s=x header.b=i5nURhUF; dkim=neutral (body hash did not verify) header.i=@gmail.com header.s=20210112 header.b=WIC7waY8; 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 z11-20020a637e0b000000b00477ca5b5617si7756786pgc.147.2023.01.28.14.35.35 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Sat, 28 Jan 2023 14:35:36 -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="dElSVj/S"; dkim=neutral (body hash did not verify) header.i=@sf.net header.s=x header.b=i5nURhUF; dkim=neutral (body hash did not verify) header.i=@gmail.com header.s=20210112 header.b=WIC7waY8; 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-2.v29.lw.sourceforge.com) by sfs-ml-2.v29.lw.sourceforge.com with esmtp (Exim 4.95) (envelope-from ) id 1pLtmc-0001bp-K6; Sat, 28 Jan 2023 22:34:49 +0000 Received: from [172.30.20.202] (helo=mx.sourceforge.net) by sfs-ml-2.v29.lw.sourceforge.com with esmtps (TLS1.2) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.95) (envelope-from ) id 1pLtmb-0001bc-Ai for openvpn-devel@lists.sourceforge.net; Sat, 28 Jan 2023 22:34:48 +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=sAQDuS4hsjIn7rb7z9QwdhiOSugcFbVAe3V+JZRIKDI=; b=dElSVj/SvdMjJHgReVpci7ID6V LZTcAfxyzI29EetREY4OgyEKjzd+44rU8Opqnh88ywY6ljdXJyxxqimvlsV9No64LfKASbJMSkrtp 8XB/Vi7JJ/bezBFbIRCkHRuhENtjMTNV13u2JwMxBQjx8+6+0p/RWC30VlCdY05sscHg=; 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=sAQDuS4hsjIn7rb7z9QwdhiOSugcFbVAe3V+JZRIKDI=; b=i5nURhUFcdxFu4gE8ZMWPb+eyC lJPDZL4LFWPdCg8kqiHNd1dbShNDga3n6RTf0thjHXOvm49cgaG7dBNiTxxKi7VtEifageE1bqi16 PzZMr96CyoJDv+85OMR+3s/Ck5hQL1HXFLNgPn4UVCSVw2Q9oO75nWL/805Hm60BO4rA=; Received: from mail-io1-f54.google.com ([209.85.166.54]) by sfi-mx-1.v28.lw.sourceforge.com with esmtps (TLS1.2:ECDHE-RSA-AES128-GCM-SHA256:128) (Exim 4.95) id 1pLtmX-001xwx-DP for openvpn-devel@lists.sourceforge.net; Sat, 28 Jan 2023 22:34:48 +0000 Received: by mail-io1-f54.google.com with SMTP id e204so3246966iof.1 for ; Sat, 28 Jan 2023 14:34:45 -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=sAQDuS4hsjIn7rb7z9QwdhiOSugcFbVAe3V+JZRIKDI=; b=WIC7waY8480V3VuRKF0eXSIb5luxjLj3/8b3e/C6Viz4tyPvNkpB7HVU5w4QSQbXar tiTFojhClQkUIj3tOPHDvs9gASOxcA8BBbMnBtRXjn8ATXtlK0pT2C/+BhmZZn9jjHDI aK9APweSsPJOcp9UlnL5wfsbxghYb9Dub7FvGGnhptzhfKzLMuTOBv/w53u48wLI5Yfg kZ9SejoLeO+2Q75WQYys1mMzXUOKRUrU7zqZq+qy4t0tl33PuzushuEC3h01OstMxZN1 kyXVS7J6H1qCn62LlPUt4OdY+k4uR8Gaj8QWFp7CdveaQl1iAo5qrasWWXIllJNvE7o3 W9Aw== 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=sAQDuS4hsjIn7rb7z9QwdhiOSugcFbVAe3V+JZRIKDI=; b=ja2/5AYd6nFJgrpCIUG1+aUfNYBJXPV3VlN3K96ycvwJ2izHOOtxXVYJTBDoFhZlW+ UlSSzZixFUSMsev7+wx/g6/SkDqwwEIHcWCfTUwAQLVU4OKyTJsGE0fwLVpdDQLoGeY9 EWj4iqAMjUh28aaO8o+yUEkeI/IEtIegqRJDYORT2SXB3MZH07bWiIOcgKVPZT9WSbVC ADDrRUOXuqAfSpSp77u815ADNlmk/57/W6ky6ECJHrYrXNc4XdNR7gTYGuIqITv3oavx 6aeVBfQgZKPWehIrqIMmU9XTtoe5pr7b46Padu/TjZDr0+y5jvw7a3ZhFRLwADHhxAQg uoXg== X-Gm-Message-State: AFqh2krZDgBsHGqqJwZw745HAm96vqPeOvHQWocykkm8wizxpNzrjDms 5k/Cwiz9ZqpQIRKXp3Po16kWaOTtXnc= X-Received: by 2002:a5d:875a:0:b0:707:d0c0:1bd6 with SMTP id k26-20020a5d875a000000b00707d0c01bd6mr3140570iol.1.1674945279421; Sat, 28 Jan 2023 14:34:39 -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 ay25-20020a5d9d99000000b006bba42f7822sm103930iob.52.2023.01.28.14.34.38 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 28 Jan 2023 14:34:39 -0800 (PST) From: selva.nair@gmail.com To: openvpn-devel@lists.sourceforge.net Date: Sat, 28 Jan 2023 17:34:20 -0500 Message-Id: <20230128223421.2207802-4-selva.nair@gmail.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230128223421.2207802-1-selva.nair@gmail.com> References: <20230128223421.2207802-1-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-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: 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. Or move ENABLE_CRYPTOAPI [...] Content analysis details: (-0.2 points, 6.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 RCVD_IN_DNSWL_NONE RBL: Sender listed at https://www.dnswl.org/, no trust [209.85.166.54 listed in list.dnswl.org] -0.0 SPF_PASS SPF: sender matches SPF record 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record 0.0 FREEMAIL_FROM Sender email is commonly abused enduser mail provider [selva.nair[at]gmail.com] -0.0 RCVD_IN_MSPIKE_H2 RBL: Average reputation (+2) [209.85.166.54 listed in wl.mailspike.net] -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain -0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from envelope-from domain -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid X-Headers-End: 1pLtmX-001xwx-DP Subject: [Openvpn-devel] [PATCH 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?1756307480657846923?= 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. Or move ENABLE_CRYPTOAPI out of syshead.h ? Signed-off-by: Selva Nair --- 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..6ff4fcb5 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: cryptoapicert not supported in this version"); + 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);