From patchwork Fri Jan 29 21:25:32 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Saulo Alessandre de Lima X-Patchwork-Id: 373435 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-10.7 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id BD8EDC433DB for ; Fri, 29 Jan 2021 21:27:27 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 4BE6E64E0B for ; Fri, 29 Jan 2021 21:27:27 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232781AbhA2V1S (ORCPT ); Fri, 29 Jan 2021 16:27:18 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45802 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233345AbhA2V1J (ORCPT ); Fri, 29 Jan 2021 16:27:09 -0500 Received: from mail-qt1-x832.google.com (mail-qt1-x832.google.com [IPv6:2607:f8b0:4864:20::832]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 505DEC061574 for ; Fri, 29 Jan 2021 13:26:29 -0800 (PST) Received: by mail-qt1-x832.google.com with SMTP id t17so7808542qtq.2 for ; Fri, 29 Jan 2021 13:26:29 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=O+GKl9V7EjD7/v6/Gyuu4j02tEHsKDGALFwoxLjyXqw=; b=L9fUiGezImVtWO/GgswsywHN62utf6DIV2GjptTvsLgPz+5J2jVw9fnF29hfnr/5s8 r7C2tt74ZySPmBSFh4cxc9PXIMKt86eK/iUQY0R6VUNY7JojFLdxTFhP2YaM6pMd5S4R HNrOzwF5h3wv7PttsnAj6Fhh3B7fn4xyrPYPCFL+ltqNKw4IXUWORt4xfdVePaUSTMSy Mj32qKyfHZxbRrD2KNPTM2ZJSOfBGxneEqkbG02F7GP4qYqs2WIkiLjTag1RrdEXtXwH vYY9vKLX54m0R2AISk8TtK0uo1DVhjkzROOr2ocSrNNb0oMlprNa+9+aOzzRwEkms3QA BJ7g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=O+GKl9V7EjD7/v6/Gyuu4j02tEHsKDGALFwoxLjyXqw=; b=qbAEbtVOWgGX/jC3+Hq/h0TtYIzLlKomwcVFUwp5kMHMjcddXjmUtvf1Gycbd4xaG4 uEIap4eLvmJqwHC72DdQOkNSXVUHLRKVEeRWtAWPff5Pl51WjTjotETPRm9qzepr+pXe 9v3c7hJuPdWmDQgRvkfex+B9tgcGuUcfcHzSECAzHdBD+Q7cGEdrGD94KS1s6xUKs4+h AbOLsJu+H10NC1wWo2/fEaij/bAS9EryG11DXzvLhK1phSoMLiVJAe2vYMh3kt/CXl8P xpXX/mo6lq8AsZo3DV1aR+mZMGKTZHAEuCndTBF5f4ef5HO0OCxj1MqcdIHnX5SBdYPR RZ6w== X-Gm-Message-State: AOAM532QkYVTkjYWDj/GChI+woX3ha6gUNSNmcS5CTLIva0q7nh31jVM A3dxZtI+W+qdWjZ7pvO79uPhOghjyuaWQN0n X-Google-Smtp-Source: ABdhPJyi/uxsxA29k3tZGqslHYIikpWacc88MZOXMWRoID4s3CXb0i+sLWl4tgR2o0n5dS+VDGeZGw== X-Received: by 2002:ac8:5d0d:: with SMTP id f13mr5959975qtx.317.1611955588142; Fri, 29 Jan 2021 13:26:28 -0800 (PST) Received: from warrior-desktop.domains. ([189.61.66.20]) by smtp.gmail.com with ESMTPSA id b194sm6763995qkc.102.2021.01.29.13.26.25 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 29 Jan 2021 13:26:27 -0800 (PST) From: Saulo Alessandre To: linux-crypto@vger.kernel.org Cc: Herbert Xu , "David S. Miller" , Vitaly Chikunov , Tianjia Zhang , Saulo Alessandre Subject: [PATCH v2 1/4] ecdsa: add params to ecdsa algo Date: Fri, 29 Jan 2021 18:25:32 -0300 Message-Id: <20210129212535.2257493-2-saulo.alessandre@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210129212535.2257493-1-saulo.alessandre@gmail.com> References: <20210129212535.2257493-1-saulo.alessandre@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-crypto@vger.kernel.org From: Saulo Alessandre * crypto/ecc_curve_defs.h - nist_p384_(x,y,p,n,z,b) and nist_p384 added curve params added; - nist_p521_(x,y,p,n,z,b) and nist_p521 added curve params added; * include/crypto/ecdh.h - ECC_CURVE_NIST_P384, ECC_CURVE_NIST_P521 - added new curves * lib/oid_registry.c - lookup_oid_sign_info - added to return sign algo name; - lookup_oid_digest_info - added to return hash algo name, len and generic OID * include/linux/oid_registry.h - OID_undef - added to reflect a zeroed structure as undefined - OID_id_secp(192r1,256r1), OID_id_ecdsa_with_sha(256,384,512), OID_id_secp(384r1,521r1) - added oid types for ecdsa algo; - lookup_oid_sign_info, lookup_oid_digest_info - added to get hash, sig info; --- crypto/ecc_curve_defs.h | 82 ++++++++++++++++++++++++++++ include/crypto/ecdh.h | 2 + include/linux/oid_registry.h | 12 +++++ lib/oid_registry.c | 100 +++++++++++++++++++++++++++++++++++ 4 files changed, 196 insertions(+) diff --git a/crypto/ecc_curve_defs.h b/crypto/ecc_curve_defs.h index 69be6c7d228f..3d97761021b7 100644 --- a/crypto/ecc_curve_defs.h +++ b/crypto/ecc_curve_defs.h @@ -54,4 +54,86 @@ static struct ecc_curve nist_p256 = { .b = nist_p256_b }; +/* NIST P-384 */ +static u64 nist_p384_g_x[] = { 0x3A545E3872760AB7ull, 0x5502F25DBF55296Cull, + 0x59F741E082542A38ull, 0x6E1D3B628BA79B98ull, + 0x8Eb1C71EF320AD74ull, 0xAA87CA22BE8B0537ull }; +static u64 nist_p384_g_y[] = { 0x7A431D7C90EA0E5Full, 0x0A60B1CE1D7E819Dull, + 0xE9DA3113B5F0B8C0ull, 0xF8F41DBD289A147Cull, + 0x5D9E98BF9292DC29ull, 0x3617DE4A96262C6Full }; +static u64 nist_p384_p[] = { 0x00000000FFFFFFFFull, 0xFFFFFFFF00000000ull, + 0xFFFFFFFFFFFFFFFEull, 0xFFFFFFFFFFFFFFFFull, + 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull }; +static u64 nist_p384_n[] = { 0xECEC196ACCC52973ull, 0x581A0DB248B0A77Aull, + 0xC7634D81F4372DDFull, 0xFFFFFFFFFFFFFFFFull, + 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull }; +static u64 nist_p384_a[] = { 0x00000000FFFFFFFCull, 0xFFFFFFFF00000000ull, + 0xFFFFFFFFFFFFFFFEull, 0xFFFFFFFFFFFFFFFFull, + 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull }; +static u64 nist_p384_b[] = { 0x2a85c8edd3ec2aefull, 0xc656398d8a2ed19dull, + 0x0314088f5013875aull, 0x181d9c6efe814112ull, + 0x988e056be3f82d19ull, 0xb3312fa7e23ee7e4ull }; +static struct ecc_curve nist_p384 = { + .name = "nist_384", + .g = { + .x = nist_p384_g_x, + .y = nist_p384_g_y, + .ndigits = 6, + }, + .p = nist_p384_p, + .n = nist_p384_n, + .a = nist_p384_a, + .b = nist_p384_b +}; + +/* NIST P-521 */ +static u64 nist_p521_g_x[] = { 0xF97E7E31C2E5BD66ull, 0x3348B3C1856A429Bull, + 0xFE1DC127A2FFA8DEull, 0xA14B5E77EFE75928ull, + 0xF828AF606B4D3DBAull, 0x9C648139053FB521ull, + 0x9E3ECB662395B442ull, 0x858E06B70404E9CDull, + 0x00000000000000C6ull }; +static u64 nist_p521_g_y[] = { 0x88BE94769FD16650ull, 0x353C7086A272C240ull, + 0xC550B9013FAD0761ull, 0x97EE72995EF42640ull, + 0x17AFBD17273E662Cull, 0x98F54449579B4468ull, + 0x5C8A5FB42C7D1BD9ull, 0x39296A789A3BC004ull, + 0x0000000000000118ull }; +static u64 nist_p521_p[] = { 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull, + 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull, + 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull, + 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull, + 0x00000000000001FFull }; +static u64 nist_p521_n[] = { 0xBB6FB71E91386409ull, 0x3BB5C9B8899C47AEull, + 0x7FCC0148F709A5D0ull, 0x51868783BF2F966Bull, + 0xFFFFFFFFFFFFFFFAull, 0xFFFFFFFFFFFFFFFFull, + 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull, + 0x00000000000001FFull }; +static u64 nist_p521_a[] = { 0xFFFFFFFFFFFFFFFCull, 0xFFFFFFFFFFFFFFFFull, + 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull, + 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull, + 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull, + 0x00000000000001FFull }; +static u64 nist_p521_b[] = { 0xEF451FD46B503F00ull, 0x3573DF883D2C34F1ull, + 0x1652C0BD3BB1BF07ull, 0x56193951EC7E937Bull, + 0xB8B489918EF109E1ull, 0xA2DA725B99B315F3ull, + 0x929A21A0B68540EEull, 0x953EB9618E1C9A1Full, + 0x0000000000000051ull }; + +static struct ecc_curve nist_p521 = { + .name = "nist_521", + .g = { + .x = nist_p521_g_x, + .y = nist_p521_g_y, + .ndigits = 9, + }, + .p = nist_p521_p, + .n = nist_p521_n, + .a = nist_p521_a, + .b = nist_p521_b +}; + +#define NIST_UNPACKED_KEY_ID 0x04 +#define NISTP256_PACKED_KEY_SIZE 64 +#define NISTP384_PACKED_KEY_SIZE 96 +#define NISTP521_PACKED_KEY_SIZE 132 + #endif diff --git a/include/crypto/ecdh.h b/include/crypto/ecdh.h index a5b805b5526d..6c7333f82b9c 100644 --- a/include/crypto/ecdh.h +++ b/include/crypto/ecdh.h @@ -25,6 +25,8 @@ /* Curves IDs */ #define ECC_CURVE_NIST_P192 0x0001 #define ECC_CURVE_NIST_P256 0x0002 +#define ECC_CURVE_NIST_P384 0x0003 +#define ECC_CURVE_NIST_P521 0x0004 /** * struct ecdh - define an ECDH private key diff --git a/include/linux/oid_registry.h b/include/linux/oid_registry.h index 4462ed2c18cd..7871c574b56a 100644 --- a/include/linux/oid_registry.h +++ b/include/linux/oid_registry.h @@ -17,9 +17,15 @@ * build_OID_registry.pl to generate the data for look_up_OID(). */ enum OID { + OID__undef, /* 1.0 */ OID_id_dsa_with_sha1, /* 1.2.840.10030.4.3 */ OID_id_dsa, /* 1.2.840.10040.4.1 */ + OID_id_secp192r1, /* 1.2.840.10045.3.1.1 */ + OID_id_secp256r1, /* 1.2.840.10045.3.1.7 */ OID_id_ecdsa_with_sha1, /* 1.2.840.10045.4.1 */ + OID_id_ecdsa_with_sha256, /* 1.2.840.10045.4.3.2 */ + OID_id_ecdsa_with_sha384, /* 1.2.840.10045.4.3.3 */ + OID_id_ecdsa_with_sha512, /* 1.2.840.10045.4.3.4 */ OID_id_ecPublicKey, /* 1.2.840.10045.2.1 */ /* PKCS#1 {iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs-1(1)} */ @@ -58,6 +64,8 @@ enum OID { OID_certAuthInfoAccess, /* 1.3.6.1.5.5.7.1.1 */ OID_sha1, /* 1.3.14.3.2.26 */ + OID_id_secp384r1, /* 1.3.132.0.34 */ + OID_id_secp521r1, /* 1.3.132.0.35 */ OID_sha256, /* 2.16.840.1.101.3.4.2.1 */ OID_sha384, /* 2.16.840.1.101.3.4.2.2 */ OID_sha512, /* 2.16.840.1.101.3.4.2.3 */ @@ -119,5 +127,9 @@ enum OID { extern enum OID look_up_OID(const void *data, size_t datasize); extern int sprint_oid(const void *, size_t, char *, size_t); extern int sprint_OID(enum OID, char *, size_t); +extern int lookup_oid_sign_info(enum OID oid, + const char **sign_algo); +extern int lookup_oid_digest_info(enum OID oid, + const char **hash_algo, u32 *hash_len, enum OID *oid_algo); #endif /* _LINUX_OID_REGISTRY_H */ diff --git a/lib/oid_registry.c b/lib/oid_registry.c index f7ad43f28579..aea941dd93ba 100644 --- a/lib/oid_registry.c +++ b/lib/oid_registry.c @@ -92,6 +92,106 @@ enum OID look_up_OID(const void *data, size_t datasize) } EXPORT_SYMBOL_GPL(look_up_OID); +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wswitch" +int lookup_oid_sign_info(enum OID oid, const char **sign_algo) +{ + int ret = -1; + + if (sign_algo) { + switch (oid) { + case OID_md4WithRSAEncryption: + case OID_sha1WithRSAEncryption: + case OID_sha256WithRSAEncryption: + case OID_sha384WithRSAEncryption: + case OID_sha512WithRSAEncryption: + case OID_sha224WithRSAEncryption: + if (sign_algo) + *sign_algo = "rsa"; + ret = 0; + break; + case OID_id_ecdsa_with_sha1: + case OID_id_ecdsa_with_sha256: + case OID_id_ecdsa_with_sha384: + case OID_id_ecdsa_with_sha512: + if (sign_algo) + *sign_algo = "ecdsa"; + ret = 0; + break; + } + } + return ret; +} +EXPORT_SYMBOL_GPL(lookup_oid_sign_info); + +int lookup_oid_digest_info(enum OID oid, + const char **digest_algo, u32 *digest_len, + enum OID *digest_oid) +{ + int ret = 0; + + switch (oid) { + case OID_md4WithRSAEncryption: + if (digest_algo) + *digest_algo = "md4"; + if (digest_oid) + *digest_oid = OID_md4; + if (digest_len) + *digest_len = 16; + break; + case OID_sha1WithRSAEncryption: + case OID_id_ecdsa_with_sha1: + if (digest_algo) + *digest_algo = "sha1"; + if (digest_oid) + *digest_oid = OID_sha1; + if (digest_len) + *digest_len = 20; + break; + case OID_sha224WithRSAEncryption: + if (digest_algo) + *digest_algo = "sha224"; + if (digest_oid) + *digest_oid = OID_sha224; + if (digest_len) + *digest_len = 28; + break; + case OID_sha256WithRSAEncryption: + case OID_id_ecdsa_with_sha256: + if (digest_algo) + *digest_algo = "sha256"; + if (digest_oid) + *digest_oid = OID_sha256; + if (digest_len) + *digest_len = 32; + break; + case OID_sha384WithRSAEncryption: + case OID_id_ecdsa_with_sha384: + if (digest_algo) + *digest_algo = "sha384"; + if (digest_oid) + *digest_oid = OID_sha384; + if (digest_len) + *digest_len = 48; + break; + case OID_sha512WithRSAEncryption: + case OID_id_ecdsa_with_sha512: + if (digest_algo) + *digest_algo = "sha512"; + if (digest_oid) + *digest_oid = OID_sha512; + if (digest_len) + *digest_len = 64; + break; + default: + ret = -1; + } + return ret; +} +EXPORT_SYMBOL_GPL(lookup_oid_digest_info); + +#pragma GCC diagnostic pop + /* * sprint_OID - Print an Object Identifier into a buffer * @data: The encoded OID to print From patchwork Fri Jan 29 21:25:33 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Saulo Alessandre de Lima X-Patchwork-Id: 373852 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-10.7 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 68F12C433E9 for ; Fri, 29 Jan 2021 21:27:28 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id F238564E0B for ; Fri, 29 Jan 2021 21:27:27 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233345AbhA2V1U (ORCPT ); Fri, 29 Jan 2021 16:27:20 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45818 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233452AbhA2V1M (ORCPT ); Fri, 29 Jan 2021 16:27:12 -0500 Received: from mail-qk1-x72f.google.com (mail-qk1-x72f.google.com [IPv6:2607:f8b0:4864:20::72f]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 4F1FFC06174A for ; Fri, 29 Jan 2021 13:26:32 -0800 (PST) Received: by mail-qk1-x72f.google.com with SMTP id n15so10204973qkh.8 for ; Fri, 29 Jan 2021 13:26:32 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=M0ubs7pUNZxPzkda/rjhGWjfmmaFMt2B1S5B/WNfUYA=; b=mx1SHErJ88x4BFNB332q+AifKDDTbx2exvNhkin8mNe6Xx+M3BO14fu9V8SRRd9aDa Id18zvWEn+L+63J41vxryK0GXYIxUn4kE19/FmTZtB16m/lbpvPfinIRrWc+VS7JAO10 /SQj5rYaDIrbrmCzzx0yvEHw1dqoiR4ULMdWo0Ie0s6qfmJAmDF+769PSTTRSIUyFcKr bABcJbfGwVSdRqfN7cEVIOXS3/L47MrNFayCcbWMLT9kcZuJOidWTpuICBhZ3F9Xvde1 JY1YIY/QTrLNIODOQFSGE8WoOy39ZVCx2PAflEBTyNfNIbxZgJ445DdzjIfMpiC8QSDZ 2IUw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=M0ubs7pUNZxPzkda/rjhGWjfmmaFMt2B1S5B/WNfUYA=; b=dSDPlQeMkgi9FkY+Eo1ZHxUvZRcwmeHwU0SsXoFB8++Kf4ux4Sn6/gF4HlL87HGyA+ 1k3GuobIAMxwfuM02JUk6pxXnbHOvRUNcPFtL9hYaLK5U27X3QFJ+N0GfDxmV7/AMQe1 GHeBA9dG+ZWGlJo5Iz2TSMeakChisfK7eYnrlL7/wDn5Tmipm0OvYabNWsq5VOmj93R2 5HF/u6mFXuISs+UklubxMiTrds5+/iRYXpmWoxrBgf2vSQNVkSpRAOSUcR99oC0W5r3N PrkhYDRmVuWPsDLG1KZNZQFfZ/akeDCbL5gX0nXuoRbQAN9M/afoo5szdfImdLHX2tI5 fBAA== X-Gm-Message-State: AOAM532B8W5M9QE2jFwV0xN/loKDxTjyFjUoCtJ/RKb6Pq8CappLXhAu Bhl9IL7Ql4kLLLy+DgymAiTYgCT2VgNWgl6f X-Google-Smtp-Source: ABdhPJyUZoml5rjT8g/3/pQcJArsovnNYfsAAcY+dEg6tLx6MsGASkGCwxDoEbr+jwAlEHJsnzgWDQ== X-Received: by 2002:a37:d03:: with SMTP id 3mr6178831qkn.45.1611955591182; Fri, 29 Jan 2021 13:26:31 -0800 (PST) Received: from warrior-desktop.domains. ([189.61.66.20]) by smtp.gmail.com with ESMTPSA id b194sm6763995qkc.102.2021.01.29.13.26.28 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 29 Jan 2021 13:26:30 -0800 (PST) From: Saulo Alessandre To: linux-crypto@vger.kernel.org Cc: Herbert Xu , "David S. Miller" , Vitaly Chikunov , Tianjia Zhang , Saulo Alessandre Subject: [PATCH v2 2/4] ecdsa: prepare akcipher and x509 parser to use incoming ecdsa Date: Fri, 29 Jan 2021 18:25:33 -0300 Message-Id: <20210129212535.2257493-3-saulo.alessandre@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210129212535.2257493-1-saulo.alessandre@gmail.com> References: <20210129212535.2257493-1-saulo.alessandre@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-crypto@vger.kernel.org From: Saulo Alessandre * crypto/asymmetric_keys/pkcs7_parser.c - pkcs7_sig_note_pkey_algo - changed to recognize OID_id_ecdsa_with_sha(1,256,384,512). * crypto/asymmetric_keys/pkcs7_verify.c - pkcs7_digest - added warning when the summary has an unsupported algorithm, to avoid let others waste time, like me. * crypto/asymmetric_keys/public_key.c - software_key_determine_akcipher - modified to recognize ecdsa. * crypto/asymmetric_keys/x509_cert_parser.c - x509_note_pkey_algo - changed to recognize ecdsa and to use lookup_oid_ routines; added info about certificates found inside kernel; - x509_note_signature - changed to recognize ecdsa; - x509_extract_key_data - changed to recognize OID_id_ecPublicKey as ecdsa --- crypto/asymmetric_keys/pkcs7_parser.c | 7 ++++- crypto/asymmetric_keys/pkcs7_verify.c | 5 ++- crypto/asymmetric_keys/public_key.c | 30 ++++++++++++------ crypto/asymmetric_keys/x509_cert_parser.c | 37 ++++++++++++----------- 4 files changed, 49 insertions(+), 30 deletions(-) diff --git a/crypto/asymmetric_keys/pkcs7_parser.c b/crypto/asymmetric_keys/pkcs7_parser.c index 967329e0a07b..501af4937516 100644 --- a/crypto/asymmetric_keys/pkcs7_parser.c +++ b/crypto/asymmetric_keys/pkcs7_parser.c @@ -267,12 +267,17 @@ int pkcs7_sig_note_pkey_algo(void *context, size_t hdrlen, switch (ctx->last_oid) { case OID_rsaEncryption: ctx->sinfo->sig->pkey_algo = "rsa"; - ctx->sinfo->sig->encoding = "pkcs1"; + break; + case OID_id_ecdsa_with_sha256: + case OID_id_ecdsa_with_sha384: + case OID_id_ecdsa_with_sha512: + ctx->sinfo->sig->pkey_algo = "ecdsa"; break; default: printk("Unsupported pkey algo: %u\n", ctx->last_oid); return -ENOPKG; } + ctx->sinfo->sig->encoding = "pkcs1"; return 0; } diff --git a/crypto/asymmetric_keys/pkcs7_verify.c b/crypto/asymmetric_keys/pkcs7_verify.c index ce49820caa97..a963aa9ec648 100644 --- a/crypto/asymmetric_keys/pkcs7_verify.c +++ b/crypto/asymmetric_keys/pkcs7_verify.c @@ -41,8 +41,11 @@ static int pkcs7_digest(struct pkcs7_message *pkcs7, * big the hash operational data will be. */ tfm = crypto_alloc_shash(sinfo->sig->hash_algo, 0, 0); - if (IS_ERR(tfm)) + if (IS_ERR(tfm)) { + pr_warn("%s unsupported hash_algo[%s]", __func__, + sinfo->sig->hash_algo); return (PTR_ERR(tfm) == -ENOENT) ? -ENOPKG : PTR_ERR(tfm); + } desc_size = crypto_shash_descsize(tfm) + sizeof(*desc); sig->digest_size = crypto_shash_digestsize(tfm); diff --git a/crypto/asymmetric_keys/public_key.c b/crypto/asymmetric_keys/public_key.c index 8892908ad58c..42429a10ef0b 100644 --- a/crypto/asymmetric_keys/public_key.c +++ b/crypto/asymmetric_keys/public_key.c @@ -70,18 +70,28 @@ int software_key_determine_akcipher(const char *encoding, 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 (!hash_algo) + if (pkey->pkey_algo && strcmp(pkey->pkey_algo, "rsa") == 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 (!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); + } else if (pkey->pkey_algo && + strcmp(pkey->pkey_algo, "ecdsa") == 0) { n = snprintf(alg_name, CRYPTO_MAX_ALG_NAME, - "pkcs1pad(%s)", - pkey->pkey_algo); - else + "%s(%s)", pkey->pkey_algo, hash_algo); + } else { n = snprintf(alg_name, CRYPTO_MAX_ALG_NAME, - "pkcs1pad(%s,%s)", - pkey->pkey_algo, hash_algo); + "pkcs1pad(%s,%s)", + pkey->pkey_algo, hash_algo); + } return n >= CRYPTO_MAX_ALG_NAME ? -EINVAL : 0; } diff --git a/crypto/asymmetric_keys/x509_cert_parser.c b/crypto/asymmetric_keys/x509_cert_parser.c index 52c9b455fc7d..a67bdbae1055 100644 --- a/crypto/asymmetric_keys/x509_cert_parser.c +++ b/crypto/asymmetric_keys/x509_cert_parser.c @@ -197,6 +197,7 @@ int x509_note_pkey_algo(void *context, size_t hdrlen, pr_debug("PubKey Algo: %u\n", ctx->last_oid); + ctx->key_algo = ctx->last_oid; switch (ctx->last_oid) { case OID_md2WithRSAEncryption: case OID_md3WithRSAEncryption: @@ -204,27 +205,15 @@ int x509_note_pkey_algo(void *context, size_t hdrlen, return -ENOPKG; /* Unsupported combination */ case OID_md4WithRSAEncryption: - ctx->cert->sig->hash_algo = "md4"; - goto rsa_pkcs1; - case OID_sha1WithRSAEncryption: - ctx->cert->sig->hash_algo = "sha1"; - goto rsa_pkcs1; - case OID_sha256WithRSAEncryption: - ctx->cert->sig->hash_algo = "sha256"; - goto rsa_pkcs1; - case OID_sha384WithRSAEncryption: - ctx->cert->sig->hash_algo = "sha384"; - goto rsa_pkcs1; - case OID_sha512WithRSAEncryption: - ctx->cert->sig->hash_algo = "sha512"; - goto rsa_pkcs1; - case OID_sha224WithRSAEncryption: - ctx->cert->sig->hash_algo = "sha224"; + case OID_id_ecdsa_with_sha1: + case OID_id_ecdsa_with_sha256: + case OID_id_ecdsa_with_sha384: + case OID_id_ecdsa_with_sha512: goto rsa_pkcs1; case OID_gost2012Signature256: @@ -241,9 +230,13 @@ int x509_note_pkey_algo(void *context, size_t hdrlen, } rsa_pkcs1: - ctx->cert->sig->pkey_algo = "rsa"; + lookup_oid_sign_info(ctx->key_algo, &ctx->cert->sig->pkey_algo); + lookup_oid_digest_info(ctx->key_algo, &ctx->cert->sig->hash_algo, + NULL, NULL); ctx->cert->sig->encoding = "pkcs1"; ctx->algo_oid = ctx->last_oid; + pr_info("Found %s(%s) X509 certificate\n", ctx->cert->sig->pkey_algo, + ctx->cert->sig->hash_algo); return 0; ecrdsa: ctx->cert->sig->pkey_algo = "ecrdsa"; @@ -275,6 +268,7 @@ int x509_note_signature(void *context, size_t hdrlen, } if (strcmp(ctx->cert->sig->pkey_algo, "rsa") == 0 || + strcmp(ctx->cert->sig->pkey_algo, "ecdsa") == 0 || strcmp(ctx->cert->sig->pkey_algo, "ecrdsa") == 0 || strcmp(ctx->cert->sig->pkey_algo, "sm2") == 0) { /* Discard the BIT STRING metadata */ @@ -470,7 +464,14 @@ int x509_extract_key_data(void *context, size_t hdrlen, ctx->cert->pub->pkey_algo = "ecrdsa"; break; case OID_id_ecPublicKey: - ctx->cert->pub->pkey_algo = "sm2"; + if (ctx->algo_oid == OID_id_ecdsa_with_sha512 || + ctx->algo_oid == OID_id_ecdsa_with_sha384 || + ctx->algo_oid == OID_id_ecdsa_with_sha256 || + ctx->algo_oid == OID_id_ecdsa_with_sha1) { + ctx->cert->pub->pkey_algo = "ecdsa"; + } else { + ctx->cert->pub->pkey_algo = "sm2"; + } break; default: return -ENOPKG; From patchwork Fri Jan 29 21:25:34 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Saulo Alessandre de Lima X-Patchwork-Id: 373434 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-10.7 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id EBE6EC433E6 for ; Fri, 29 Jan 2021 21:27:29 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 78E3F64E0B for ; Fri, 29 Jan 2021 21:27:29 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233452AbhA2V12 (ORCPT ); Fri, 29 Jan 2021 16:27:28 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45846 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233418AbhA2V1Q (ORCPT ); Fri, 29 Jan 2021 16:27:16 -0500 Received: from mail-qk1-x72e.google.com (mail-qk1-x72e.google.com [IPv6:2607:f8b0:4864:20::72e]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E15EFC061756 for ; Fri, 29 Jan 2021 13:26:35 -0800 (PST) Received: by mail-qk1-x72e.google.com with SMTP id a7so10172239qkb.13 for ; Fri, 29 Jan 2021 13:26:35 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=bku21q3+cr+GLzVk2k3vQze6gEe69qzWUyEGJx0VR1w=; b=rv0cqdkuXydUe5awBZ3awT1hE2A2oVutNJt3kWjYTMCEkxZ3AHqpoPFFW9PJcQXDBG fzpzmD98X9JsTZG3PuEC0VwvmK6bm2wo+rTM6qD+mD8qgnq/C7KNuc3N6bgH2I4KRv18 MjCSLw29Yg7NvFd0n3uEK2VdUpaHFeOiZ+Mc2EkSfqkL0M91gVL9intHvCZS3qSmwNud Ec2Y5lo9SuU79sYIbl1nkLKpKmj8+dISZici5xz0URyXbOK71aHC9/4QU5V/kis3xbtI lWkjdBO6My4FSXivKrwS8wxI9wkVd9X9A3ITFaVlVfnBwIs0++M0DztiP3A2GBSOGsRQ 9YWA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=bku21q3+cr+GLzVk2k3vQze6gEe69qzWUyEGJx0VR1w=; b=IRNludBCgF2M7MPOp2sfXnfkz7pxAzv2+yjBiUihzUZQHRbdENfuTryNReNQzf/fP7 kFe5HS+zIPlaU4/ovALSL8R2yD1V3bE91ZmnonO0uM+F0rHCXtwuO5HXeHyXXNhw95RZ HnyKn2K4zIMDjk5ebyK8W0Wd+Zs/iGdWaSE7K6apgMJw5YO+sotXm/WjyYD/q/Q72Tak HhGuj83TVV8TCC7w58yJjOq1ScMtHsLaSjzRs/7hoVozDQ/u3TbTrKbrXzK8UZfhrq9Q E6YqbpwCVPhCzt4wlr6qrj3ppOzosjlFNySEfS21ZNOr5rZTQhuEW9JaBPf+xgVi8Y4c mIQQ== X-Gm-Message-State: AOAM530g3GOTTqUOfzF1QBsQxzL2V1ThmN9T6SaSE7ZvC7Yoa+KMzbb5 HXa5S2CofwdnV6P42bcQ0ndBH5D7ad8HdOSU X-Google-Smtp-Source: ABdhPJxT//oFrOwMEmSAOen9MUma7F8Atm0SLWzKTdBn1bv3JEZ9+Tr+RQ+0Y9qmRG6X7reeM822lA== X-Received: by 2002:a37:a10c:: with SMTP id k12mr6069341qke.443.1611955594308; Fri, 29 Jan 2021 13:26:34 -0800 (PST) Received: from warrior-desktop.domains. ([189.61.66.20]) by smtp.gmail.com with ESMTPSA id b194sm6763995qkc.102.2021.01.29.13.26.31 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 29 Jan 2021 13:26:33 -0800 (PST) From: Saulo Alessandre To: linux-crypto@vger.kernel.org Cc: Herbert Xu , "David S. Miller" , Vitaly Chikunov , Tianjia Zhang , Saulo Alessandre Subject: [PATCH v2 3/4] ecdsa: change ecc.c and ecc.h to support ecdsa Date: Fri, 29 Jan 2021 18:25:34 -0300 Message-Id: <20210129212535.2257493-4-saulo.alessandre@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210129212535.2257493-1-saulo.alessandre@gmail.com> References: <20210129212535.2257493-1-saulo.alessandre@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-crypto@vger.kernel.org From: Saulo Alessandre * crypto/ecc.c - ecc_get_curve - modified to recognize NIST_P384 and NISTP521; - vli_rshift - created for use on vli_mmod_fast_521 for ecdsa; - vli_mod_add - exported for use on ecdsa.c; - vli_mmod_fast_384 - implements fast elliptic curve nist p384 [4]; - vli_mmod_fast_521 - implements fast elliptic curve nist p521 [4]; - vli_mmod_fast - changed params to receive struct ecc_curve*; changed condition to use correct way to detect nist algo; added new curves (384 and 521); - vli_mmod_fast - changed params to receive ecc_curve; - vli_mod_slow - moved from .h to .c and exported for use on ecdsa.c; - vli_mod_mult_fast - changed params to receive struct ecc_curve*; exported for use on ecdsa.c; - vli_mod_square_fast - changed params to receive struct ecc_curve*; exported for use on ecdsa.c; - ecc_point_is_zero - exported for use on ecdsa.c; - ecc_point_double_jacobian - changed params to receive struct ecc_curve*; - apply_z - changed params to receive struct ecc_curve*; - xycz_initial_double - changed params to receive struct ecc_curve*; - xycz_add - changed params to receive struct ecc_curve*; - xycz_add_c - changed params to receive struct ecc_curve*; - ecc_point_mult - changed to pass struct ecc_curve* forward; - ecc_point_mult_shamir - changed to pass struct ecc_curve* forward; - ecc_is_pubkey_valid_partial - changed to pass struct ecc_curve*; * crypto/ecc.h - NIST_P384 and NIST_P521 constants defined; - ecc_point_is_zero - added to export; - vli_mod_slow - added to export; - vli_mod_add - added to export - vli_mod_fast - added to export; - vli_mod_mult_fast - added to export. --- crypto/ecc.c | 338 +++++++++++++++++++++++++++++++++++++++------------ crypto/ecc.h | 59 ++++++++- 2 files changed, 318 insertions(+), 79 deletions(-) diff --git a/crypto/ecc.c b/crypto/ecc.c index c80aa25994a0..f9e8b155f493 100644 --- a/crypto/ecc.c +++ b/crypto/ecc.c @@ -50,6 +50,10 @@ static inline const struct ecc_curve *ecc_get_curve(unsigned int curve_id) return fips_enabled ? NULL : &nist_p192; case ECC_CURVE_NIST_P256: return &nist_p256; + case ECC_CURVE_NIST_P384: + return &nist_p384; + case ECC_CURVE_NIST_P521: + return &nist_p521; default: return NULL; } @@ -235,6 +239,25 @@ static u64 vli_lshift(u64 *result, const u64 *in, unsigned int shift, return carry; } +/* Computes result = in >> c, returning carry. */ +static u64 vli_rshift(u64 *result, const u64 *in, unsigned int shift, + unsigned int ndigits) +{ + u64 carry = 0; + int i; + + for (i = 0; i < ndigits; i++) { + if (i + 1 < ndigits) + carry = in[i + 1] << (64 - shift); + else + carry = 0; + + result[i] = (in[i] >> shift) | carry; + } + + return carry; +} + /* Computes vli = vli >> 1. */ static void vli_rshift1(u64 *vli, unsigned int ndigits) { @@ -474,7 +497,7 @@ static void vli_square(u64 *result, const u64 *left, unsigned int ndigits) /* Computes result = (left + right) % mod. * Assumes that left < mod and right < mod, result != mod. */ -static void vli_mod_add(u64 *result, const u64 *left, const u64 *right, +void vli_mod_add(u64 *result, const u64 *left, const u64 *right, const u64 *mod, unsigned int ndigits) { u64 carry; @@ -487,6 +510,7 @@ static void vli_mod_add(u64 *result, const u64 *left, const u64 *right, if (carry || vli_cmp(result, mod, ndigits) >= 0) vli_sub(result, result, mod, ndigits); } +EXPORT_SYMBOL(vli_mod_add); /* Computes result = (left - right) % mod. * Assumes that left < mod and right < mod, result != mod. @@ -775,18 +799,156 @@ static void vli_mmod_fast_256(u64 *result, const u64 *product, } } +#define SL32OR32(x32, y32) (((u64)x32 << 32) | y32) +#define AND64H(x64) (x64 & 0xffFFffFF00000000ull) +#define AND64L(x64) (x64 & 0x00000000ffFFffFFull) + +/* Computes result = product % curve_prime + * from "Mathematical routines for the NIST prime elliptic curves" + */ +static void vli_mmod_fast_384(u64 *result, const u64 *product, + const u64 *curve_prime, u64 *tmp) +{ + int carry; + const unsigned int ndigits = 6; + + /* t */ + vli_set(result, product, ndigits); + + /* s1 */ + tmp[0] = 0; // 0 || 0 + tmp[1] = 0; // 0 || 0 + tmp[2] = SL32OR32(product[11], (product[10]>>32)); //a22||a21 + tmp[3] = product[11]>>32; // 0 ||a23 + tmp[4] = 0; // 0 || 0 + tmp[5] = 0; // 0 || 0 + carry = vli_lshift(tmp, tmp, 1, ndigits); + carry += vli_add(result, result, tmp, ndigits); + + /* s2 */ + tmp[0] = product[6]; //a13||a12 + tmp[1] = product[7]; //a15||a14 + tmp[2] = product[8]; //a17||a16 + tmp[3] = product[9]; //a19||a18 + tmp[4] = product[10]; //a21||a20 + tmp[5] = product[11]; //a23||a22 + carry += vli_add(result, result, tmp, ndigits); + + /* s3 */ + tmp[0] = SL32OR32(product[11], (product[10]>>32)); //a22||a21 + tmp[1] = SL32OR32(product[6], (product[11]>>32)); //a12||a23 + tmp[2] = SL32OR32(product[7], (product[6])>>32); //a14||a13 + tmp[3] = SL32OR32(product[8], (product[7]>>32)); //a16||a15 + tmp[4] = SL32OR32(product[9], (product[8]>>32)); //a18||a17 + tmp[5] = SL32OR32(product[10], (product[9]>>32)); //a20||a19 + carry += vli_add(result, result, tmp, ndigits); + + /* s4 */ + tmp[0] = AND64H(product[11]); //a23|| 0 + tmp[1] = (product[10]<<32); //a20|| 0 + tmp[2] = product[6]; //a13||a12 + tmp[3] = product[7]; //a15||a14 + tmp[4] = product[8]; //a17||a16 + tmp[5] = product[9]; //a19||a18 + carry += vli_add(result, result, tmp, ndigits); + + /* s5 */ + tmp[0] = 0; // 0|| 0 + tmp[1] = 0; // 0|| 0 + tmp[2] = product[10]; //a21||a20 + tmp[3] = product[11]; //a23||a22 + tmp[4] = 0; // 0|| 0 + tmp[5] = 0; // 0|| 0 + carry += vli_add(result, result, tmp, ndigits); + + /* s6 */ + tmp[0] = AND64L(product[10]); // 0 ||a20 + tmp[1] = AND64H(product[10]); //a21|| 0 + tmp[2] = product[11]; //a23||a22 + tmp[3] = 0; // 0 || 0 + tmp[4] = 0; // 0 || 0 + tmp[5] = 0; // 0 || 0 + carry += vli_add(result, result, tmp, ndigits); + + /* d1 */ + tmp[0] = SL32OR32(product[6], (product[11]>>32)); //a12||a23 + tmp[1] = SL32OR32(product[7], (product[6]>>32)); //a14||a13 + tmp[2] = SL32OR32(product[8], (product[7]>>32)); //a16||a15 + tmp[3] = SL32OR32(product[9], (product[8]>>32)); //a18||a17 + tmp[4] = SL32OR32(product[10], (product[9]>>32)); //a20||a19 + tmp[5] = SL32OR32(product[11], (product[10]>>32)); //a22||a21 + carry -= vli_sub(result, result, tmp, ndigits); + + /* d2 */ + tmp[0] = (product[10]<<32); //a20|| 0 + tmp[1] = SL32OR32(product[11], (product[10]>>32)); //a22||a21 + tmp[2] = (product[11]>>32); // 0 ||a23 + tmp[3] = 0; // 0 || 0 + tmp[4] = 0; // 0 || 0 + tmp[5] = 0; // 0 || 0 + carry -= vli_sub(result, result, tmp, ndigits); + + /* d3 */ + tmp[0] = 0; // 0 || 0 + tmp[1] = AND64H(product[11]); //a23|| 0 + tmp[2] = product[11]>>32; // 0 ||a23 + tmp[3] = 0; // 0 || 0 + tmp[4] = 0; // 0 || 0 + tmp[5] = 0; // 0 || 0 + carry -= vli_sub(result, result, tmp, ndigits); + + if (carry < 0) { + do { + carry += vli_add(result, result, curve_prime, ndigits); + } while (carry < 0); + } else { + while (carry || vli_cmp(curve_prime, result, ndigits) != 1) + carry -= vli_sub(result, result, curve_prime, ndigits); + } + +} + +#undef SL32OR32 +#undef AND64H +#undef AND64L + +/* Computes result = product % curve_prime + * from "Mathematical routines for the NIST prime elliptic curves" + */ +static void vli_mmod_fast_521(u64 *result, const u64 *product, + const u64 *curve_prime, u64 *tmp) +{ + int carry; + const unsigned int ndigits = 9; + + /* t 512 bits + 9 bits a0 .. a520 */ + vli_set(result, product, 9); + result[8] &= 0x000001ff; + + /* t 512 bits + 9 bits a521 .. a1041 */ + vli_set(tmp, product + 8, ndigits); + vli_rshift(tmp, tmp, 9, ndigits); + + carry = vli_add(result, result, tmp, ndigits); + + while (carry || vli_cmp(curve_prime, result, ndigits) != 1) + carry -= vli_sub(result, result, curve_prime, ndigits); +} + /* Computes result = product % curve_prime for different curve_primes. * * Note that curve_primes are distinguished just by heuristic check and * not by complete conformance check. */ static bool vli_mmod_fast(u64 *result, u64 *product, - const u64 *curve_prime, unsigned int ndigits) + const struct ecc_curve *curve) { u64 tmp[2 * ECC_MAX_DIGITS]; + const u64 *curve_prime = curve->p; + const unsigned int ndigits = curve->g.ndigits; - /* Currently, both NIST primes have -1 in lowest qword. */ - if (curve_prime[0] != -1ull) { + /* Currently, all NIST have name nist_*. */ + if (strncmp(curve->name, "nist_", 5) != 0) { /* Try to handle Pseudo-Marsenne primes. */ if (curve_prime[ndigits - 1] == -1ull) { vli_mmod_special(result, product, curve_prime, @@ -809,6 +971,12 @@ static bool vli_mmod_fast(u64 *result, u64 *product, case 4: vli_mmod_fast_256(result, product, curve_prime, tmp); break; + case 6: + vli_mmod_fast_384(result, product, curve_prime, tmp); + break; + case 9: + vli_mmod_fast_521(result, product, curve_prime, tmp); + break; default: pr_err_ratelimited("ecc: unsupported digits size!\n"); return false; @@ -830,25 +998,38 @@ void vli_mod_mult_slow(u64 *result, const u64 *left, const u64 *right, } EXPORT_SYMBOL(vli_mod_mult_slow); +/* Computes result = input % curve_prime. */ +void vli_mod_slow(u64 *result, const u64 *input, + const u64 *mod, unsigned int ndigits) +{ + u64 product[ECC_MAX_DIGITS * 2] = { 0 }; + + vli_set(&product[0], input, ndigits); + vli_mmod_slow(result, product, mod, ndigits); +} +EXPORT_SYMBOL(vli_mod_slow); + /* Computes result = (left * right) % curve_prime. */ -static void vli_mod_mult_fast(u64 *result, const u64 *left, const u64 *right, - const u64 *curve_prime, unsigned int ndigits) +void vli_mod_mult_fast(u64 *result, const u64 *left, const u64 *right, + const struct ecc_curve *curve) { u64 product[2 * ECC_MAX_DIGITS]; - vli_mult(product, left, right, ndigits); - vli_mmod_fast(result, product, curve_prime, ndigits); + vli_mult(product, left, right, curve->g.ndigits); + vli_mmod_fast(result, product, curve); } +EXPORT_SYMBOL(vli_mod_mult_fast); /* Computes result = left^2 % curve_prime. */ -static void vli_mod_square_fast(u64 *result, const u64 *left, - const u64 *curve_prime, unsigned int ndigits) +void vli_mod_square_fast(u64 *result, const u64 *left, + const struct ecc_curve *curve) { u64 product[2 * ECC_MAX_DIGITS]; - vli_square(product, left, ndigits); - vli_mmod_fast(result, product, curve_prime, ndigits); + vli_square(product, left, curve->g.ndigits); + vli_mmod_fast(result, product, curve); } +EXPORT_SYMBOL(vli_mod_square_fast); #define EVEN(vli) (!(vli[0] & 1)) /* Computes result = (1 / p_input) % mod. All VLIs are the same size. @@ -933,11 +1114,12 @@ EXPORT_SYMBOL(vli_mod_inv); /* ------ Point operations ------ */ /* Returns true if p_point is the point at infinity, false otherwise. */ -static bool ecc_point_is_zero(const struct ecc_point *point) +bool ecc_point_is_zero(const struct ecc_point *point) { return (vli_is_zero(point->x, point->ndigits) && vli_is_zero(point->y, point->ndigits)); } +EXPORT_SYMBOL(ecc_point_is_zero); /* Point multiplication algorithm using Montgomery's ladder with co-Z * coordinates. From https://eprint.iacr.org/2011/338.pdf @@ -945,25 +1127,27 @@ static bool ecc_point_is_zero(const struct ecc_point *point) /* Double in place */ static void ecc_point_double_jacobian(u64 *x1, u64 *y1, u64 *z1, - u64 *curve_prime, unsigned int ndigits) + const struct ecc_curve *curve) { /* t1 = x, t2 = y, t3 = z */ u64 t4[ECC_MAX_DIGITS]; u64 t5[ECC_MAX_DIGITS]; + const u64 *curve_prime = curve->p; + const unsigned int ndigits = curve->g.ndigits; if (vli_is_zero(z1, ndigits)) return; /* t4 = y1^2 */ - vli_mod_square_fast(t4, y1, curve_prime, ndigits); + vli_mod_square_fast(t4, y1, curve); /* t5 = x1*y1^2 = A */ - vli_mod_mult_fast(t5, x1, t4, curve_prime, ndigits); + vli_mod_mult_fast(t5, x1, t4, curve); /* t4 = y1^4 */ - vli_mod_square_fast(t4, t4, curve_prime, ndigits); + vli_mod_square_fast(t4, t4, curve); /* t2 = y1*z1 = z3 */ - vli_mod_mult_fast(y1, y1, z1, curve_prime, ndigits); + vli_mod_mult_fast(y1, y1, z1, curve); /* t3 = z1^2 */ - vli_mod_square_fast(z1, z1, curve_prime, ndigits); + vli_mod_square_fast(z1, z1, curve); /* t1 = x1 + z1^2 */ vli_mod_add(x1, x1, z1, curve_prime, ndigits); @@ -972,7 +1156,7 @@ static void ecc_point_double_jacobian(u64 *x1, u64 *y1, u64 *z1, /* t3 = x1 - z1^2 */ vli_mod_sub(z1, x1, z1, curve_prime, ndigits); /* t1 = x1^2 - z1^4 */ - vli_mod_mult_fast(x1, x1, z1, curve_prime, ndigits); + vli_mod_mult_fast(x1, x1, z1, curve); /* t3 = 2*(x1^2 - z1^4) */ vli_mod_add(z1, x1, x1, curve_prime, ndigits); @@ -989,7 +1173,7 @@ static void ecc_point_double_jacobian(u64 *x1, u64 *y1, u64 *z1, /* t1 = 3/2*(x1^2 - z1^4) = B */ /* t3 = B^2 */ - vli_mod_square_fast(z1, x1, curve_prime, ndigits); + vli_mod_square_fast(z1, x1, curve); /* t3 = B^2 - A */ vli_mod_sub(z1, z1, t5, curve_prime, ndigits); /* t3 = B^2 - 2A = x3 */ @@ -997,7 +1181,7 @@ static void ecc_point_double_jacobian(u64 *x1, u64 *y1, u64 *z1, /* t5 = A - x3 */ vli_mod_sub(t5, t5, z1, curve_prime, ndigits); /* t1 = B * (A - x3) */ - vli_mod_mult_fast(x1, x1, t5, curve_prime, ndigits); + vli_mod_mult_fast(x1, x1, t5, curve); /* t4 = B * (A - x3) - y1^4 = y3 */ vli_mod_sub(t4, x1, t4, curve_prime, ndigits); @@ -1007,23 +1191,22 @@ static void ecc_point_double_jacobian(u64 *x1, u64 *y1, u64 *z1, } /* Modify (x1, y1) => (x1 * z^2, y1 * z^3) */ -static void apply_z(u64 *x1, u64 *y1, u64 *z, u64 *curve_prime, - unsigned int ndigits) +static void apply_z(u64 *x1, u64 *y1, u64 *z, const struct ecc_curve *curve) { u64 t1[ECC_MAX_DIGITS]; - vli_mod_square_fast(t1, z, curve_prime, ndigits); /* z^2 */ - vli_mod_mult_fast(x1, x1, t1, curve_prime, ndigits); /* x1 * z^2 */ - vli_mod_mult_fast(t1, t1, z, curve_prime, ndigits); /* z^3 */ - vli_mod_mult_fast(y1, y1, t1, curve_prime, ndigits); /* y1 * z^3 */ + vli_mod_square_fast(t1, z, curve); /* z^2 */ + vli_mod_mult_fast(x1, x1, t1, curve); /* x1 * z^2 */ + vli_mod_mult_fast(t1, t1, z, curve); /* z^3 */ + vli_mod_mult_fast(y1, y1, t1, curve); /* y1 * z^3 */ } /* P = (x1, y1) => 2P, (x2, y2) => P' */ static void xycz_initial_double(u64 *x1, u64 *y1, u64 *x2, u64 *y2, - u64 *p_initial_z, u64 *curve_prime, - unsigned int ndigits) + u64 *p_initial_z, const struct ecc_curve *curve) { u64 z[ECC_MAX_DIGITS]; + const unsigned int ndigits = curve->g.ndigits; vli_set(x2, x1, ndigits); vli_set(y2, y1, ndigits); @@ -1034,35 +1217,37 @@ static void xycz_initial_double(u64 *x1, u64 *y1, u64 *x2, u64 *y2, if (p_initial_z) vli_set(z, p_initial_z, ndigits); - apply_z(x1, y1, z, curve_prime, ndigits); + apply_z(x1, y1, z, curve); - ecc_point_double_jacobian(x1, y1, z, curve_prime, ndigits); + ecc_point_double_jacobian(x1, y1, z, curve); - apply_z(x2, y2, z, curve_prime, ndigits); + apply_z(x2, y2, z, curve); } /* Input P = (x1, y1, Z), Q = (x2, y2, Z) * Output P' = (x1', y1', Z3), P + Q = (x3, y3, Z3) * or P => P', Q => P + Q */ -static void xycz_add(u64 *x1, u64 *y1, u64 *x2, u64 *y2, u64 *curve_prime, - unsigned int ndigits) +static void xycz_add(u64 *x1, u64 *y1, u64 *x2, u64 *y2, + const struct ecc_curve *curve) { /* t1 = X1, t2 = Y1, t3 = X2, t4 = Y2 */ u64 t5[ECC_MAX_DIGITS]; + const u64 *curve_prime = curve->p; + const unsigned int ndigits = curve->g.ndigits; /* t5 = x2 - x1 */ vli_mod_sub(t5, x2, x1, curve_prime, ndigits); /* t5 = (x2 - x1)^2 = A */ - vli_mod_square_fast(t5, t5, curve_prime, ndigits); + vli_mod_square_fast(t5, t5, curve); /* t1 = x1*A = B */ - vli_mod_mult_fast(x1, x1, t5, curve_prime, ndigits); + vli_mod_mult_fast(x1, x1, t5, curve); /* t3 = x2*A = C */ - vli_mod_mult_fast(x2, x2, t5, curve_prime, ndigits); + vli_mod_mult_fast(x2, x2, t5, curve); /* t4 = y2 - y1 */ vli_mod_sub(y2, y2, y1, curve_prime, ndigits); /* t5 = (y2 - y1)^2 = D */ - vli_mod_square_fast(t5, y2, curve_prime, ndigits); + vli_mod_square_fast(t5, y2, curve); /* t5 = D - B */ vli_mod_sub(t5, t5, x1, curve_prime, ndigits); @@ -1071,11 +1256,11 @@ static void xycz_add(u64 *x1, u64 *y1, u64 *x2, u64 *y2, u64 *curve_prime, /* t3 = C - B */ vli_mod_sub(x2, x2, x1, curve_prime, ndigits); /* t2 = y1*(C - B) */ - vli_mod_mult_fast(y1, y1, x2, curve_prime, ndigits); + vli_mod_mult_fast(y1, y1, x2, curve); /* t3 = B - x3 */ vli_mod_sub(x2, x1, t5, curve_prime, ndigits); /* t4 = (y2 - y1)*(B - x3) */ - vli_mod_mult_fast(y2, y2, x2, curve_prime, ndigits); + vli_mod_mult_fast(y2, y2, x2, curve); /* t4 = y3 */ vli_mod_sub(y2, y2, y1, curve_prime, ndigits); @@ -1086,22 +1271,24 @@ static void xycz_add(u64 *x1, u64 *y1, u64 *x2, u64 *y2, u64 *curve_prime, * Output P + Q = (x3, y3, Z3), P - Q = (x3', y3', Z3) * or P => P - Q, Q => P + Q */ -static void xycz_add_c(u64 *x1, u64 *y1, u64 *x2, u64 *y2, u64 *curve_prime, - unsigned int ndigits) +static void xycz_add_c(u64 *x1, u64 *y1, u64 *x2, u64 *y2, + const struct ecc_curve *curve) { /* t1 = X1, t2 = Y1, t3 = X2, t4 = Y2 */ u64 t5[ECC_MAX_DIGITS]; u64 t6[ECC_MAX_DIGITS]; u64 t7[ECC_MAX_DIGITS]; + const u64 *curve_prime = curve->p; + const unsigned int ndigits = curve->g.ndigits; /* t5 = x2 - x1 */ vli_mod_sub(t5, x2, x1, curve_prime, ndigits); /* t5 = (x2 - x1)^2 = A */ - vli_mod_square_fast(t5, t5, curve_prime, ndigits); + vli_mod_square_fast(t5, t5, curve); /* t1 = x1*A = B */ - vli_mod_mult_fast(x1, x1, t5, curve_prime, ndigits); + vli_mod_mult_fast(x1, x1, t5, curve); /* t3 = x2*A = C */ - vli_mod_mult_fast(x2, x2, t5, curve_prime, ndigits); + vli_mod_mult_fast(x2, x2, t5, curve); /* t4 = y2 + y1 */ vli_mod_add(t5, y2, y1, curve_prime, ndigits); /* t4 = y2 - y1 */ @@ -1110,29 +1297,29 @@ static void xycz_add_c(u64 *x1, u64 *y1, u64 *x2, u64 *y2, u64 *curve_prime, /* t6 = C - B */ vli_mod_sub(t6, x2, x1, curve_prime, ndigits); /* t2 = y1 * (C - B) */ - vli_mod_mult_fast(y1, y1, t6, curve_prime, ndigits); + vli_mod_mult_fast(y1, y1, t6, curve); /* t6 = B + C */ vli_mod_add(t6, x1, x2, curve_prime, ndigits); /* t3 = (y2 - y1)^2 */ - vli_mod_square_fast(x2, y2, curve_prime, ndigits); + vli_mod_square_fast(x2, y2, curve); /* t3 = x3 */ vli_mod_sub(x2, x2, t6, curve_prime, ndigits); /* t7 = B - x3 */ vli_mod_sub(t7, x1, x2, curve_prime, ndigits); /* t4 = (y2 - y1)*(B - x3) */ - vli_mod_mult_fast(y2, y2, t7, curve_prime, ndigits); + vli_mod_mult_fast(y2, y2, t7, curve); /* t4 = y3 */ vli_mod_sub(y2, y2, y1, curve_prime, ndigits); /* t7 = (y2 + y1)^2 = F */ - vli_mod_square_fast(t7, t5, curve_prime, ndigits); + vli_mod_square_fast(t7, t5, curve); /* t7 = x3' */ vli_mod_sub(t7, t7, t6, curve_prime, ndigits); /* t6 = x3' - B */ vli_mod_sub(t6, t7, x1, curve_prime, ndigits); /* t6 = (y2 + y1)*(x3' - B) */ - vli_mod_mult_fast(t6, t6, t5, curve_prime, ndigits); + vli_mod_mult_fast(t6, t6, t5, curve); /* t2 = y3' */ vli_mod_sub(y1, t6, y1, curve_prime, ndigits); @@ -1162,41 +1349,37 @@ static void ecc_point_mult(struct ecc_point *result, vli_set(rx[1], point->x, ndigits); vli_set(ry[1], point->y, ndigits); - xycz_initial_double(rx[1], ry[1], rx[0], ry[0], initial_z, curve_prime, - ndigits); + xycz_initial_double(rx[1], ry[1], rx[0], ry[0], initial_z, curve); for (i = num_bits - 2; i > 0; i--) { nb = !vli_test_bit(scalar, i); - xycz_add_c(rx[1 - nb], ry[1 - nb], rx[nb], ry[nb], curve_prime, - ndigits); - xycz_add(rx[nb], ry[nb], rx[1 - nb], ry[1 - nb], curve_prime, - ndigits); + xycz_add_c(rx[1 - nb], ry[1 - nb], rx[nb], ry[nb], curve); + xycz_add(rx[nb], ry[nb], rx[1 - nb], ry[1 - nb], curve); } nb = !vli_test_bit(scalar, 0); - xycz_add_c(rx[1 - nb], ry[1 - nb], rx[nb], ry[nb], curve_prime, - ndigits); + xycz_add_c(rx[1 - nb], ry[1 - nb], rx[nb], ry[nb], curve); /* Find final 1/Z value. */ /* X1 - X0 */ vli_mod_sub(z, rx[1], rx[0], curve_prime, ndigits); /* Yb * (X1 - X0) */ - vli_mod_mult_fast(z, z, ry[1 - nb], curve_prime, ndigits); + vli_mod_mult_fast(z, z, ry[1 - nb], curve); /* xP * Yb * (X1 - X0) */ - vli_mod_mult_fast(z, z, point->x, curve_prime, ndigits); + vli_mod_mult_fast(z, z, point->x, curve); /* 1 / (xP * Yb * (X1 - X0)) */ vli_mod_inv(z, z, curve_prime, point->ndigits); /* yP / (xP * Yb * (X1 - X0)) */ - vli_mod_mult_fast(z, z, point->y, curve_prime, ndigits); + vli_mod_mult_fast(z, z, point->y, curve); /* Xb * yP / (xP * Yb * (X1 - X0)) */ - vli_mod_mult_fast(z, z, rx[1 - nb], curve_prime, ndigits); + vli_mod_mult_fast(z, z, rx[1 - nb], curve); /* End 1/Z calculation */ - xycz_add(rx[nb], ry[nb], rx[1 - nb], ry[1 - nb], curve_prime, ndigits); + xycz_add(rx[nb], ry[nb], rx[1 - nb], ry[1 - nb], curve); - apply_z(rx[0], ry[0], z, curve_prime, ndigits); + apply_z(rx[0], ry[0], z, curve); vli_set(result->x, rx[0], ndigits); vli_set(result->y, ry[0], ndigits); @@ -1217,9 +1400,9 @@ static void ecc_point_add(const struct ecc_point *result, vli_mod_sub(z, result->x, p->x, curve->p, ndigits); vli_set(px, p->x, ndigits); vli_set(py, p->y, ndigits); - xycz_add(px, py, result->x, result->y, curve->p, ndigits); + xycz_add(px, py, result->x, result->y, curve); vli_mod_inv(z, z, curve->p, ndigits); - apply_z(result->x, result->y, z, curve->p, ndigits); + apply_z(result->x, result->y, z, curve); } /* Computes R = u1P + u2Q mod p using Shamir's trick. @@ -1248,8 +1431,7 @@ void ecc_point_mult_shamir(const struct ecc_point *result, points[2] = q; points[3] = ∑ - num_bits = max(vli_num_bits(u1, ndigits), - vli_num_bits(u2, ndigits)); + num_bits = max(vli_num_bits(u1, ndigits), vli_num_bits(u2, ndigits)); i = num_bits - 1; idx = (!!vli_test_bit(u1, i)) | ((!!vli_test_bit(u2, i)) << 1); point = points[idx]; @@ -1260,7 +1442,7 @@ void ecc_point_mult_shamir(const struct ecc_point *result, z[0] = 1; for (--i; i >= 0; i--) { - ecc_point_double_jacobian(rx, ry, z, curve->p, ndigits); + ecc_point_double_jacobian(rx, ry, z, curve); idx = (!!vli_test_bit(u1, i)) | ((!!vli_test_bit(u2, i)) << 1); point = points[idx]; if (point) { @@ -1270,14 +1452,14 @@ void ecc_point_mult_shamir(const struct ecc_point *result, vli_set(tx, point->x, ndigits); vli_set(ty, point->y, ndigits); - apply_z(tx, ty, z, curve->p, ndigits); + apply_z(tx, ty, z, curve); vli_mod_sub(tz, rx, tx, curve->p, ndigits); - xycz_add(tx, ty, rx, ry, curve->p, ndigits); - vli_mod_mult_fast(z, z, tz, curve->p, ndigits); + xycz_add(tx, ty, rx, ry, curve); + vli_mod_mult_fast(z, z, tz, curve); } } vli_mod_inv(z, z, curve->p, ndigits); - apply_z(rx, ry, z, curve->p, ndigits); + apply_z(rx, ry, z, curve); } EXPORT_SYMBOL(ecc_point_mult_shamir); @@ -1441,10 +1623,10 @@ int ecc_is_pubkey_valid_partial(const struct ecc_curve *curve, return -EINVAL; /* Check 3: Verify that y^2 == (x^3 + a·x + b) mod p */ - vli_mod_square_fast(yy, pk->y, curve->p, pk->ndigits); /* y^2 */ - vli_mod_square_fast(xxx, pk->x, curve->p, pk->ndigits); /* x^2 */ - vli_mod_mult_fast(xxx, xxx, pk->x, curve->p, pk->ndigits); /* x^3 */ - vli_mod_mult_fast(w, curve->a, pk->x, curve->p, pk->ndigits); /* a·x */ + vli_mod_square_fast(yy, pk->y, curve); /* y^2 */ + vli_mod_square_fast(xxx, pk->x, curve); /* x^2 */ + vli_mod_mult_fast(xxx, xxx, pk->x, curve); /* x^3 */ + vli_mod_mult_fast(w, curve->a, pk->x, curve); /* a·x */ vli_mod_add(w, w, curve->b, curve->p, pk->ndigits); /* a·x + b */ vli_mod_add(w, w, xxx, curve->p, pk->ndigits); /* x^3 + a·x + b */ if (vli_cmp(yy, w, pk->ndigits) != 0) /* Equation */ diff --git a/crypto/ecc.h b/crypto/ecc.h index d4e546b9ad79..f02ea6cfd10d 100644 --- a/crypto/ecc.h +++ b/crypto/ecc.h @@ -29,7 +29,9 @@ /* One digit is u64 qword. */ #define ECC_CURVE_NIST_P192_DIGITS 3 #define ECC_CURVE_NIST_P256_DIGITS 4 -#define ECC_MAX_DIGITS (512 / 64) +#define ECC_CURVE_NIST_P384_DIGITS 6 +#define ECC_CURVE_NIST_P521_DIGITS 9 +#define ECC_MAX_DIGITS (ECC_CURVE_NIST_P521_DIGITS) #define ECC_DIGITS_TO_BYTES_SHIFT 3 @@ -147,6 +149,9 @@ int crypto_ecdh_shared_secret(unsigned int curve_id, unsigned int ndigits, int ecc_is_pubkey_valid_partial(const struct ecc_curve *curve, struct ecc_point *pk); +/* Returns true if p_point is the point at infinity, false otherwise. */ +bool ecc_point_is_zero(const struct ecc_point *point); + /** * ecc_is_pubkey_valid_full() - Full public key validation * @@ -225,6 +230,22 @@ void vli_from_le64(u64 *dest, const void *src, unsigned int ndigits); void vli_mod_inv(u64 *result, const u64 *input, const u64 *mod, unsigned int ndigits); +/** + * vli_mod_slow() - Computes result = product % mod, where product is 2N words + * long. + * Reference: Ken MacKay's micro-ecc. + * Currently only designed to work for curve_p or curve_n. + * + * @result: where to write result value + * @product: vli number to operate mod on + * @mod: modulus + * @ndigits: length of all vlis + * + * Note: Assumes that mod is big enough curve order. + */ +void vli_mod_slow(u64 *result, const u64 *input, const u64 *mod, + unsigned int ndigits); + /** * vli_mod_mult_slow() - Modular multiplication * @@ -239,6 +260,42 @@ void vli_mod_inv(u64 *result, const u64 *input, const u64 *mod, void vli_mod_mult_slow(u64 *result, const u64 *left, const u64 *right, const u64 *mod, unsigned int ndigits); +/* Computes result = (left + right) % mod. + * Assumes that left < mod and right < mod, result != mod. + */ +void vli_mod_add(u64 *result, const u64 *left, const u64 *right, + const u64 *mod, unsigned int ndigits); + +/** + * vli_mod_fast() - Computes result = product % curve_prime for different + * curve_primes. + * + * Note that curve_primes are distinguished just by heuristic check and + * not by complete conformance check. + * + * @result: where to write result value + * @input: vli number to multiply with @right + * @mod: mod + * @ndigits: length of all vlis + * + * Note: Assumes that mod is big enough curve order. + */ +void vli_mod_fast(u64 *result, const u64 *input, const struct ecc_curve *curve); + +/** + * vli_mod_mult_fast() - Modular multiplication + * + * @result: where to write result value + * @left: vli number to multiply with @right + * @right: vli number to multiply with @left + * @mod: modulus + * @ndigits: length of all vlis + * + * Note: Assumes that mod is big enough curve order. + */ +void vli_mod_mult_fast(u64 *result, const u64 *left, const u64 *right, + const struct ecc_curve *curve); + /** * ecc_point_mult_shamir() - Add two points multiplied by scalars * From patchwork Fri Jan 29 21:25:35 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Saulo Alessandre de Lima X-Patchwork-Id: 373851 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-10.7 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 6379DC433DB for ; Fri, 29 Jan 2021 21:27:35 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id DE9F464E0B for ; Fri, 29 Jan 2021 21:27:34 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233418AbhA2V1a (ORCPT ); Fri, 29 Jan 2021 16:27:30 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45862 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233461AbhA2V1T (ORCPT ); Fri, 29 Jan 2021 16:27:19 -0500 Received: from mail-qk1-x72f.google.com (mail-qk1-x72f.google.com [IPv6:2607:f8b0:4864:20::72f]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id CD33DC0613D6 for ; Fri, 29 Jan 2021 13:26:38 -0800 (PST) Received: by mail-qk1-x72f.google.com with SMTP id 19so10211863qkh.3 for ; Fri, 29 Jan 2021 13:26:38 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=PbpAVMxLXOUnyRcmPHfMFHESAeL4Z3hLTQ92fdHFQqk=; b=rsE9JKIi+Ga6yA8hR36U55d/z1RzozbkpAvh6pS/d6v/AvAYixNA/VrslJQ1KMdcHN ETnPoqPBAO1XINkDnj3dCHow1kbt9otggxLGiLWYLPNU/pP/nkXcWgTi8wEPzW1x+eMp sLdSlGuiBa0M5xDU5vnncSHWFIytiAYezLe3GAmrB9v2MCAbn1lujzYMceerrQvhM4Nx 5tds7tfbP2hemhM8fTKWpTVwx/GzprEnlf5v6T0cQeC+hfbNWpu1o2HIUaV+oI67TNgD oLLJn2RyTJ0x5+kgV3Wpx7ZjkddIIRC6q6TYsFGf7zsQxqLNN01croY3ljm/q/vcIC43 D2dg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=PbpAVMxLXOUnyRcmPHfMFHESAeL4Z3hLTQ92fdHFQqk=; b=nbTpwMmrnPoAV6DoNw4yyl2Zre7bio+W/pNHkr6MMPsMBEHaF1y+sSc5V/KfvoysnZ uQ4unzuMcal3mC1uNd8xeT1z3jkI8+96EPlwleqnlk6YIKhlrHwagArMh9Dgq7pgzCd8 NLQiPH+WGEwOvpFRJxX8EAtc3vj1QDI33lrKCPiipubabj10lQQK1+vEDvefFY4znFl2 JIrGqi/1uZVECGUJy1X2adDKWFt2D2ib49n8rGHpnN3oBdoik9slpR2TRJdh3ib8ViO6 EbaTdIGnw30h6yFbopWC6TBLGclM+0X/CVhz3BWfPPTgrxbKP02sYlSoRjHb31cowkvA Dz4w== X-Gm-Message-State: AOAM533y1JvlZb/6S/bxgvkJ4MOmJeElKQUeuH7iSK4VP7+rVDCSuWm9 aY7V0Cbfb2PoM0KH2hN0lX1hZ7WvvQ0C42F2 X-Google-Smtp-Source: ABdhPJwe/kwOkymmxWvKq3I+ofo7uISWP9cloAkOSf3gUFj9Choy5ylDJbMBnwAUydMf3SzrLW3wjw== X-Received: by 2002:a37:64c2:: with SMTP id y185mr6150370qkb.55.1611955597365; Fri, 29 Jan 2021 13:26:37 -0800 (PST) Received: from warrior-desktop.domains. ([189.61.66.20]) by smtp.gmail.com with ESMTPSA id b194sm6763995qkc.102.2021.01.29.13.26.34 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 29 Jan 2021 13:26:36 -0800 (PST) From: Saulo Alessandre To: linux-crypto@vger.kernel.org Cc: Herbert Xu , "David S. Miller" , Vitaly Chikunov , Tianjia Zhang , Saulo Alessandre Subject: [PATCH v2 4/4] ecdsa: implements ecdsa signature verification Date: Fri, 29 Jan 2021 18:25:35 -0300 Message-Id: <20210129212535.2257493-5-saulo.alessandre@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210129212535.2257493-1-saulo.alessandre@gmail.com> References: <20210129212535.2257493-1-saulo.alessandre@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-crypto@vger.kernel.org From: Saulo Alessandre * Documentation/admin-guide/module-signing.rst - Documents how to generate certificate and signature for (ECDSA). * crypto/Kconfig - ECDSA added into kernel Public-key cryptography section. * crypto/Makefile - add ECDSA objects and asn1 params to compile. * crypto/ecdsa.c - Elliptical Curve DSA verify implementation * crypto/ecdsa_params.asn1 - Elliptical Curve DSA verify definitions * crypto/ecdsa_signature.asn1 - Elliptical Curve DSA asn.1 parameters * crypto/testmgr.c - test_akcipher_one - modified to reflect the real code call for nist code; - alg_test_descs - added ecdsa vector for test; * crypto/testmgr.h - ecdsa_tv_template - added to test ecdsa implementation; --- Documentation/admin-guide/module-signing.rst | 10 + crypto/Kconfig | 12 + crypto/Makefile | 7 + crypto/ecdsa.c | 509 +++++++++++++++++++ crypto/ecdsa_params.asn1 | 1 + crypto/ecdsa_signature.asn1 | 6 + crypto/testmgr.c | 17 +- crypto/testmgr.h | 78 +++ 8 files changed, 638 insertions(+), 2 deletions(-) create mode 100644 crypto/ecdsa.c create mode 100644 crypto/ecdsa_params.asn1 create mode 100644 crypto/ecdsa_signature.asn1 diff --git a/Documentation/admin-guide/module-signing.rst b/Documentation/admin-guide/module-signing.rst index 7d7c7c8a545c..00ee487de84d 100644 --- a/Documentation/admin-guide/module-signing.rst +++ b/Documentation/admin-guide/module-signing.rst @@ -174,6 +174,16 @@ The full pathname for the resulting kernel_key.pem file can then be specified in the ``CONFIG_MODULE_SIG_KEY`` option, and the certificate and key therein will be used instead of an autogenerated keypair. +It is also possible use the key private/public files using the ecdsa +alghorithm that is more fast than rsa. For this, configure ``CONFIG_CRYPTO_ECDSA`` +and for generate key and certificate use the openssl commands. + + openssl ecparam -gnenkey \ + -name -noout -out kernel_key.pem + openssl req -new -key kernel_key.pem -x509 -nodes -days 36500 -out kernel_key.x509 + +To sign with ecdsa use the same way or manually using scripts/sign-file. + ========================= Public keys in the kernel diff --git a/crypto/Kconfig b/crypto/Kconfig index 9779c7f7531f..79bec162d9dd 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -224,6 +224,18 @@ config CRYPTO_RSA help Generic implementation of the RSA public key algorithm. +config CRYPTO_ECDSA + tristate "ECDSA algorithm" + select CRYPTO_AKCIPHER + select CRYPTO_MANAGER + select MPILIB + select ASN1 + help + Generic implementation of the ECDSA eliptical curve public key algorithm. + FIPS 186-3, Digital Signature Standard using Mathematical routines for + the NIST prime elliptic curves April 05, 2010. Compatible with openssl + command line tools. + config CRYPTO_DH tristate "Diffie-Hellman algorithm" select CRYPTO_KPP diff --git a/crypto/Makefile b/crypto/Makefile index cf23affb1678..0e0b33106c82 100644 --- a/crypto/Makefile +++ b/crypto/Makefile @@ -176,6 +176,13 @@ ecdh_generic-y += ecdh.o ecdh_generic-y += ecdh_helper.o obj-$(CONFIG_CRYPTO_ECDH) += ecdh_generic.o +$(obj)/ecdsa_signature.asn1.o: $(obj)/ecdsa_signature.asn1.c $(obj)/ecdsa_signature.asn1.h +$(obj)/ecdsa_params.asn1.o: $(obj)/ecdsa_params.asn1.c $(obj)/ecdsa_params.asn1.h +clean-files += ecdsa_signature.asn1.c ecdsa_signature.asn1.h +clean-files += ecdsa_params.asn1.c ecdsa_params.asn1.h +ecdsa_generic-y := ecdsa_signature.asn1.o ecdsa_params.asn1.o ecdsa.o +obj-$(CONFIG_CRYPTO_ECDSA) += ecdsa_generic.o + $(obj)/ecrdsa_params.asn1.o: $(obj)/ecrdsa_params.asn1.c $(obj)/ecrdsa_params.asn1.h $(obj)/ecrdsa_pub_key.asn1.o: $(obj)/ecrdsa_pub_key.asn1.c $(obj)/ecrdsa_pub_key.asn1.h $(obj)/ecrdsa.o: $(obj)/ecrdsa_params.asn1.h $(obj)/ecrdsa_pub_key.asn1.h diff --git a/crypto/ecdsa.c b/crypto/ecdsa.c new file mode 100644 index 000000000000..f33258c21db2 --- /dev/null +++ b/crypto/ecdsa.c @@ -0,0 +1,509 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Elliptic Curve Digital Signature Algorithm for Cryptographic API + * + * Copyright (c) 2019 Saulo Alessandre + * + * References: + * Mathematical routines for the NIST prime elliptic curves April 05, 2010 + * Technical Guideline TR-03111 - Elliptic Curve Cryptography + * FIPS 186-3, Digital Signature Standard + * + * this code is strongly embased on the ecrdsa code, written by + * Vitaly Chikunov + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + */ + +#include +#include +#include "crypto/public_key.h" +#include +#include +#include +#include +#include +#include "ecc.h" +#include "ecc_curve_defs.h" +#include "ecdsa_signature.asn1.h" +#include "ecdsa_params.asn1.h" + +#define MAX_DIGEST_SIZE 64 + +#define ECDSA_MAX_BITS 521 +#define ECDSA_MAX_SIG_SIZE 140 +#define ECDSA_MAX_DIGITS 9 + +struct ecdsa_ctx { + enum OID algo_oid; /* overall public key oid */ + enum OID curve_oid; /* parameter */ + enum OID digest_oid; /* parameter */ + const struct ecc_curve *curve; /* curve from oid */ + unsigned int digest_len; /* parameter (bytes) */ + const char *digest; /* digest name from oid */ + unsigned int key_len; /* @key length (bytes) */ + const char *key; /* raw public key */ + struct ecc_point pub_key; + u64 _pubp[2][ECDSA_MAX_DIGITS]; /* point storage for @pub_key */ +}; + +struct ecdsa_sig_ctx { + u64 r[ECDSA_MAX_DIGITS]; + u64 s[ECDSA_MAX_DIGITS]; + int sig_size; + u8 ndigits; +}; + +static int check_digest_len(int len) +{ + switch (len) { + case 32: + case 48: + case 64: + return 0; + default: + return -1; + } +} + +static inline void ecc_swap_digits(const u64 *in, u64 *out, + unsigned int ndigits) +{ + const __be64 *src = (__force __be64 *) in; + int i; + + for (i = 0; i < ndigits; i++) + out[i] = be64_to_cpu(src[ndigits - 1 - i]); +} + +static int ecdsa_parse_sig_rs(struct ecdsa_sig_ctx *ctx, u64 *rs, + size_t hdrlen, unsigned char tag, + const void *value, size_t vlen) +{ + u8 ndigits; + // skip byte 0 if exists + const void *idx = value; + + if (*(u8 *) idx == 0x0) { + idx++; + vlen--; + } + ndigits = vlen / 8; + if (ndigits == ctx->ndigits) + ecc_swap_digits((const u64 *)idx, rs, ndigits); + else { + u8 nvalue[ECDSA_MAX_SIG_SIZE]; + const u8 start = (ctx->ndigits * 8) - vlen; + + memset(nvalue, 0, start); + memcpy(nvalue + start, idx, vlen); + ecc_swap_digits((const u64 *)nvalue, rs, ctx->ndigits); + vlen = ctx->ndigits * 8; + } + ctx->sig_size += vlen; + return 0; +} + +int ecdsa_parse_sig_r(void *context, size_t hdrlen, unsigned char tag, + const void *value, size_t vlen) +{ + struct ecdsa_sig_ctx *ctx = context; + + return ecdsa_parse_sig_rs(ctx, ctx->r, hdrlen, tag, value, vlen); +} + +int ecdsa_parse_sig_s(void *context, size_t hdrlen, unsigned char tag, + const void *value, size_t vlen) +{ + struct ecdsa_sig_ctx *ctx = context; + + return ecdsa_parse_sig_rs(ctx, ctx->s, hdrlen, tag, value, vlen); +} + +#define ASN_TAG_SIZE 5 + +static int ecdsa_verify(struct akcipher_request *req, enum OID oid) +{ + struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req); + struct ecdsa_ctx *ctx = akcipher_tfm_ctx(tfm); + struct ecdsa_sig_ctx ctx_sig; + u8 sig[ECDSA_MAX_SIG_SIZE]; + u8 digest[MAX_DIGEST_SIZE]; + u16 ndigits = ctx->pub_key.ndigits; + u16 min_digits; + u64 _r[ECDSA_MAX_DIGITS]; /* ecc_point x */ + u64 _s[ECDSA_MAX_DIGITS]; /* ecc_point y and temp s^{-1} */ + u64 e[ECDSA_MAX_DIGITS]; /* h \mod q */ + u64 v[ECDSA_MAX_DIGITS]; /* s^{-1}e \mod q */ + u64 u[ECDSA_MAX_DIGITS]; /* s^{-1}r \mod q */ + struct ecc_point cc = ECC_POINT_INIT(_r, _s, ndigits); /* reuse r, s */ + struct scatterlist *sgl_s, *sgl_d; + int err; + int i; + + if (lookup_oid_digest_info(oid, &ctx->digest, &ctx->digest_len, + &ctx->digest_oid)) + return -ENOPKG; + + min_digits = + (ndigits < ctx->digest_len / 8) ? ndigits : ctx->digest_len / 8; + + if (!ctx->curve || !ctx->digest || !req->src || !ctx->pub_key.x) + return -EBADMSG; + if (check_digest_len(req->dst_len)) { + pr_err("%s: invalid source digest size %d\n", + __func__, req->dst_len); + return -EBADMSG; + } + if (check_digest_len(ctx->digest_len)) { + pr_err("%s: invalid context digest size %d\n", + __func__, ctx->digest_len); + return -EBADMSG; + } + + sgl_s = req->src; + sgl_d = (((void *)req->src) + sizeof(struct scatterlist)); + + if (ctx->pub_key.ndigits != ctx->curve->g.ndigits || + WARN_ON(sgl_s->length > sizeof(sig)) || + WARN_ON(sgl_d->length > sizeof(digest))) { + pr_err("%s: invalid curve size g(%d) pub(%d)\n", + __func__, + ctx->curve->g.ndigits, ctx->pub_key.ndigits); + return -EBADMSG; + } + sg_copy_to_buffer(sgl_s, sg_nents_for_len(sgl_s, sgl_s->length), + sig, sizeof(sig)); + sg_copy_to_buffer(sgl_d, sg_nents_for_len(sgl_d, sgl_d->length), + digest, sizeof(digest)); + + ctx_sig.sig_size = 0; + ctx_sig.ndigits = ndigits; + err = + asn1_ber_decoder(&ecdsa_signature_decoder, &ctx_sig, sig, + sgl_s->length); + if (err < 0) + return err; + + /* Step 1: verify that 0 < r < q, 0 < s < q */ + if (vli_is_zero(ctx_sig.r, ndigits) || + vli_cmp(ctx_sig.r, ctx->curve->n, ndigits) == 1 || + vli_is_zero(ctx_sig.s, ndigits) || + vli_cmp(ctx_sig.s, ctx->curve->n, ndigits) == 1) + return -EKEYREJECTED; + + /* need truncate digest */ + for (i = min_digits; i < ndigits; i++) + e[i] = 0; + /* Step 2: calculate hash (h) of the message (passed as input) */ + /* Step 3: calculate e = h \mod q */ + vli_from_be64(e, digest, min_digits); + if (vli_cmp(e, ctx->curve->n, ndigits) == 1) + vli_sub(e, e, ctx->curve->n, ndigits); + if (vli_is_zero(e, ndigits)) + e[0] = 1; + + /* Step 4: calculate _s = s^{-1} \mod q */ + vli_mod_inv(_s, ctx_sig.s, ctx->curve->n, ndigits); + /* Step 5: calculate u = s^{-1} * e \mod q */ + vli_mod_mult_slow(u, _s, e, ctx->curve->n, ndigits); + /* Step 6: calculate v = s^{-1} * r \mod q */ + vli_mod_mult_slow(v, _s, ctx_sig.r, ctx->curve->n, ndigits); + /* Step 7: calculate cc = (x0, y0) = uG + vP */ + ecc_point_mult_shamir(&cc, u, &ctx->curve->g, v, &ctx->pub_key, + ctx->curve); + /* v = x0 mod q */ + vli_mod_slow(v, cc.x, ctx->curve->n, ndigits); + + /* Step 9: if X0 == r signature is valid */ + if (vli_cmp(v, ctx_sig.r, ndigits) == 0) + return 0; + + return -EKEYREJECTED; +} + +static int ecdsa_verify_256(struct akcipher_request *req) +{ + return ecdsa_verify(req, OID_id_ecdsa_with_sha256); +} + +static int ecdsa_verify_384(struct akcipher_request *req) +{ + return ecdsa_verify(req, OID_id_ecdsa_with_sha384); +} + +static int ecdsa_verify_512(struct akcipher_request *req) +{ + return ecdsa_verify(req, OID_id_ecdsa_with_sha512); +} + +static const struct ecc_curve *get_curve_by_oid(enum OID oid) +{ + switch (oid) { + case OID_id_secp192r1: + return &nist_p192; + case OID_id_secp256r1: + return &nist_p256; + case OID_id_secp384r1: + return &nist_p384; + case OID_id_secp521r1: + return &nist_p521; + default: + return NULL; + } +} + +int ecdsa_param_curve(void *context, size_t hdrlen, unsigned char tag, + const void *value, size_t vlen) +{ + struct ecdsa_ctx *ctx = context; + + ctx->curve_oid = look_up_OID(value, vlen); + if (!ctx->curve_oid) + return -EINVAL; + ctx->curve = get_curve_by_oid(ctx->curve_oid); + + return 0; +} + +/* Optional. If present should match expected digest algo OID. */ +int ecdsa_param_digest(void *context, size_t hdrlen, unsigned char tag, + const void *value, size_t vlen) +{ + struct ecdsa_ctx *ctx = context; + int digest_oid = look_up_OID(value, vlen); + + if (digest_oid != ctx->digest_oid) + return -EINVAL; + + return 0; +} + +int ecdsa_parse_pub_key(void *context, size_t hdrlen, unsigned char tag, + const void *value, size_t vlen) +{ + struct ecdsa_ctx *ctx = context; + + ctx->key = value; + ctx->key_len = vlen; + return 0; +} + +static u8 *pkey_unpack_u32(u32 *dst, void *src) +{ + memcpy(dst, src, sizeof(*dst)); + return src + sizeof(*dst); +} + +static inline void copy4be8(u64 *out, const u8 *in, u32 size) +{ + int i; + u8 *dst = (u8 *) out; + + *out = 0; + for (i = 0; i < size; i++) { + *dst = in[size - i - 1]; + dst++; + } +} + +static void convert4be(u64 *out, const u8 *in, u32 size) +{ + int i; + + while (*in == 0 && size > 0) { + in++; + size--; + } + in = in + size; + /* convert from BE */ + for (i = 0; i < size; i += 8) { + const u32 count = size - i; + const u32 limit = count >= 8 ? 8 : count; + const u8 *part = in - limit; + + if (limit == 8) + *out = get_unaligned_be64(part); + else + copy4be8(out, part, limit); + out++; + in -= limit; + } +} + +/* Parse BER encoded subjectPublicKey. */ +static int ecdsa_set_pub_key(struct crypto_akcipher *tfm, const void *key, + unsigned int keylen) +{ + struct ecdsa_ctx *ctx = akcipher_tfm_ctx(tfm); + unsigned int ndigits; + u32 algo, paramlen; + u8 *params; + int err; + const u8 nist_type = *(u8 *) key; + u8 half_pub; + + /* Key parameters is in the key after keylen. */ + params = (u8 *) key + keylen; + params = pkey_unpack_u32(&algo, params); + params = pkey_unpack_u32(¶mlen, params); + + ctx->algo_oid = algo; + + /* Parse SubjectPublicKeyInfo.AlgorithmIdentifier.parameters. */ + err = asn1_ber_decoder(&ecdsa_params_decoder, ctx, params, paramlen); + if (err < 0) + return err; + ctx->key = key; + ctx->key_len = keylen; + if (!ctx->curve) + return -ENOPKG; + + /* + * Accepts only uncompressed it's not accepted + */ + if (nist_type != NIST_UNPACKED_KEY_ID) + return -ENOPKG; + /* Skip nist type octet */ + ctx->key++; + ctx->key_len--; + if (ctx->key_len != NISTP256_PACKED_KEY_SIZE + && ctx->key_len != NISTP384_PACKED_KEY_SIZE + && ctx->key_len != NISTP521_PACKED_KEY_SIZE) + return -ENOPKG; + ndigits = ctx->key_len / sizeof(u64) / 2; + if (ndigits * 2 * sizeof(u64) < ctx->key_len) + ndigits++; + half_pub = ctx->key_len / 2; + /* + * Sizes of key_len and curve should match each other. + */ + if (ctx->curve->g.ndigits != ndigits) + return -ENOPKG; + ctx->pub_key = ECC_POINT_INIT(ctx->_pubp[0], ctx->_pubp[1], ndigits); + /* + * X509 stores key.x and key.y as BE + */ + if (ndigits != 9) { + vli_from_be64(ctx->pub_key.x, ctx->key, ndigits); + vli_from_be64(ctx->pub_key.y, ctx->key + half_pub, ndigits); + } else { + convert4be(ctx->pub_key.x, ctx->key, half_pub); + convert4be(ctx->pub_key.y, ctx->key + half_pub, half_pub); + } + err = ecc_is_pubkey_valid_partial(ctx->curve, &ctx->pub_key); + if (err) + return -EKEYREJECTED; + + return 0; +} + +static unsigned int ecdsa_max_size(struct crypto_akcipher *tfm) +{ + struct ecdsa_ctx *ctx = akcipher_tfm_ctx(tfm); + + /* + * Verify doesn't need any output, so it's just informational + * for keyctl to determine the key bit size. + */ + return ctx->pub_key.ndigits * sizeof(u64); +} + +static void ecdsa_exit_tfm(struct crypto_akcipher *tfm) +{ +} + +//static const struct s_ecdsa_template { +// const char *name; +// enum OID oid; +// size_t size; +// int (*ecdsa_verify)(struct akcipher_request *req); +//} ecdsa_templates[] = { +// {"ecdsa(sha256)", OID_id_ecdsa_with_sha256, ecdsa_verify}, +// {"ecdsa(sha384)", OID_id_ecdsa_with_sha384, ecdsa_verify}, +// {"ecdsa(sha512)", OID_id_ecdsa_with_sha512, ecdsa_verify}, +// NULL +//}; + +static struct akcipher_alg ecdsa_alg256 = { + .verify = ecdsa_verify_256, + .set_pub_key = ecdsa_set_pub_key, + .max_size = ecdsa_max_size, + .exit = ecdsa_exit_tfm, + .base = { + .cra_name = "ecdsa(sha256)", + .cra_driver_name = "ecdsa-generic", + .cra_priority = 100, + .cra_module = THIS_MODULE, + .cra_ctxsize = sizeof(struct ecdsa_ctx), + }, +}; + +static struct akcipher_alg ecdsa_alg384 = { + .verify = ecdsa_verify_384, + .set_pub_key = ecdsa_set_pub_key, + .max_size = ecdsa_max_size, + .exit = ecdsa_exit_tfm, + .base = { + .cra_name = "ecdsa(sha384)", + .cra_driver_name = "ecdsa-generic", + .cra_priority = 100, + .cra_module = THIS_MODULE, + .cra_ctxsize = sizeof(struct ecdsa_ctx), + }, +}; + +static struct akcipher_alg ecdsa_alg512 = { + .verify = ecdsa_verify_512, + .set_pub_key = ecdsa_set_pub_key, + .max_size = ecdsa_max_size, + .exit = ecdsa_exit_tfm, + .base = { + .cra_name = "ecdsa(sha512)", + .cra_driver_name = "ecdsa-generic", + .cra_priority = 100, + .cra_module = THIS_MODULE, + .cra_ctxsize = sizeof(struct ecdsa_ctx), + }, +}; + +static int __init ecdsa_mod_init(void) +{ + int result; + + result = crypto_register_akcipher(&ecdsa_alg256); + if (result) + goto out256; + result = crypto_register_akcipher(&ecdsa_alg384); + if (result) + goto out384; + result = crypto_register_akcipher(&ecdsa_alg512); + if (result) + goto out512; + return 0; + +out512: + crypto_unregister_akcipher(&ecdsa_alg384); +out384: + crypto_unregister_akcipher(&ecdsa_alg256); +out256: + return result; +} + +static void __exit ecdsa_mod_fini(void) +{ + crypto_unregister_akcipher(&ecdsa_alg256); + crypto_unregister_akcipher(&ecdsa_alg384); + crypto_unregister_akcipher(&ecdsa_alg512); +} + +subsys_initcall(ecdsa_mod_init); +module_exit(ecdsa_mod_fini); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Saulo Alessandre "); +MODULE_DESCRIPTION("EC-DSA generic algorithm"); +MODULE_ALIAS_CRYPTO("ecdsa-generic"); diff --git a/crypto/ecdsa_params.asn1 b/crypto/ecdsa_params.asn1 new file mode 100644 index 000000000000..f683aec27bd4 --- /dev/null +++ b/crypto/ecdsa_params.asn1 @@ -0,0 +1 @@ +EcdsaCurve ::= OBJECT IDENTIFIER ({ ecdsa_param_curve }) diff --git a/crypto/ecdsa_signature.asn1 b/crypto/ecdsa_signature.asn1 new file mode 100644 index 000000000000..378e73913865 --- /dev/null +++ b/crypto/ecdsa_signature.asn1 @@ -0,0 +1,6 @@ +EcdsaSignature ::= SEQUENCE { + signatureR INTEGER ({ ecdsa_parse_sig_r }), + signatureS INTEGER ({ ecdsa_parse_sig_s }) +} + +EcdsaPubKey ::= BIT STRING ({ ecdsa_parse_pub_key }) diff --git a/crypto/testmgr.c b/crypto/testmgr.c index 1a4103b1b202..3e8a6cf084de 100644 --- a/crypto/testmgr.c +++ b/crypto/testmgr.c @@ -3992,8 +3992,15 @@ static int test_akcipher_one(struct crypto_akcipher *tfm, memcpy(xbuf[0], m, m_size); sg_init_table(src_tab, 3); - sg_set_buf(&src_tab[0], xbuf[0], 8); - sg_set_buf(&src_tab[1], xbuf[0] + 8, m_size - 8); + if (vecs->algo == OID_id_ecdsa_with_sha256 || + vecs->algo == OID_id_ecdsa_with_sha384 || + vecs->algo == OID_id_ecdsa_with_sha512) { + sg_set_buf(&src_tab[0], xbuf[0], m_size); + sg_set_buf(&src_tab[1], xbuf[1], c_size); + } else { + sg_set_buf(&src_tab[0], xbuf[0], 8); + sg_set_buf(&src_tab[1], xbuf[0] + 8, m_size - 8); + } if (vecs->siggen_sigver_test) { if (WARN_ON(c_size > PAGE_SIZE)) goto free_all; @@ -4916,6 +4923,12 @@ static const struct alg_test_desc alg_test_descs[] = { .suite = { .kpp = __VECS(ecdh_tv_template) } + }, { + .alg = "ecdsa", + .test = alg_test_akcipher, + .suite = { + .akcipher = __VECS(ecdsa_tv_template) + } }, { .alg = "ecrdsa", .test = alg_test_akcipher, diff --git a/crypto/testmgr.h b/crypto/testmgr.h index 99aca08263d2..ad31d8deb3d7 100644 --- a/crypto/testmgr.h +++ b/crypto/testmgr.h @@ -566,6 +566,84 @@ static const struct akcipher_testvec rsa_tv_template[] = { } }; +/* + * EC-DSA test vectors + */ +static const struct akcipher_testvec ecdsa_tv_template[] = { + { + .key = + "\x04\x9c\x9e\x45\xe5\x61\xf4\x3d\xf8\x8f\xea\xdf\xce\x9a\xd5\x2a" + "\x9e\x7e\x8a\x0a\xef\xff\xad\x9c\x2e\x87\x8e\xa0\xa9\x40\x0a\x3d" + "\x7f\x01\x85\x8d\xd6\x36\xcf\x84\x56\x59\xb8\xd8\x3d\x20\x78\xe7" + "\xaf\x35\xa8\xeb\x89\x37\x0e\x52\xa7\x71\x81\x2f\x64\xbb\x1d\x6c" + "\x04", + .key_len = 65, + /* + * m is SHA256 hash of following message: + * "\x49\x41\xbe\x0a\x0c\xc9\xf6\x35\x51\xe4\x27\x56\x13\x71\x4b\xd0" + * "\x36\x92\x84\x89\x1b\xf8\x56\x4a\x72\x61\x14\x69\x4f\x5e\x98\xa5" + * "\x80\x5a\x37\x51\x1f\xd8\xf5\xb5\x63\xfc\xf4\xb1\xbb\x4d\x33\xa3" + * "\x1e\xb9\x75\x8b\x9c\xda\x7e\x6d\x3a\x77\x85\xf7\xfc\x4e\xe7\x64" + * "\x43\x10\x19\xa0\x59\xae\xe0\xad\x4b\xd3\xc4\x45\xf7\xb1\xc2\xc1" + * "\x65\x01\x41\x39\x5b\x45\x47\xed\x2b\x51\xed\xe3\xd0\x09\x10\xd2" + * "\x39\x6c\x4a\x3f\xe5\xd2\x20\xe6\xb0\x71\x7d\x5b\xed\x26\x60\xf1" + * "\xb4\x73\xd1\xdb\x7d\xc4\x19\x91\xee\xf6\x32\x76\xf2\x19\x7d\xb7" + */ + .m = + "\x3e\xc8\xa1\x26\x20\x54\x44\x52\x48\x0d\xe5\x66\xf3\xb3\xf5\x04" + "\xbe\x10\xa8\x48\x94\x22\x2d\xdd\xba\x7a\xb4\x76\x8d\x79\x98\x89", + .m_size = 32, + .params = /* ecdsaWithSHA512 */ + //"\x06\x08\x2a\x86\x48\xce\x3d\x04\x03\x04", + "\x06\x08\x2A\x86\x48\xCE\x3D\x03\x01\x07", + .param_len = 10, + .c = + "\x30\x44\x02\x20\x2b\xf7\x53\x42\xc2\x80\x52\xca\x9f\x54\x5e\x52" + "\xe2\x46\xa4\x83\xf4\x00\x59\x1e\x88\xd4\x7a\x88\x96\xb7\xee\xc7" + "\xbf\x2c\x1e\xd0\x02\x20\x46\x58\x95\x5f\x39\x75\x35\xaa\x73\x7d" + "\xe3\x87\x18\xad\x6d\x60\xd0\xc3\xb7\x21\x10\xeb\x77\x7b\x5a\xd4" + "\x52\x05\xc0\xfe\xa8\x46", + .c_size = 70, + .algo = OID_id_ecdsa_with_sha256, + .public_key_vec = true, + .siggen_sigver_test = true, + }, + { + .key = + "\x04\xee\x89\x69\x41\xa0\x10\xfe\x56\xbc\x50\x37\x6d\xa1\xfe" + "\x89\xa6\x34\xaf\x0a\x97\x7c\x7a\x5c\x13\x5f\xea\x5f\x36\x07" + "\x82\xd4\x4b\x09\x97\xd4\xf9\x91\xb9\x0e\x06\xd4\x3d\xd3\x87" + "\xc3\x1b\x00\x93\xc8\x0f\x8a\x45\xa9\xb7\x3d\xa0\xbf\xe3\xb3" + "\x0f\x9a\xf0\xbd\x70\x62\x16\x40\xc3\x83\x56\x25\xc3\x0f\x85" + "\xa2\xd3\x88\x89\xbd\x5b\x92\x27\x3f\x95\x77\xd0\xc1\x49\x07" + "\xe2\xa5\xd7\xb2\x5b\xba\xea", + .key_len = 97, + /* + * m is SHA256 hash of same previous message: + * "\x49\x41\xbe\x0a ... \xf2\x19\x7d\xb7" + */ + .m = + "\x3e\xc8\xa1\x26\x20\x54\x44\x52\x48\x0d\xe5\x66\xf3\xb3\xf5\x04" + "\xbe\x10\xa8\x48\x94\x22\x2d\xdd\xba\x7a\xb4\x76\x8d\x79\x98\x89", + .m_size = 32, + .params = /* ecdsaWithSHA512 */ + "\x06\x05\x2B\x81\x04\x00\x22", + .param_len = 7, + .c = + "\x30\x64\x02\x30\x4f\xd3\xe8\x98\xcb\x6b\x82\x4b\x41\x2d\x3b\x85" + "\xde\x07\x19\xc4\x64\x2b\xd9\x80\x00\x50\xa8\x79\x48\x07\x75\xb6" + "\x56\x66\xb9\x89\x0b\xab\x89\x18\x4c\xe9\x21\x38\x4e\xe0\x70\x9d" + "\x80\x76\x8a\x2b\x02\x30\x5f\x01\xc5\x0b\x6e\x72\x42\x2e\x79\xee" + "\x42\x15\xe0\x16\xf5\x38\x90\x49\x44\x7f\xca\x29\xdf\x0d\xce\x5b" + "\xeb\x7f\xef\x2a\x51\xef\x52\x6e\x14\xa6\x25\xe5\xfb\x7b\x66\xea" + "\x07\x3f\x4c\x17\xd0\xfc", + .c_size = 102, + .algo = OID_id_ecdsa_with_sha256, + .public_key_vec = true, + .siggen_sigver_test = true, + }, +}; + /* * EC-RDSA test vectors are generated by gost-engine. */