tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

pk11_ecdsa_unittest.cc (16046B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
      3 * You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 #include <memory>
      6 #include "nss.h"
      7 #include "pk11pub.h"
      8 #include "sechash.h"
      9 #include "cryptohi.h"
     10 
     11 #include "cpputil.h"
     12 #include "gtest/gtest.h"
     13 #include "json_reader.h"
     14 #include "nss_scoped_ptrs.h"
     15 #include "testvectors/curve25519-vectors.h"
     16 
     17 #include "pk11_ecdsa_vectors.h"
     18 #include "pk11_signature_test.h"
     19 #include "pk11_keygen.h"
     20 
     21 namespace nss_test {
     22 
     23 CK_MECHANISM_TYPE
     24 EcHashToComboMech(SECOidTag hash) {
     25  switch (hash) {
     26    case SEC_OID_SHA1:
     27      return CKM_ECDSA_SHA1;
     28    case SEC_OID_SHA224:
     29      return CKM_ECDSA_SHA224;
     30    case SEC_OID_SHA256:
     31      return CKM_ECDSA_SHA256;
     32    case SEC_OID_SHA384:
     33      return CKM_ECDSA_SHA384;
     34    case SEC_OID_SHA512:
     35      return CKM_ECDSA_SHA512;
     36    default:
     37      break;
     38  }
     39  return CKM_INVALID_MECHANISM;
     40 }
     41 
     42 class Pkcs11EcdsaTestBase : public Pk11SignatureTest {
     43 protected:
     44  Pkcs11EcdsaTestBase(SECOidTag hash_oid)
     45      : Pk11SignatureTest(CKM_ECDSA, hash_oid, EcHashToComboMech(hash_oid)) {}
     46 };
     47 
     48 struct Pkcs11EcdsaTestParams {
     49  SECOidTag hash_oid_;
     50  Pkcs11SignatureTestParams sig_params_;
     51 };
     52 
     53 class Pkcs11EcdsaTest
     54    : public Pkcs11EcdsaTestBase,
     55      public ::testing::WithParamInterface<Pkcs11EcdsaTestParams> {
     56 public:
     57  Pkcs11EcdsaTest() : Pkcs11EcdsaTestBase(GetParam().hash_oid_) {}
     58 };
     59 
     60 TEST_P(Pkcs11EcdsaTest, Verify) { Verify(GetParam().sig_params_); }
     61 
     62 TEST_P(Pkcs11EcdsaTest, SignAndVerify) {
     63  SignAndVerify(GetParam().sig_params_);
     64 }
     65 
     66 TEST_P(Pkcs11EcdsaTest, ImportExport) {
     67  ImportExport(GetParam().sig_params_.pkcs8_);
     68 }
     69 
     70 static const Pkcs11EcdsaTestParams kEcdsaVectors[] = {
     71    {SEC_OID_SHA256,
     72     {DataBuffer(kP256Pkcs8, sizeof(kP256Pkcs8)),
     73      DataBuffer(kP256Spki, sizeof(kP256Spki)),
     74      DataBuffer(kP256Data, sizeof(kP256Data)),
     75      DataBuffer(kP256Signature, sizeof(kP256Signature))}},
     76    {SEC_OID_SHA256,
     77     {DataBuffer(kP256Pkcs8KeyLen30, sizeof(kP256Pkcs8KeyLen30)),
     78      DataBuffer(kP256SpkiKeyLen, sizeof(kP256SpkiKeyLen)),
     79      DataBuffer(kP256DataKeyLen, sizeof(kP256DataKeyLen)),
     80      DataBuffer(kP256SignatureKeyLen, sizeof(kP256SignatureKeyLen))}},
     81    {SEC_OID_SHA256,
     82     {DataBuffer(kP256Pkcs8KeyLen33, sizeof(kP256Pkcs8KeyLen33)),
     83      DataBuffer(kP256SpkiKeyLen, sizeof(kP256SpkiKeyLen)),
     84      DataBuffer(kP256DataKeyLen, sizeof(kP256DataKeyLen)),
     85      DataBuffer(kP256SignatureKeyLen, sizeof(kP256SignatureKeyLen))}},
     86    {SEC_OID_SHA384,
     87     {DataBuffer(kP384Pkcs8, sizeof(kP384Pkcs8)),
     88      DataBuffer(kP384Spki, sizeof(kP384Spki)),
     89      DataBuffer(kP384Data, sizeof(kP384Data)),
     90      DataBuffer(kP384Signature, sizeof(kP384Signature))}},
     91    {SEC_OID_SHA256,
     92     {DataBuffer(kP384Pkcs8KeyLen46, sizeof(kP384Pkcs8KeyLen46)),
     93      DataBuffer(kP384SpkiKeyLen, sizeof(kP384SpkiKeyLen)),
     94      DataBuffer(kP384DataKeyLen, sizeof(kP384DataKeyLen)),
     95      DataBuffer(kP384SignatureKeyLen, sizeof(kP384SignatureKeyLen))}},
     96    {SEC_OID_SHA256,
     97     {DataBuffer(kP384Pkcs8KeyLen49, sizeof(kP384Pkcs8KeyLen49)),
     98      DataBuffer(kP384SpkiKeyLen, sizeof(kP384SpkiKeyLen)),
     99      DataBuffer(kP384DataKeyLen, sizeof(kP384DataKeyLen)),
    100      DataBuffer(kP384SignatureKeyLen, sizeof(kP384SignatureKeyLen))}},
    101    {SEC_OID_SHA512,
    102     {DataBuffer(kP521Pkcs8, sizeof(kP521Pkcs8)),
    103      DataBuffer(kP521Spki, sizeof(kP521Spki)),
    104      DataBuffer(kP521Data, sizeof(kP521Data)),
    105      DataBuffer(kP521Signature, sizeof(kP521Signature))}},
    106    {SEC_OID_SHA256,
    107     {DataBuffer(kP521Pkcs8KeyLen64, sizeof(kP521Pkcs8KeyLen64)),
    108      DataBuffer(kP521SpkiKeyLen, sizeof(kP521SpkiKeyLen)),
    109      DataBuffer(kP521DataKeyLen, sizeof(kP521DataKeyLen)),
    110      DataBuffer(kP521SignatureKeyLen, sizeof(kP521SignatureKeyLen))}},
    111    {SEC_OID_SHA256,
    112     {DataBuffer(kP521Pkcs8KeyLen67, sizeof(kP521Pkcs8KeyLen67)),
    113      DataBuffer(kP521SpkiKeyLen, sizeof(kP521SpkiKeyLen)),
    114      DataBuffer(kP521DataKeyLen, sizeof(kP521DataKeyLen)),
    115      DataBuffer(kP521SignatureKeyLen, sizeof(kP521SignatureKeyLen))}}};
    116 
    117 INSTANTIATE_TEST_SUITE_P(EcdsaSignVerify, Pkcs11EcdsaTest,
    118                         ::testing::ValuesIn(kEcdsaVectors));
    119 
    120 class Pkcs11EcdsaSha256Test : public Pkcs11EcdsaTestBase {
    121 public:
    122  Pkcs11EcdsaSha256Test() : Pkcs11EcdsaTestBase(SEC_OID_SHA256) {}
    123 };
    124 
    125 // Importing a private key in PKCS#8 format must fail when the outer AlgID
    126 // struct contains neither id-ecPublicKey nor a namedCurve parameter.
    127 TEST_F(Pkcs11EcdsaSha256Test, ImportNoCurveOIDOrAlgorithmParams) {
    128  DataBuffer k(kP256Pkcs8NoCurveOIDOrAlgorithmParams,
    129               sizeof(kP256Pkcs8NoCurveOIDOrAlgorithmParams));
    130  EXPECT_FALSE(ImportPrivateKey(k));
    131 };
    132 
    133 // Importing a private key in PKCS#8 format must succeed when only the outer
    134 // AlgID struct contains the namedCurve parameters.
    135 TEST_F(Pkcs11EcdsaSha256Test, ImportOnlyAlgorithmParams) {
    136  DataBuffer k(kP256Pkcs8OnlyAlgorithmParams,
    137               sizeof(kP256Pkcs8OnlyAlgorithmParams));
    138  DataBuffer data(kP256Data, sizeof(kP256Data));
    139  DataBuffer sig;
    140  DataBuffer sig2;
    141  EXPECT_TRUE(ImportPrivateKeyAndSignHashedData(k, data, &sig, &sig2));
    142 };
    143 
    144 // Importing a private key in PKCS#8 format must succeed when the outer AlgID
    145 // struct and the inner ECPrivateKey contain the same namedCurve parameters.
    146 // The inner curveOID is always ignored, so only the outer one will be used.
    147 TEST_F(Pkcs11EcdsaSha256Test, ImportMatchingCurveOIDAndAlgorithmParams) {
    148  DataBuffer k(kP256Pkcs8MatchingCurveOIDAndAlgorithmParams,
    149               sizeof(kP256Pkcs8MatchingCurveOIDAndAlgorithmParams));
    150  DataBuffer data(kP256Data, sizeof(kP256Data));
    151  DataBuffer sig;
    152  DataBuffer sig2;
    153  EXPECT_TRUE(ImportPrivateKeyAndSignHashedData(k, data, &sig, &sig2));
    154 };
    155 
    156 // Importing a private key in PKCS#8 format must succeed when the outer AlgID
    157 // struct and the inner ECPrivateKey contain dissimilar namedCurve parameters.
    158 // The inner curveOID is always ignored, so only the outer one will be used.
    159 TEST_F(Pkcs11EcdsaSha256Test, ImportDissimilarCurveOIDAndAlgorithmParams) {
    160  DataBuffer k(kP256Pkcs8DissimilarCurveOIDAndAlgorithmParams,
    161               sizeof(kP256Pkcs8DissimilarCurveOIDAndAlgorithmParams));
    162  DataBuffer data(kP256Data, sizeof(kP256Data));
    163  DataBuffer sig;
    164  DataBuffer sig2;
    165  EXPECT_TRUE(ImportPrivateKeyAndSignHashedData(k, data, &sig, &sig2));
    166 };
    167 
    168 // Importing a private key in PKCS#8 format must fail when the outer ASN.1
    169 // AlgorithmID struct contains only id-ecPublicKey but no namedCurve parameter.
    170 TEST_F(Pkcs11EcdsaSha256Test, ImportNoAlgorithmParams) {
    171  DataBuffer k(kP256Pkcs8NoAlgorithmParams,
    172               sizeof(kP256Pkcs8NoAlgorithmParams));
    173  EXPECT_FALSE(ImportPrivateKey(k));
    174 };
    175 
    176 // Importing a private key in PKCS#8 format must fail when id-ecPublicKey is
    177 // given (so we know it's an EC key) but the namedCurve parameter is unknown.
    178 TEST_F(Pkcs11EcdsaSha256Test, ImportInvalidAlgorithmParams) {
    179  DataBuffer k(kP256Pkcs8InvalidAlgorithmParams,
    180               sizeof(kP256Pkcs8InvalidAlgorithmParams));
    181  EXPECT_FALSE(ImportPrivateKey(k));
    182 };
    183 
    184 // Importing a private key in PKCS#8 format with a point not on the curve will
    185 // succeed. Using the contained public key however will fail when trying to
    186 // import it before using it for any operation.
    187 TEST_F(Pkcs11EcdsaSha256Test, ImportPointNotOnCurve) {
    188  DataBuffer k(kP256Pkcs8PointNotOnCurve, sizeof(kP256Pkcs8PointNotOnCurve));
    189  ScopedSECKEYPrivateKey privKey(ImportPrivateKey(k));
    190  ASSERT_TRUE(privKey);
    191 
    192  ScopedSECKEYPublicKey pubKey(SECKEY_ConvertToPublicKey(privKey.get()));
    193  ASSERT_TRUE(pubKey);
    194 
    195  ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
    196  ASSERT_TRUE(slot);
    197 
    198  auto handle = PK11_ImportPublicKey(slot.get(), pubKey.get(), false);
    199  EXPECT_EQ(handle, static_cast<decltype(handle)>(CK_INVALID_HANDLE));
    200 };
    201 
    202 // Importing a private key in PKCS#8 without a public key will succeed
    203 // if NSS supports public key derivation for this curve (P-256, P-384, P-521).
    204 TEST_F(Pkcs11EcdsaSha256Test, ImportNoPublicKey) {
    205  DataBuffer k(kP256Pkcs8NoPublicKey, sizeof(kP256Pkcs8NoPublicKey));
    206  ScopedSECKEYPrivateKey privKey(ImportPrivateKey(k));
    207  ASSERT_TRUE(privKey);
    208 
    209  ScopedSECKEYPublicKey pubKey(SECKEY_ConvertToPublicKey(privKey.get()));
    210  ASSERT_TRUE(pubKey);
    211 
    212  ASSERT_NE(pubKey->u.ec.publicValue.len, 0ul);
    213 };
    214 
    215 // Importing a public key in SPKI format must fail when id-ecPublicKey is
    216 // given (so we know it's an EC key) but the namedCurve parameter is missing.
    217 TEST_F(Pkcs11EcdsaSha256Test, ImportSpkiNoAlgorithmParams) {
    218  DataBuffer k(kP256SpkiNoAlgorithmParams, sizeof(kP256SpkiNoAlgorithmParams));
    219  EXPECT_FALSE(ImportPublicKey(k));
    220 }
    221 
    222 // Importing a public key in SPKI format with a point not on the curve will
    223 // succeed. Using the public key however will fail when trying to import
    224 // it before using it for any operation.
    225 TEST_F(Pkcs11EcdsaSha256Test, ImportSpkiPointNotOnCurve) {
    226  DataBuffer k(kP256SpkiPointNotOnCurve, sizeof(kP256SpkiPointNotOnCurve));
    227  ScopedSECKEYPublicKey pubKey(ImportPublicKey(k));
    228  ASSERT_TRUE(pubKey);
    229 
    230  ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
    231  ASSERT_TRUE(slot);
    232 
    233  auto handle = PK11_ImportPublicKey(slot.get(), pubKey.get(), false);
    234  EXPECT_EQ(handle, static_cast<decltype(handle)>(CK_INVALID_HANDLE));
    235 }
    236 
    237 class Pkcs11EcdsaWycheproofTest : public ::testing::Test {
    238 protected:
    239  void Run(const std::string& name) {
    240    WycheproofHeader(name, "ECDSA", "ecdsa_verify_schema.json",
    241                     [this](JsonReader& r) { RunGroup(r); });
    242  }
    243 
    244 private:
    245  void RunGroup(JsonReader& r) {
    246    std::vector<EcdsaTestVector> tests;
    247    std::vector<uint8_t> public_key;
    248    SECOidTag hash_oid = SEC_OID_UNKNOWN;
    249 
    250    while (r.NextItem()) {
    251      std::string n = r.ReadLabel();
    252      if (n == "") {
    253        break;
    254      }
    255 
    256      if (n == "key" || n == "keyPem") {
    257        r.SkipValue();
    258      } else if (n == "keyDer") {
    259        public_key = r.ReadHex();
    260      } else if (n == "sha") {
    261        hash_oid = r.ReadHash();
    262      } else if (n == "type") {
    263        ASSERT_EQ("EcdsaVerify", r.ReadString());
    264      } else if (n == "tests") {
    265        WycheproofReadTests(r, &tests, ReadTestAttr);
    266      } else {
    267        FAIL() << "unknown label in group: " << n;
    268      }
    269    }
    270 
    271    for (auto& t : tests) {
    272      std::cout << "Running test " << t.id << std::endl;
    273      t.public_key = public_key;
    274      t.hash_oid = hash_oid;
    275      Derive(t);
    276    }
    277  }
    278 
    279  static void ReadTestAttr(EcdsaTestVector& t, const std::string& n,
    280                           JsonReader& r) {
    281    if (n == "msg") {
    282      t.msg = r.ReadHex();
    283    } else if (n == "sig") {
    284      t.sig = r.ReadHex();
    285    } else {
    286      FAIL() << "unknown test key: " << n;
    287    }
    288  }
    289 
    290  void Derive(const EcdsaTestVector& vec) {
    291    SECItem spki_item = {siBuffer, toUcharPtr(vec.public_key.data()),
    292                         static_cast<unsigned int>(vec.public_key.size())};
    293    SECItem sig_item = {siBuffer, toUcharPtr(vec.sig.data()),
    294                        static_cast<unsigned int>(vec.sig.size())};
    295 
    296    DataBuffer hash;
    297    hash.Allocate(static_cast<size_t>(HASH_ResultLenByOidTag(vec.hash_oid)));
    298    SECStatus rv = PK11_HashBuf(vec.hash_oid, toUcharPtr(hash.data()),
    299                                toUcharPtr(vec.msg.data()), vec.msg.size());
    300    ASSERT_EQ(rv, SECSuccess);
    301    SECItem hash_item = {siBuffer, toUcharPtr(hash.data()),
    302                         static_cast<unsigned int>(hash.len())};
    303 
    304    ScopedCERTSubjectPublicKeyInfo cert_spki(
    305        SECKEY_DecodeDERSubjectPublicKeyInfo(&spki_item));
    306    ASSERT_TRUE(cert_spki);
    307    ScopedSECKEYPublicKey pub_key(SECKEY_ExtractPublicKey(cert_spki.get()));
    308    ASSERT_TRUE(pub_key);
    309 
    310    rv = VFY_VerifyDigestDirect(&hash_item, pub_key.get(), &sig_item,
    311                                SEC_OID_ANSIX962_EC_PUBLIC_KEY, vec.hash_oid,
    312                                nullptr);
    313    EXPECT_EQ(rv, vec.valid ? SECSuccess : SECFailure);
    314  };
    315 };
    316 
    317 TEST_F(Pkcs11EcdsaWycheproofTest, P256) { Run("ecdsa_secp256r1_sha256"); }
    318 TEST_F(Pkcs11EcdsaWycheproofTest, P256Sha512) { Run("ecdsa_secp256r1_sha512"); }
    319 TEST_F(Pkcs11EcdsaWycheproofTest, P384) { Run("ecdsa_secp384r1_sha384"); }
    320 TEST_F(Pkcs11EcdsaWycheproofTest, P384Sha512) { Run("ecdsa_secp384r1_sha512"); }
    321 TEST_F(Pkcs11EcdsaWycheproofTest, P521) { Run("ecdsa_secp521r1_sha512"); }
    322 
    323 class Pkcs11EcdsaRoundtripTest
    324    : public Pkcs11EcdsaTestBase,
    325      public ::testing::WithParamInterface<SECOidTag> {
    326 public:
    327  Pkcs11EcdsaRoundtripTest() : Pkcs11EcdsaTestBase(SEC_OID_SHA256) {}
    328 
    329 protected:
    330  void GenerateExportImportSignVerify(SECOidTag tag) {
    331    Pkcs11KeyPairGenerator generator(CKM_EC_KEY_PAIR_GEN, tag);
    332    ScopedSECKEYPrivateKey priv;
    333    ScopedSECKEYPublicKey pub;
    334    generator.GenerateKey(&priv, &pub, false);
    335 
    336    DataBuffer exported;
    337    ExportPrivateKey(&priv, exported);
    338 
    339    if (tag != SEC_OID_CURVE25519) {
    340      DataBuffer sig;
    341      DataBuffer sig2;
    342      DataBuffer data(kP256Data, sizeof(kP256Data));
    343      ASSERT_TRUE(
    344          ImportPrivateKeyAndSignHashedData(exported, data, &sig, &sig2));
    345 
    346      Verify(pub, data, sig);
    347    }
    348  }
    349 };
    350 
    351 TEST_P(Pkcs11EcdsaRoundtripTest, GenerateExportImportSignVerify) {
    352  GenerateExportImportSignVerify(GetParam());
    353 }
    354 INSTANTIATE_TEST_SUITE_P(Pkcs11EcdsaRoundtripTest, Pkcs11EcdsaRoundtripTest,
    355                         ::testing::Values(SEC_OID_SECG_EC_SECP256R1,
    356                                           SEC_OID_SECG_EC_SECP384R1,
    357                                           SEC_OID_SECG_EC_SECP521R1,
    358                                           SEC_OID_CURVE25519));
    359 
    360 class Pkcs11EcdsaUnpaddedSignatureTest
    361    : public Pkcs11EcdsaTestBase,
    362      public ::testing::WithParamInterface<Pkcs11EcdsaTestParams> {
    363 public:
    364  Pkcs11EcdsaUnpaddedSignatureTest()
    365      : Pkcs11EcdsaTestBase(GetParam().hash_oid_) {}
    366 };
    367 
    368 static const Pkcs11EcdsaTestParams kEcdsaUnpaddedSignaturesVectors[] = {
    369    {SEC_OID_SHA512,
    370     {DataBuffer(NULL, 0),
    371      DataBuffer(kP256SpkiUnpaddedSig, sizeof(kP256SpkiUnpaddedSig)),
    372      DataBuffer(kP256DataUnpaddedSigLong, sizeof(kP256DataUnpaddedSigLong)),
    373      DataBuffer(kP256SignatureUnpaddedSigLong,
    374                 sizeof(kP256SignatureUnpaddedSigLong))}},
    375    {SEC_OID_SHA512,
    376     {DataBuffer(NULL, 0),
    377      DataBuffer(kP256SpkiUnpaddedSig, sizeof(kP256SpkiUnpaddedSig)),
    378      DataBuffer(kP256DataUnpaddedSigShort, sizeof(kP256DataUnpaddedSigShort)),
    379      DataBuffer(kP256SignatureUnpaddedSigShort,
    380                 sizeof(kP256SignatureUnpaddedSigShort))}},
    381    {SEC_OID_SHA512,
    382     {DataBuffer(NULL, 0),
    383      DataBuffer(kP384SpkiUnpaddedSig, sizeof(kP384SpkiUnpaddedSig)),
    384      DataBuffer(kP384DataUnpaddedSigLong, sizeof(kP384DataUnpaddedSigLong)),
    385      DataBuffer(kP384SignatureUnpaddedSigLong,
    386                 sizeof(kP384SignatureUnpaddedSigLong))}},
    387    {SEC_OID_SHA512,
    388     {DataBuffer(NULL, 0),
    389      DataBuffer(kP384SpkiUnpaddedSig, sizeof(kP384SpkiUnpaddedSig)),
    390      DataBuffer(kP384DataUnpaddedSigShort, sizeof(kP384DataUnpaddedSigShort)),
    391      DataBuffer(kP384SignatureUnpaddedSigShort,
    392                 sizeof(kP384SignatureUnpaddedSigShort))}},
    393    {SEC_OID_SHA512,
    394     {DataBuffer(NULL, 0),
    395      DataBuffer(kP521SpkiUnpaddedSig, sizeof(kP521SpkiUnpaddedSig)),
    396      DataBuffer(kP521DataUnpaddedSigLong, sizeof(kP521DataUnpaddedSigLong)),
    397      DataBuffer(kP521SignatureUnpaddedSigLong,
    398                 sizeof(kP521SignatureUnpaddedSigLong))}},
    399    {SEC_OID_SHA512,
    400     {DataBuffer(NULL, 0),
    401      DataBuffer(kP521SpkiUnpaddedSig, sizeof(kP521SpkiUnpaddedSig)),
    402      DataBuffer(kP521DataUnpaddedSigShort, sizeof(kP521DataUnpaddedSigShort)),
    403      DataBuffer(kP521SignatureUnpaddedSigShort,
    404                 sizeof(kP521SignatureUnpaddedSigShort))}}};
    405 
    406 TEST_P(Pkcs11EcdsaUnpaddedSignatureTest, Verify) {
    407  Verify(GetParam().sig_params_);
    408 }
    409 INSTANTIATE_TEST_SUITE_P(EcdsaVerifyUnpaddedSignatures,
    410                         Pkcs11EcdsaUnpaddedSignatureTest,
    411                         ::testing::ValuesIn(kEcdsaUnpaddedSignaturesVectors));
    412 }  // namespace nss_test