Received: by 2002:a05:6a10:1a4d:0:0:0:0 with SMTP id nk13csp1557360pxb; Tue, 8 Feb 2022 22:12:10 -0800 (PST) X-Google-Smtp-Source: ABdhPJyRAiI6rcrJWEOJW0/TfkK5VyIGZBQqT3ao5PBs6LtF2MLiUxYpS5hPRDnwyLdE3c20H+/m X-Received: by 2002:a17:902:ec8a:: with SMTP id x10mr722762plg.107.1644387130623; Tue, 08 Feb 2022 22:12:10 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1644387130; cv=none; d=google.com; s=arc-20160816; b=orMNLPo6MEd9jTsKrDQUxjoEUea2yvdP6BIvMsxcYZ6KR8nST4Tau0CJyg6BjmmeTq +zDBl3BIbdjtYVwLiAkKamJmDeRawpHt43LeuulGVr+OiTxFK9cxyYZU52uPdQEeQvrZ 91DKGzb8UnnlctTzQaGRHeY11hIFAiQlm5WgL2mp3j4cCTo0TVu7Mwd+Glc9NfxBIUxt k5JvP8shxExeBEmIQiL7m0yviWeKGXLv1TyRheP9UTV+KyXsgD1tKTijAGXB068+2RfJ DkFBcsVmN7z9oiXGH+1aUxWyH5l9rJBQEtOthgKhcrz1a9Q3HUc7eBfKVcfpp6izFux5 287w== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:in-reply-to:content-disposition:mime-version :references:message-id:subject:cc:to:from:date; bh=utvj8nf1LVjkgPODrxexXi22fz2trrZl3AYL62EZWP8=; b=maIEDpH6OxAhox3RMm4L9cz+RQx/KM5vc7nLJqo2enU8CxudhSt5ZxBVtbltTCjYub fcodE9FZntCE3RBsQA947qvNGI02yf8PVTScOt9BCmRGHi99DeQKWcU2HGQjSMyK7QyU oIdMc/+gYm0HoUpOBaW/MT7FhAdfuJVLZt5FDuXE+bdkDZiHkg4d8FvxBtho0P4vmPmK STu1XBIJJwDGmOlZe3QlW2sHAbkHC8F97kdSbeFM0ZpS8gluFZIyPywfUaGxL6ifyDdQ OwRQwsKk1ASjVuZezqbnKQe+I/xz81/nmWJhUbLE1amofqrNRzfPRsgbs9vReevQPssn M0jA== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of linux-crypto-owner@vger.kernel.org designates 2620:137:e000::1:18 as permitted sender) smtp.mailfrom=linux-crypto-owner@vger.kernel.org Return-Path: Received: from lindbergh.monkeyblade.net (lindbergh.monkeyblade.net. [2620:137:e000::1:18]) by mx.google.com with ESMTPS id k10si14503911plt.595.2022.02.08.22.12.10 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 08 Feb 2022 22:12:10 -0800 (PST) Received-SPF: pass (google.com: domain of linux-crypto-owner@vger.kernel.org designates 2620:137:e000::1:18 as permitted sender) client-ip=2620:137:e000::1:18; Authentication-Results: mx.google.com; spf=pass (google.com: domain of linux-crypto-owner@vger.kernel.org designates 2620:137:e000::1:18 as permitted sender) smtp.mailfrom=linux-crypto-owner@vger.kernel.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id E2B34E00E5A3; Tue, 8 Feb 2022 21:56:19 -0800 (PST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1344967AbiBHJ0b (ORCPT + 99 others); Tue, 8 Feb 2022 04:26:31 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:37138 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231997AbiBHJ0a (ORCPT ); Tue, 8 Feb 2022 04:26:30 -0500 Received: from vmicros1.altlinux.org (vmicros1.altlinux.org [194.107.17.57]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id D438CC03FEC3; Tue, 8 Feb 2022 01:26:28 -0800 (PST) Received: from imap.altlinux.org (imap.altlinux.org [194.107.17.38]) by vmicros1.altlinux.org (Postfix) with ESMTP id 13F6F72C905; Tue, 8 Feb 2022 12:26:28 +0300 (MSK) Received: from altlinux.org (sole.flsd.net [185.75.180.6]) by imap.altlinux.org (Postfix) with ESMTPSA id E61EB4A46EA; Tue, 8 Feb 2022 12:26:27 +0300 (MSK) Date: Tue, 8 Feb 2022 12:26:27 +0300 From: Vitaly Chikunov To: Eric Biggers Cc: keyrings@vger.kernel.org, Jarkko Sakkinen , David Howells , linux-crypto@vger.kernel.org, linux-integrity@vger.kernel.org, Stefan Berger , Gilad Ben-Yossef , Tianjia Zhang , Mimi Zohar , stable@vger.kernel.org Subject: Re: [PATCH v2 2/2] KEYS: asymmetric: properly validate hash_algo and encoding Message-ID: <20220208092627.7id2k7vze5sh6zdk@altlinux.org> References: <20220208052448.409152-1-ebiggers@kernel.org> <20220208052448.409152-3-ebiggers@kernel.org> MIME-Version: 1.0 Content-Type: text/plain; charset=koi8-r Content-Disposition: inline In-Reply-To: <20220208052448.409152-3-ebiggers@kernel.org> X-Spam-Status: No, score=-7.7 required=5.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI, SPF_HELO_PASS,SPF_PASS,T_SCC_BODY_TEXT_LINE autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-crypto@vger.kernel.org On Mon, Feb 07, 2022 at 09:24:48PM -0800, Eric Biggers wrote: > From: Eric Biggers > > It is insecure to allow arbitrary hash algorithms and signature > encodings to be used with arbitrary signature algorithms. Notably, > ECDSA, ECRDSA, and SM2 all sign/verify raw hash values and don't > disambiguate between different hash algorithms like RSA PKCS#1 v1.5 > padding does. Therefore, they need to be restricted to certain sets of > hash algorithms (ideally just one, but in practice small sets are used). > Additionally, the encoding is an integral part of modern signature > algorithms, and is not supposed to vary. > > Therefore, tighten the checks of hash_algo and encoding done by > software_key_determine_akcipher(). > > Also rearrange the parameters to software_key_determine_akcipher() to > put the public_key first, as this is the most important parameter and it > often determines everything else. > > Fixes: 299f561a6693 ("x509: Add support for parsing x509 certs with ECDSA keys") > Fixes: 215525639631 ("X.509: support OSCCA SM2-with-SM3 certificate verification") > Fixes: 0d7a78643f69 ("crypto: ecrdsa - add EC-RDSA (GOST 34.10) algorithm") > Cc: stable@vger.kernel.org > Tested-by: Stefan Berger > Tested-by: Tianjia Zhang > Signed-off-by: Eric Biggers Reviewed-by: Vitaly Chikunov Small question below. > --- > crypto/asymmetric_keys/public_key.c | 111 +++++++++++++++++++--------- > 1 file changed, 76 insertions(+), 35 deletions(-) > > diff --git a/crypto/asymmetric_keys/public_key.c b/crypto/asymmetric_keys/public_key.c > index e36213945686..7c9e6be35c30 100644 > --- a/crypto/asymmetric_keys/public_key.c > +++ b/crypto/asymmetric_keys/public_key.c > @@ -60,39 +60,83 @@ static void public_key_destroy(void *payload0, void *payload3) > } > > /* > - * Determine the crypto algorithm name. > + * Given a public_key, and an encoding and hash_algo to be used for signing > + * and/or verification with that key, determine the name of the corresponding > + * akcipher algorithm. Also check that encoding and hash_algo are allowed. > */ > -static > -int software_key_determine_akcipher(const char *encoding, > - const char *hash_algo, > - const struct public_key *pkey, > - char alg_name[CRYPTO_MAX_ALG_NAME]) > +static int > +software_key_determine_akcipher(const struct public_key *pkey, > + const char *encoding, const char *hash_algo, > + char alg_name[CRYPTO_MAX_ALG_NAME]) > { > int n; > > - if (strcmp(encoding, "pkcs1") == 0) { > - /* The data wangled by the RSA algorithm is typically padded > - * and encoded in some manner, such as EMSA-PKCS1-1_5 [RFC3447 > - * sec 8.2]. > + if (!encoding) > + return -EINVAL; > + > + if (strcmp(pkey->pkey_algo, "rsa") == 0) { > + /* > + * RSA signatures usually use EMSA-PKCS1-1_5 [RFC3447 sec 8.2]. > + */ > + if (strcmp(encoding, "pkcs1") == 0) { > + if (!hash_algo) > + n = snprintf(alg_name, CRYPTO_MAX_ALG_NAME, > + "pkcs1pad(%s)", > + pkey->pkey_algo); > + else > + n = snprintf(alg_name, CRYPTO_MAX_ALG_NAME, > + "pkcs1pad(%s,%s)", > + pkey->pkey_algo, hash_algo); > + return n >= CRYPTO_MAX_ALG_NAME ? -EINVAL : 0; > + } > + if (strcmp(encoding, "raw") != 0) > + return -EINVAL; Should raw RSA be allowed at all? I understand it was there before, but I wonder what is the use case. Thanks, > + /* > + * Raw RSA cannot differentiate between different hash > + * algorithms. > + */ > + if (hash_algo) > + return -EINVAL; > + } else if (strncmp(pkey->pkey_algo, "ecdsa", 5) == 0) { > + if (strcmp(encoding, "x962") != 0) > + return -EINVAL; > + /* > + * ECDSA signatures are taken over a raw hash, so they don't > + * differentiate between different hash algorithms. That means > + * that the verifier should hard-code a specific hash algorithm. > + * Unfortunately, in practice ECDSA is used with multiple SHAs, > + * so we have to allow all of them and not just one. > */ > if (!hash_algo) > - n = snprintf(alg_name, CRYPTO_MAX_ALG_NAME, > - "pkcs1pad(%s)", > - pkey->pkey_algo); > - else > - n = snprintf(alg_name, CRYPTO_MAX_ALG_NAME, > - "pkcs1pad(%s,%s)", > - pkey->pkey_algo, hash_algo); > - return n >= CRYPTO_MAX_ALG_NAME ? -EINVAL : 0; > - } > - > - if (strcmp(encoding, "raw") == 0 || > - strcmp(encoding, "x962") == 0) { > - strcpy(alg_name, pkey->pkey_algo); > - return 0; > + return -EINVAL; > + if (strcmp(hash_algo, "sha1") != 0 && > + strcmp(hash_algo, "sha224") != 0 && > + strcmp(hash_algo, "sha256") != 0 && > + strcmp(hash_algo, "sha384") != 0 && > + strcmp(hash_algo, "sha512") != 0) > + return -EINVAL; > + } else if (strcmp(pkey->pkey_algo, "sm2") == 0) { > + if (strcmp(encoding, "raw") != 0) > + return -EINVAL; > + if (!hash_algo) > + return -EINVAL; > + if (strcmp(hash_algo, "sm3") != 0) > + return -EINVAL; > + } else if (strcmp(pkey->pkey_algo, "ecrdsa") == 0) { > + if (strcmp(encoding, "raw") != 0) > + return -EINVAL; > + if (!hash_algo) > + return -EINVAL; > + if (strcmp(hash_algo, "streebog256") != 0 && > + strcmp(hash_algo, "streebog512") != 0) > + return -EINVAL; > + } else { > + /* Unknown public key algorithm */ > + return -ENOPKG; > } > - > - return -ENOPKG; > + if (strscpy(alg_name, pkey->pkey_algo, CRYPTO_MAX_ALG_NAME) < 0) > + return -EINVAL; > + return 0; > } > > static u8 *pkey_pack_u32(u8 *dst, u32 val) > @@ -113,9 +157,8 @@ static int software_key_query(const struct kernel_pkey_params *params, > u8 *key, *ptr; > int ret, len; > > - ret = software_key_determine_akcipher(params->encoding, > - params->hash_algo, > - pkey, alg_name); > + ret = software_key_determine_akcipher(pkey, params->encoding, > + params->hash_algo, alg_name); > if (ret < 0) > return ret; > > @@ -179,9 +222,8 @@ static int software_key_eds_op(struct kernel_pkey_params *params, > > pr_devel("==>%s()\n", __func__); > > - ret = software_key_determine_akcipher(params->encoding, > - params->hash_algo, > - pkey, alg_name); > + ret = software_key_determine_akcipher(pkey, params->encoding, > + params->hash_algo, alg_name); > if (ret < 0) > return ret; > > @@ -340,9 +382,8 @@ int public_key_verify_signature(const struct public_key *pkey, > return -EKEYREJECTED; > } > > - ret = software_key_determine_akcipher(sig->encoding, > - sig->hash_algo, > - pkey, alg_name); > + ret = software_key_determine_akcipher(pkey, sig->encoding, > + sig->hash_algo, alg_name); > if (ret < 0) > return ret; > > -- > 2.35.1