From 99b0a24aebc7e5db353f25a70a4baaf25bb5eb66 Mon Sep 17 00:00:00 2001 From: Franziskus Kiefer Date: Tue, 4 Apr 2017 09:44:08 +0200 Subject: [PATCH] Bug 1352039 - improvements for elliptic curve addition in mixed Jacobian-affine coordinates, r=ttaubert Differential Revision: https://nss-review.dev.mozaws.net/D333 --HG-- extra : rebase_source : 320eea393a34a19ec7a2576f949a39a7c8da1392 extra : histedit_source : 8e7f5d908a477e655e23bfb46b4799df01d366f2%2Cc9dc778bdf0c5240704c9e29a9dc34395a7401d1 --- cpputil/scoped_ptrs.h | 2 + gtests/freebl_gtest/ecl_unittest.cc | 124 +++++++++++++++++++++++++++ gtests/freebl_gtest/freebl_gtest.gyp | 2 + gtests/freebl_gtest/mpi_unittest.cc | 5 -- lib/freebl/ecl/ecp_jm.c | 11 +++ 5 files changed, 139 insertions(+), 5 deletions(-) create mode 100644 gtests/freebl_gtest/ecl_unittest.cc diff --git a/cpputil/scoped_ptrs.h b/cpputil/scoped_ptrs.h index c5f81906fb..0436cd20ed 100644 --- a/cpputil/scoped_ptrs.h +++ b/cpputil/scoped_ptrs.h @@ -34,6 +34,7 @@ struct ScopedDelete { SECKEY_DestroyPrivateKeyList(list); } void operator()(PK11URI* uri) { PK11URI_DestroyURI(uri); } + void operator()(PLArenaPool* arena) { PORT_FreeArena(arena, PR_FALSE); } }; template @@ -62,6 +63,7 @@ SCOPED(SECKEYPublicKey); SCOPED(SECKEYPrivateKey); SCOPED(SECKEYPrivateKeyList); SCOPED(PK11URI); +SCOPED(PLArenaPool); #undef SCOPED diff --git a/gtests/freebl_gtest/ecl_unittest.cc b/gtests/freebl_gtest/ecl_unittest.cc new file mode 100644 index 0000000000..fbad0246f9 --- /dev/null +++ b/gtests/freebl_gtest/ecl_unittest.cc @@ -0,0 +1,124 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at http://mozilla.org/MPL/2.0/. + +#include "gtest/gtest.h" + +#include + +#include "blapi.h" +#include "scoped_ptrs.h" +#include "secerr.h" + +namespace nss_test { + +class ECLTest : public ::testing::Test { + protected: + const ECCurveName GetCurveName(std::string name) { + if (name == "P256") return ECCurve_NIST_P256; + if (name == "P384") return ECCurve_NIST_P384; + if (name == "P521") return ECCurve_NIST_P521; + return ECCurve_pastLastCurve; + } + std::vector hexStringToBytes(std::string s) { + std::vector bytes; + for (size_t i = 0; i < s.length(); i += 2) { + bytes.push_back(std::stoul(s.substr(i, 2), nullptr, 16)); + } + return bytes; + } + std::string bytesToHexString(std::vector bytes) { + std::stringstream s; + for (auto b : bytes) { + s << std::setfill('0') << std::setw(2) << std::uppercase << std::hex + << static_cast(b); + } + return s.str(); + } + void ecName2params(const std::string curve, SECItem *params) { + SECOidData *oidData = nullptr; + + switch (GetCurveName(curve)) { + case ECCurve_NIST_P256: + oidData = SECOID_FindOIDByTag(SEC_OID_ANSIX962_EC_PRIME256V1); + break; + case ECCurve_NIST_P384: + oidData = SECOID_FindOIDByTag(SEC_OID_SECG_EC_SECP384R1); + break; + case ECCurve_NIST_P521: + oidData = SECOID_FindOIDByTag(SEC_OID_SECG_EC_SECP521R1); + break; + default: + FAIL(); + } + ASSERT_NE(oidData, nullptr); + + if (SECITEM_AllocItem(nullptr, params, (2 + oidData->oid.len)) == nullptr) { + FAIL() << "Couldn't allocate memory for OID."; + } + params->data[0] = SEC_ASN1_OBJECT_ID; + params->data[1] = oidData->oid.len; + memcpy(params->data + 2, oidData->oid.data, oidData->oid.len); + } + + void TestECDH_Derive(const std::string p, const std::string secret, + const std::string group_name, const std::string result, + const SECStatus expected_status) { + ECParams ecParams = {0}; + ScopedSECItem ecEncodedParams(SECITEM_AllocItem(nullptr, nullptr, 0U)); + ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE)); + + ASSERT_TRUE(arena && ecEncodedParams); + + ecName2params(group_name, ecEncodedParams.get()); + EC_FillParams(arena.get(), ecEncodedParams.get(), &ecParams); + + std::vector p_bytes = hexStringToBytes(p); + ASSERT_GT(p_bytes.size(), 0U); + SECItem public_value = {siBuffer, p_bytes.data(), + static_cast(p_bytes.size())}; + + std::vector secret_bytes = hexStringToBytes(secret); + ASSERT_GT(secret_bytes.size(), 0U); + SECItem secret_value = {siBuffer, secret_bytes.data(), + static_cast(secret_bytes.size())}; + + ScopedSECItem derived_secret(SECITEM_AllocItem(nullptr, nullptr, 0U)); + + SECStatus rv = ECDH_Derive(&public_value, &ecParams, &secret_value, false, + derived_secret.get()); + ASSERT_EQ(expected_status, rv); + if (expected_status != SECSuccess) { + // Abort when we expect an error. + return; + } + + std::string derived_result = bytesToHexString(std::vector( + derived_secret->data, derived_secret->data + derived_secret->len)); + std::cout << "derived secret: " << derived_result << std::endl; + EXPECT_EQ(derived_result, result); + } +}; + +TEST_F(ECLTest, TestECDH_DeriveP256) { + TestECDH_Derive( + "045ce5c643dffa402bc1837bbcbc223e51d06f20200470d341adfa9deed1bba10e850a16" + "368b673732a5c220a778990b22a0e74cdc3b22c7410b9dd552a5635497", + "971", "P256", "0", SECFailure); +} +TEST_F(ECLTest, TestECDH_DeriveP521) { + TestECDH_Derive( + "04" + "00c6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d3dbaa14b" + "5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66" + "011839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e662c97ee" + "72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650", + "01fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa5186" + "8783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e913863f7", + "P521", + "01BC33425E72A12779EACB2EDCC5B63D1281F7E86DBC7BF99A7ABD0CFE367DE4666D6EDB" + "B8525BFFE5222F0702C3096DEC0884CE572F5A15C423FDF44D01DD99C61D", + SECSuccess); +} + +} // nss_test diff --git a/gtests/freebl_gtest/freebl_gtest.gyp b/gtests/freebl_gtest/freebl_gtest.gyp index 9a0449553c..99f10fbd26 100644 --- a/gtests/freebl_gtest/freebl_gtest.gyp +++ b/gtests/freebl_gtest/freebl_gtest.gyp @@ -13,6 +13,7 @@ 'sources': [ 'mpi_unittest.cc', 'dh_unittest.cc', + 'ecl_unittest.cc', '<(DEPTH)/gtests/common/gtests.cc' ], 'dependencies': [ @@ -65,6 +66,7 @@ 'target_defaults': { 'include_dirs': [ '<(DEPTH)/lib/freebl/mpi', + '<(DEPTH)/lib/freebl/', ], # For test builds we have to set MPI defines. 'conditions': [ diff --git a/gtests/freebl_gtest/mpi_unittest.cc b/gtests/freebl_gtest/mpi_unittest.cc index 059183fb6d..4fed1a40e0 100644 --- a/gtests/freebl_gtest/mpi_unittest.cc +++ b/gtests/freebl_gtest/mpi_unittest.cc @@ -2,15 +2,10 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this file, // You can obtain one at http://mozilla.org/MPL/2.0/. -#include "secdert.h" -#include "secitem.h" -#include "secport.h" - #include "gtest/gtest.h" #include #include -#include #ifdef __MACH__ #include diff --git a/lib/freebl/ecl/ecp_jm.c b/lib/freebl/ecl/ecp_jm.c index a1106cea83..bd13fa0508 100644 --- a/lib/freebl/ecl/ecp_jm.c +++ b/lib/freebl/ecl/ecp_jm.c @@ -127,6 +127,17 @@ ec_GFp_pt_add_jm_aff(const mp_int *px, const mp_int *py, const mp_int *pz, MP_CHECKOK(group->meth->field_mul(A, qx, A, group->meth)); MP_CHECKOK(group->meth->field_mul(B, qy, B, group->meth)); + /* Check P == Q */ + if (mp_cmp(A, px) == 0) { + if (mp_cmp(B, py) == 0) { + /* If Px == Qx && Py == Qy, double P. */ + return ec_GFp_pt_dbl_jm(px, py, pz, paz4, rx, ry, rz, raz4, + scratch, group); + } + /* If Px == Qx && Py != Qy, return point at infinity. */ + return ec_GFp_pt_set_inf_jac(rx, ry, rz); + } + /* C = A - px, D = B - py */ MP_CHECKOK(group->meth->field_sub(A, px, C, group->meth)); MP_CHECKOK(group->meth->field_sub(B, py, D, group->meth));