summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFranziskus Kiefer <franziskuskiefer@gmail.com>2017-04-04 09:44:08 +0200
committerFranziskus Kiefer <franziskuskiefer@gmail.com>2017-04-04 09:44:08 +0200
commit93aebb4fb584d8502fd7ca04ba0daf912e97df43 (patch)
treef633f404c395ecd92faf8b97780e813030c21797
parent282dd7157722ae4b6af8ca5427232b8d3da5be9d (diff)
downloadnss-hg-93aebb4fb584d8502fd7ca04ba0daf912e97df43.tar.gz
Bug 1352039 - improvements for elliptic curve addition in mixed Jacobian-affine coordinates, r=ttaubert
Differential Revision: https://nss-review.dev.mozaws.net/D333
-rw-r--r--cpputil/scoped_ptrs.h2
-rw-r--r--gtests/freebl_gtest/ecl_unittest.cc124
-rw-r--r--gtests/freebl_gtest/freebl_gtest.gyp2
-rw-r--r--gtests/freebl_gtest/mpi_unittest.cc5
-rw-r--r--lib/freebl/ecl/ecp_jm.c11
5 files changed, 139 insertions, 5 deletions
diff --git a/cpputil/scoped_ptrs.h b/cpputil/scoped_ptrs.h
index c5f81906f..0436cd20e 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 <class T>
@@ -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 000000000..fbad0246f
--- /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 <stdint.h>
+
+#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<uint8_t> hexStringToBytes(std::string s) {
+ std::vector<uint8_t> 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<uint8_t> bytes) {
+ std::stringstream s;
+ for (auto b : bytes) {
+ s << std::setfill('0') << std::setw(2) << std::uppercase << std::hex
+ << static_cast<int>(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<uint8_t> p_bytes = hexStringToBytes(p);
+ ASSERT_GT(p_bytes.size(), 0U);
+ SECItem public_value = {siBuffer, p_bytes.data(),
+ static_cast<unsigned int>(p_bytes.size())};
+
+ std::vector<uint8_t> secret_bytes = hexStringToBytes(secret);
+ ASSERT_GT(secret_bytes.size(), 0U);
+ SECItem secret_value = {siBuffer, secret_bytes.data(),
+ static_cast<unsigned int>(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<uint8_t>(
+ 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 9a0449553..99f10fbd2 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 059183fb6..4fed1a40e 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 <stdint.h>
#include <string.h>
-#include <string>
#ifdef __MACH__
#include <mach/clock.h>
diff --git a/lib/freebl/ecl/ecp_jm.c b/lib/freebl/ecl/ecp_jm.c
index a1106cea8..bd13fa050 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));