From patchwork Tue Dec 14 05:59:25 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Selva Nair X-Patchwork-Id: 2177 Return-Path: Delivered-To: patchwork@openvpn.net Delivered-To: patchwork@openvpn.net Received: from director13.mail.ord1d.rsapps.net ([172.30.191.6]) by backend41.mail.ord1d.rsapps.net with LMTP id kL3eHujNuGHQWAAAqwncew (envelope-from ) for ; Tue, 14 Dec 2021 12:01:28 -0500 Received: from proxy4.mail.ord1d.rsapps.net ([172.30.191.6]) by director13.mail.ord1d.rsapps.net with LMTP id kIydBOnNuGGYFAAA91zNiA (envelope-from ) for ; Tue, 14 Dec 2021 12:01:29 -0500 Received: from smtp26.gate.ord1d ([172.30.191.6]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) by proxy4.mail.ord1d.rsapps.net with LMTPS id UC7yAunNuGG9fQAAiYrejw (envelope-from ) for ; Tue, 14 Dec 2021 12:01:29 -0500 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: smtp26.gate.ord1d.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; dkim=fail (signature verification failed) header.d=gmail.com; dmarc=fail (p=none; dis=none) header.from=gmail.com X-Suspicious-Flag: YES X-Classification-ID: 78c86816-5cff-11ec-82fb-525400c5b129-1-1 Received: from [216.105.38.7] ([216.105.38.7:60370] helo=lists.sourceforge.net) by smtp26.gate.ord1d.rsapps.net (envelope-from ) (ecelerity 4.2.38.62370 r(:)) with ESMTPS (cipher=DHE-RSA-AES256-GCM-SHA384) id 2A/93-10556-5EDC8B16; Tue, 14 Dec 2021 12:01:27 -0500 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.94.2) (envelope-from ) id 1mxBA7-0003L5-HQ; Tue, 14 Dec 2021 17:00:23 +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.94.2) (envelope-from ) id 1mxBA2-0003Ke-4D for openvpn-devel@lists.sourceforge.net; Tue, 14 Dec 2021 17:00:18 +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=zAWnjHFCmQ3xQEHKnVto9MzBrypuyShwxn0BPQMs8Tk=; b=fjBhQsaSTiFsJXxtGi/Y9i1IK9 dJa++JDbR+EnUcZQzI+Iic8drLOipPRYh8JTLsATQIr2oQW+jh0NkMVDnGNe4wW0NnOTe8AgL+y0n DCGpE5yiBF9iYaLXpX29zMC6NEW3QaOwPEpBATa0kmZXcUTcApuiRinEMQpmWAgLxCJQ=; 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=zAWnjHFCmQ3xQEHKnVto9MzBrypuyShwxn0BPQMs8Tk=; b=MMC1ckAQVve8EeTYBFXhJfbrc0 M1IEEIlw1927UPK7/YnwSxYdi5n9+OrIbT7KoKluSm3m4hLH2e7VrpB/VPVbAxjw3mX5gW/uBO2W9 XdXjrY+wfxgChSXpMajp1itqd/iaNZhG0SadUt/5PyDwcn8haiMLGns6jwOzAJ3nMdJ8=; Received: from mail-io1-f51.google.com ([209.85.166.51]) by sfi-mx-1.v28.lw.sourceforge.com with esmtps (TLSv1.2:ECDHE-RSA-AES128-GCM-SHA256:128) (Exim 4.92.3) id 1mxB9u-00FKXl-UM for openvpn-devel@lists.sourceforge.net; Tue, 14 Dec 2021 17:00:17 +0000 Received: by mail-io1-f51.google.com with SMTP id z26so25274669iod.10 for ; Tue, 14 Dec 2021 09:00:10 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=zAWnjHFCmQ3xQEHKnVto9MzBrypuyShwxn0BPQMs8Tk=; b=l2HRim7FlO0Rn2LbrCVhTjL0zaqmPKzFmDFOZVtYj3yax2AtbF6BmheuhGCFwQCr9G Mi+wBXb78WOGt58b/el0ITDDrsTX/vcc119H1VJpfWQN5PDv4QhxDCzxL5J7zf8tDfa3 mTZpw5iQO7AOsjrrctYIiQhG3P6sSuPPCxxS7ORLhNI8mDGGmmc3hKCUYmVgtKh5Ll2A wXGC3vF3MG/1MH4SIp32eKdWAacXNiR4eTVJyGxKpG3r79m5/o9x69vpYUl+xD5aIehy 0FF7W9n5yOJiIwBQpeHS5h7PCYz6bmee/+mtP9BygHv8CDsf4WdKhLj3dF9ZQbO0KeTZ /RTA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=zAWnjHFCmQ3xQEHKnVto9MzBrypuyShwxn0BPQMs8Tk=; b=H1eOtaaGyJMAtaHFplDzKWqScFg7D6zFdb8A2pxIetf04yHN47+7LXIcGnvhWGLJ/7 43hdir0+a7hNfJjSG/Rwe1lkC2BHTTNBeIRuyx+paGbRQbt8ygxMw3YzCW9RXm9txzWS rdSaC4v0rsuPiAwOI4onUG+mFgI+pAvf0waAVXljTOzFH0/A35WmR1/jRuuanN9owGNx pG63k1hXnOwVxxvYIODM+s5d+Q/YHARLwznAGhXQWjse81ARw99Od/GEnc0tL+WD2oN+ +rsJNi6O8Av9Ya47wBFoiVn0WQIl1uvHeIiZzznAyzlP2/7l0TYsUD2Dl30aun6/ai2v E7QA== X-Gm-Message-State: AOAM532lJiOhluFxTFAwOEV7rXC/sz64E0wHNn2CzBJdhOS/2+a6h3/F Glu21r9/y35Apt4R+x9YvgmxLSxgSsQ= X-Google-Smtp-Source: ABdhPJwMLUm3lv4qe186bN0IG4rbZqAfOYqcjHzmlPHZA+vRMV8dCx7mRBf3/TtAMaokTh96ldVIpA== X-Received: by 2002:a02:ba90:: with SMTP id g16mr3694586jao.85.1639501205039; Tue, 14 Dec 2021 09:00:05 -0800 (PST) Received: from uranus.home.sansel.ca (bras-vprn-tnhlon4053w-lp130-02-70-51-223-8.dsl.bell.ca. [70.51.223.8]) by smtp.gmail.com with ESMTPSA id e9sm178778ilm.44.2021.12.14.09.00.04 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 14 Dec 2021 09:00:04 -0800 (PST) From: selva.nair@gmail.com To: openvpn-devel@lists.sourceforge.net Date: Tue, 14 Dec 2021 11:59:25 -0500 Message-Id: <20211214165928.30676-16-selva.nair@gmail.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20211214165928.30676-1-selva.nair@gmail.com> References: <20211214165928.30676-1-selva.nair@gmail.com> 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: From: Selva Nair - Add xkey_cng_sign() as sign_op for the provider and load the key using xkey_generic_load. - Enable/Disable old code when provider is available or not. 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.51 listed in list.dnswl.org] -0.0 RCVD_IN_MSPIKE_H2 RBL: Average reputation (+2) [209.85.166.51 listed in wl.mailspike.net] 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.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from envelope-from domain -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature X-Headers-End: 1mxB9u-00FKXl-UM Subject: [Openvpn-devel] [PATCH v3 15/18] Enable signing using CNG through 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 From: Selva Nair - Add xkey_cng_sign() as sign_op for the provider and load the key using xkey_generic_load. - Enable/Disable old code when provider is available or not. - xkey_digest is made non-static for use in cryptoapi.c One function cng_padding_type() is moved down to reduce number of ifdef's. Signed-off-by: Selva Nair Acked-By: Arne Schwabe --- src/openvpn/cryptoapi.c | 241 +++++++++++++++++++++++++++++++++++----- 1 file changed, 211 insertions(+), 30 deletions(-) diff --git a/src/openvpn/cryptoapi.c b/src/openvpn/cryptoapi.c index 7fe3c57c..08cb434f 100644 --- a/src/openvpn/cryptoapi.c +++ b/src/openvpn/cryptoapi.c @@ -52,7 +52,9 @@ #include "buffer.h" #include "openssl_compat.h" #include "win32.h" +#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; @@ -61,44 +63,19 @@ 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 +static XKEY_EXTERNAL_SIGN_fn xkey_cng_sign; +#endif /* HAVE_XKEY_PROVIDER */ typedef struct _CAPI_DATA { const CERT_CONTEXT *cert_context; HCRYPTPROV_OR_NCRYPT_KEY_HANDLE crypt_prov; + EVP_PKEY *pubkey; DWORD key_spec; BOOL free_crypt_prov; int ref_count; } CAPI_DATA; -/* 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; -} - /* * Translate OpenSSL hash OID to CNG algorithm name. Returns * "UNKNOWN" for unsupported algorithms and NULL for MD5+SHA1 @@ -164,9 +141,42 @@ CAPI_DATA_free(CAPI_DATA *cd) { CertFreeCertificateContext(cd->cert_context); } + EVP_PKEY_free(cd->pubkey); /* passing NULL is okay */ + 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 @@ -255,6 +265,7 @@ 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 @@ -290,6 +301,8 @@ 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, @@ -421,6 +434,8 @@ err: return 0; } +#endif /* !HAVE_XKEY_PROVIDER */ + static const CERT_CONTEXT * find_certificate_in_store(const char *cert_prop, HCERTSTORE cert_store) { @@ -521,6 +536,8 @@ out: return rv; } +#ifndef HAVE_XKEY_PROVIDER + static const CAPI_DATA * retrieve_capi_data(EVP_PKEY *pkey) { @@ -765,6 +782,158 @@ cleanup: 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, + size_t tbslen) +{ + BYTE buf[1024]; /* large enough for EC keys upto 1024 bits */ + DWORD len = _countof(buf); + + msg(D_LOW, "Signing using NCryptSignHash with EC key"); + + DWORD status = NCryptSignHash(cd->crypt_prov, NULL, (BYTE *)tbs, tbslen, buf, len, &len, 0); + + if (status != ERROR_SUCCESS) + { + SetLastError(status); + msg(M_NONFATAL|M_ERRNO, "Error in cryptoapicert: ECDSA signature using CNG failed."); + return 0; + } + + /* NCryptSignHash returns r|s -- convert to OpenSSL's ECDSA_SIG */ + ECDSA_SIG *ecsig = ecdsa_bin2sig(buf, len); + if (!ecsig) + { + msg(M_NONFATAL, "Error in cryptopicert: Failed to convert ECDSA signature"); + return 0; + } + + /* convert internal signature structure 's' to DER encoded byte array in sig */ + if (i2d_ECDSA_SIG(ecsig, NULL) > EVP_PKEY_size(cd->pubkey)) + { + ECDSA_SIG_free(ecsig); + msg(M_NONFATAL, "Error in cryptoapicert: DER encoded ECDSA signature is too long"); + return 0; + } + + *siglen = i2d_ECDSA_SIG(ecsig, &sig); + ECDSA_SIG_free(ecsig); + + return (*siglen > 0); +} + +/** Sign hash in tbs using RSA key in cd and NCryptSignHash */ +static int +xkey_cng_rsa_sign(CAPI_DATA *cd, unsigned char *sig, size_t *siglen, const unsigned char *tbs, + size_t tbslen, XKEY_SIGALG sigalg) +{ + dmsg(D_LOW, "In xkey_cng_rsa_sign"); + + ASSERT(cd); + ASSERT(sig); + ASSERT(tbs); + + DWORD status = ERROR_SUCCESS; + DWORD len = 0; + + const wchar_t *hashalg = cng_hash_algo(OBJ_sn2nid(sigalg.mdname)); + + if (hashalg && wcscmp(hashalg, L"UNKNOWN") == 0) + { + msg(M_NONFATAL, "Error in cryptoapicert: Unknown hash name <%s>", sigalg.mdname); + return 0; + } + + if (!strcmp(sigalg.padmode, "pkcs1")) + { + msg(D_LOW, "Signing using NCryptSignHash with PKCS1 padding: hashalg <%s>", sigalg.mdname); + + BCRYPT_PKCS1_PADDING_INFO padinfo = {hashalg}; + status = NCryptSignHash(cd->crypt_prov, &padinfo, (BYTE *)tbs, (DWORD)tbslen, + sig, (DWORD)*siglen, &len, BCRYPT_PAD_PKCS1); + } + else if (!strcmp(sigalg.padmode, "pss")) + { + int saltlen = tbslen; /* digest size by default */ + if (!strcmp(sigalg.saltlen, "max")) + { + saltlen = (EVP_PKEY_bits(cd->pubkey) - 1)/8 - tbslen - 2; + if (saltlen < 0) + { + msg(M_NONFATAL, "Error in cryptoapicert: invalid salt length (%d)", saltlen); + return 0; + } + } + + msg(D_LOW, "Signing using NCryptSignHash with PSS padding: hashalg <%s>, saltlen <%d>", + sigalg.mdname, saltlen); + + BCRYPT_PSS_PADDING_INFO padinfo = {hashalg, (DWORD) saltlen}; /* cast is safe as saltlen >= 0 */ + status = NCryptSignHash(cd->crypt_prov, &padinfo, (BYTE *)tbs, (DWORD) tbslen, + sig, (DWORD)*siglen, &len, BCRYPT_PAD_PSS); + } + else + { + msg(M_NONFATAL, "Error in cryptoapicert: Unsupported padding mode <%s>", sigalg.padmode); + return 0; + } + + if (status != ERROR_SUCCESS) + { + SetLastError(status); + msg(M_NONFATAL|M_ERRNO, "Error in cryptoapicert: RSA signature using CNG failed."); + return 0; + } + + *siglen = len; + return (*siglen > 0); +} + +/** Dispatch sign op to xkey_cng__sign */ +static int +xkey_cng_sign(void *handle, unsigned char *sig, size_t *siglen, const unsigned char *tbs, + size_t tbslen, XKEY_SIGALG sigalg) +{ + dmsg(D_LOW, "In xkey_cng_sign"); + + CAPI_DATA *cd = handle; + ASSERT(cd); + ASSERT(sig); + ASSERT(tbs); + + unsigned char mdbuf[EVP_MAX_MD_SIZE]; + size_t buflen = _countof(mdbuf); + + /* compute digest if required */ + if (!strcmp(sigalg.op, "DigestSign")) + { + if(!xkey_digest(tbs, tbslen, mdbuf, &buflen, sigalg.mdname)) + { + return 0; + } + tbs = mdbuf; + tbslen = buflen; + } + + if (!strcmp(sigalg.keytype, "EC")) + { + return xkey_cng_ec_sign(cd, sig, siglen, tbs, tbslen); + } + else if (!strcmp(sigalg.keytype, "RSA")) + { + return xkey_cng_rsa_sign(cd, sig, siglen, tbs, tbslen, sigalg); + } + else + { + return 0; /* Unknown keytype -- should not happen */ + } +} + +#endif /* HAVE_XKEY_PROVIDER */ + int SSL_CTX_use_CryptoAPI_certificate(SSL_CTX *ssl_ctx, const char *cert_prop) { @@ -835,13 +1004,23 @@ SSL_CTX_use_CryptoAPI_certificate(SSL_CTX *ssl_ctx, const char *cert_prop) } /* the public key */ - EVP_PKEY *pkey = X509_get0_pubkey(cert); + EVP_PKEY *pkey = X509_get_pubkey(cert); + cd->pubkey = pkey; /* will be freed with cd */ /* SSL_CTX_use_certificate() increased the reference count in 'cert', so * we decrease it here with X509_free(), or it will never be cleaned up. */ 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); + return 1; /* do not free cd -- its kept by xkey provider */ + +#else + if (EVP_PKEY_id(pkey) == EVP_PKEY_RSA) { if (!ssl_ctx_set_rsakey(ssl_ctx, cd, pkey)) @@ -865,6 +1044,8 @@ SSL_CTX_use_CryptoAPI_certificate(SSL_CTX *ssl_ctx, const char *cert_prop) CAPI_DATA_free(cd); /* this will do a ref_count-- */ return 1; +#endif /* HAVE_XKEY_PROVIDER */ + err: CAPI_DATA_free(cd); return 0;