tor-browser

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

pk11_rsapss_unittest.cc (12005B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
      5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include <memory>
      8 #include "nss.h"
      9 #include "pk11pub.h"
     10 #include "sechash.h"
     11 #include "json_reader.h"
     12 
     13 #include "databuffer.h"
     14 
     15 #include "gtest/gtest.h"
     16 #include "nss_scoped_ptrs.h"
     17 
     18 #include "pk11_signature_test.h"
     19 #include "pk11_rsapss_vectors.h"
     20 #include "testvectors_base/test-structs.h"
     21 
     22 namespace nss_test {
     23 
     24 CK_MECHANISM_TYPE RsaPssMapCombo(SECOidTag hashOid) {
     25  switch (hashOid) {
     26    case SEC_OID_SHA1:
     27      return CKM_SHA1_RSA_PKCS_PSS;
     28    case SEC_OID_SHA224:
     29      return CKM_SHA224_RSA_PKCS_PSS;
     30    case SEC_OID_SHA256:
     31      return CKM_SHA256_RSA_PKCS_PSS;
     32    case SEC_OID_SHA384:
     33      return CKM_SHA384_RSA_PKCS_PSS;
     34    case SEC_OID_SHA512:
     35      return CKM_SHA512_RSA_PKCS_PSS;
     36    default:
     37      break;
     38  }
     39  return CKM_INVALID_MECHANISM;
     40 }
     41 
     42 class Pkcs11RsaPssTestBase : public Pk11SignatureTest {
     43 public:
     44  Pkcs11RsaPssTestBase(SECOidTag hashOid, CK_RSA_PKCS_MGF_TYPE mgf, int sLen)
     45      : Pk11SignatureTest(CKM_RSA_PKCS_PSS, hashOid, RsaPssMapCombo(hashOid)) {
     46    pss_params_.hashAlg = PK11_AlgtagToMechanism(hashOid);
     47    pss_params_.mgf = mgf;
     48    pss_params_.sLen = sLen;
     49 
     50    params_.type = siBuffer;
     51    params_.data = reinterpret_cast<unsigned char*>(&pss_params_);
     52    params_.len = sizeof(pss_params_);
     53  }
     54 
     55  const SECItem* parameters() const { return &params_; }
     56 
     57  void Verify(const RsaPssTestVector& vec) {
     58    Pkcs11SignatureTestParams params = {
     59        DataBuffer(), DataBuffer(vec.public_key.data(), vec.public_key.size()),
     60        DataBuffer(vec.msg.data(), vec.msg.size()),
     61        DataBuffer(vec.sig.data(), vec.sig.size())};
     62 
     63    Pk11SignatureTest::Verify(params, vec.valid);
     64  }
     65 
     66 private:
     67  CK_RSA_PKCS_PSS_PARAMS pss_params_;
     68  SECItem params_;
     69 };
     70 
     71 class Pkcs11RsaPssTest : public Pkcs11RsaPssTestBase {
     72 public:
     73  Pkcs11RsaPssTest()
     74      : Pkcs11RsaPssTestBase(SEC_OID_SHA1, CKG_MGF1_SHA1, SHA1_LENGTH) {}
     75 };
     76 
     77 class Pkcs11RsaPssTestWycheproof : public ::testing::Test {
     78 public:
     79  struct TestVector {
     80    uint64_t id;
     81    std::vector<uint8_t> msg;
     82    std::vector<uint8_t> sig;
     83    bool valid;
     84  };
     85 
     86  Pkcs11RsaPssTestWycheproof() {}
     87 
     88  void Run(const std::string& file) {
     89    WycheproofHeader("rsa_pss_" + file, "RSASSA-PSS",
     90                     "rsassa_pss_verify_schema.json",
     91                     [this](JsonReader& r) { RunGroup(r); });
     92  }
     93 
     94  static void ReadTestAttr(TestVector& t, const std::string& n, JsonReader& r) {
     95    if (n == "msg") {
     96      t.msg = r.ReadHex();
     97    } else if (n == "sig") {
     98      t.sig = r.ReadHex();
     99    } else {
    100      FAIL() << "unknown key in test: " << n;
    101    }
    102  }
    103 
    104 private:
    105  class Pkcs11RsaPssTestWrap : public Pkcs11RsaPssTestBase {
    106   public:
    107    Pkcs11RsaPssTestWrap(SECOidTag hash, CK_RSA_PKCS_MGF_TYPE mgf, int s_len)
    108        : Pkcs11RsaPssTestBase(hash, mgf, s_len) {}
    109 
    110    void TestBody() {}
    111 
    112    void Verify(const Pkcs11SignatureTestParams& params, bool valid) {
    113      Pk11SignatureTest::Verify(params, valid);
    114    }
    115  };
    116 
    117  void RunTests(const std::vector<uint8_t>& public_key, SECOidTag hash,
    118                CK_RSA_PKCS_MGF_TYPE mgf, int s_len,
    119                const std::vector<TestVector>& tests) {
    120    ASSERT_NE(0u, public_key.size());
    121    ASSERT_NE(SEC_OID_UNKNOWN, hash);
    122    ASSERT_NE(CKM_INVALID_MECHANISM, mgf);
    123    ASSERT_NE(0u, tests.size());
    124 
    125    for (auto& v : tests) {
    126      std::cout << "Running tcid: " << v.id << std::endl;
    127 
    128      Pkcs11RsaPssTestWrap test(hash, mgf, s_len);
    129      Pkcs11SignatureTestParams params = {
    130          DataBuffer(), DataBuffer(public_key.data(), public_key.size()),
    131          DataBuffer(v.msg.data(), v.msg.size()),
    132          DataBuffer(v.sig.data(), v.sig.size())};
    133      test.Verify(params, v.valid);
    134    }
    135  }
    136 
    137  void RunGroup(JsonReader& r) {
    138    std::vector<uint8_t> public_key;
    139    SECOidTag hash = SEC_OID_UNKNOWN;
    140    CK_RSA_PKCS_MGF_TYPE mgf = CKM_INVALID_MECHANISM;
    141    int s_len = 0;
    142    std::vector<TestVector> tests;
    143    while (r.NextItem()) {
    144      std::string n = r.ReadLabel();
    145      if (n == "") {
    146        break;
    147      }
    148      if (n == "e" || n == "keyAsn" || n == "keyPem" || n == "n") {
    149        (void)r.ReadString();
    150      } else if (n == "keyDer") {
    151        public_key = r.ReadHex();
    152      } else if (n == "keysize") {
    153        (void)r.ReadInt();
    154      } else if (n == "mgf") {
    155        std::string s = r.ReadString();
    156        ASSERT_EQ(s, "MGF1");
    157      } else if (n == "mgfSha") {
    158        std::string s = r.ReadString();
    159        if (s == "SHA-1") {
    160          mgf = CKG_MGF1_SHA1;
    161        } else if (s == "SHA-224") {
    162          mgf = CKG_MGF1_SHA224;
    163        } else if (s == "SHA-256") {
    164          mgf = CKG_MGF1_SHA256;
    165        } else if (s == "SHA-384") {
    166          mgf = CKG_MGF1_SHA384;
    167        } else if (s == "SHA-512") {
    168          mgf = CKG_MGF1_SHA512;
    169        } else {
    170          FAIL() << "unsupported MGF hash";
    171        }
    172      } else if (n == "sLen") {
    173        s_len = static_cast<unsigned int>(r.ReadInt());
    174      } else if (n == "sha") {
    175        std::string s = r.ReadString();
    176        if (s == "SHA-1") {
    177          hash = SEC_OID_SHA1;
    178        } else if (s == "SHA-224") {
    179          hash = SEC_OID_SHA224;
    180        } else if (s == "SHA-256") {
    181          hash = SEC_OID_SHA256;
    182        } else if (s == "SHA-384") {
    183          hash = SEC_OID_SHA384;
    184        } else if (s == "SHA-512") {
    185          hash = SEC_OID_SHA512;
    186        } else {
    187          FAIL() << "unsupported hash";
    188        }
    189      } else if (n == "type") {
    190        ASSERT_EQ("RsassaPssVerify", r.ReadString());
    191      } else if (n == "tests") {
    192        WycheproofReadTests(r, &tests, ReadTestAttr);
    193      } else {
    194        FAIL() << "unknown test group attribute: " << n;
    195      }
    196    }
    197 
    198    RunTests(public_key, hash, mgf, s_len, tests);
    199  }
    200 };
    201 
    202 TEST_F(Pkcs11RsaPssTest, GenerateAndSignAndVerify) {
    203  // Sign data with a 1024-bit RSA key, using PSS/SHA-256.
    204  SECOidTag hashOid = SEC_OID_SHA256;
    205  CK_MECHANISM_TYPE hash_mech = CKM_SHA256;
    206  CK_RSA_PKCS_MGF_TYPE mgf = CKG_MGF1_SHA256;
    207  PK11RSAGenParams rsaGenParams = {1024, 0x10001};
    208 
    209  // Generate RSA key pair.
    210  ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
    211  SECKEYPublicKey* pub_keyRaw = nullptr;
    212  ScopedSECKEYPrivateKey privKey(
    213      PK11_GenerateKeyPair(slot.get(), CKM_RSA_PKCS_KEY_PAIR_GEN, &rsaGenParams,
    214                           &pub_keyRaw, false, false, nullptr));
    215  ASSERT_TRUE(!!privKey && pub_keyRaw);
    216  ScopedSECKEYPublicKey pub_key(pub_keyRaw);
    217 
    218  // Generate random data to sign.
    219  uint8_t dataBuf[50];
    220  SECItem data = {siBuffer, dataBuf, sizeof(dataBuf)};
    221  unsigned int hLen = HASH_ResultLenByOidTag(hashOid);
    222  SECStatus rv = PK11_GenerateRandomOnSlot(slot.get(), data.data, data.len);
    223  EXPECT_EQ(rv, SECSuccess);
    224 
    225  // Allocate memory for the signature.
    226  std::vector<uint8_t> sigBuf(PK11_SignatureLen(privKey.get()));
    227  SECItem sig = {siBuffer, &sigBuf[0],
    228                 static_cast<unsigned int>(sigBuf.size())};
    229 
    230  // Set up PSS parameters.
    231  CK_RSA_PKCS_PSS_PARAMS pss_params = {hash_mech, mgf, hLen};
    232  SECItem params = {siBuffer, reinterpret_cast<unsigned char*>(&pss_params),
    233                    sizeof(pss_params)};
    234 
    235  // Sign.
    236  rv = PK11_SignWithMechanism(privKey.get(), mechanism(), &params, &sig, &data);
    237  EXPECT_EQ(rv, SECSuccess);
    238 
    239  // Verify.
    240  rv = PK11_VerifyWithMechanism(pub_key.get(), mechanism(), &params, &sig,
    241                                &data, nullptr);
    242  EXPECT_EQ(rv, SECSuccess);
    243 
    244  // Verification with modified data must fail.
    245  data.data[0] ^= 0xff;
    246  rv = PK11_VerifyWithMechanism(pub_key.get(), mechanism(), &params, &sig,
    247                                &data, nullptr);
    248  EXPECT_EQ(rv, SECFailure);
    249 
    250  // Verification with original data but the wrong signature must fail.
    251  data.data[0] ^= 0xff;  // Revert previous changes.
    252  sig.data[0] ^= 0xff;
    253  rv = PK11_VerifyWithMechanism(pub_key.get(), mechanism(), &params, &sig,
    254                                &data, nullptr);
    255  EXPECT_EQ(rv, SECFailure);
    256 }
    257 
    258 TEST_F(Pkcs11RsaPssTest, NoLeakWithInvalidExponent) {
    259  // Attempt to generate an RSA key with a public exponent of 1. This should
    260  // fail, but it shouldn't leak memory.
    261  PK11RSAGenParams rsaGenParams = {1024, 0x01};
    262 
    263  // Generate RSA key pair.
    264  ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
    265  SECKEYPublicKey* pub_key = nullptr;
    266  SECKEYPrivateKey* privKey =
    267      PK11_GenerateKeyPair(slot.get(), CKM_RSA_PKCS_KEY_PAIR_GEN, &rsaGenParams,
    268                           &pub_key, false, false, nullptr);
    269  EXPECT_FALSE(privKey);
    270  EXPECT_FALSE(pub_key);
    271 }
    272 class Pkcs11RsaPssVectorTest
    273    : public Pkcs11RsaPssTest,
    274      public ::testing::WithParamInterface<Pkcs11SignatureTestParams> {};
    275 
    276 TEST_P(Pkcs11RsaPssVectorTest, Verify) {
    277  Pk11SignatureTest::Verify(GetParam());
    278 }
    279 
    280 TEST_P(Pkcs11RsaPssVectorTest, SignAndVerify) { SignAndVerify(GetParam()); }
    281 
    282 #define VECTOR(pkcs8, spki, data, sig)                                \
    283  {                                                                   \
    284    DataBuffer(pkcs8, sizeof(pkcs8)), DataBuffer(spki, sizeof(spki)), \
    285        DataBuffer(data, sizeof(data)), DataBuffer(sig, sizeof(sig))  \
    286  }
    287 #define VECTOR_N(n)                                                         \
    288  VECTOR(kTestVector##n##Pkcs8, kTestVector##n##Spki, kTestVector##n##Data, \
    289         kTestVector##n##Sig)
    290 
    291 static const Pkcs11SignatureTestParams kRsaPssVectors[] = {
    292    // RSA-PSS test vectors, pss-vect.txt, Example 1.1: A 1024-bit RSA Key Pair
    293    // <ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1-vec.zip>
    294    VECTOR_N(1),
    295    // RSA-PSS test vectors, pss-vect.txt, Example 2.1: A 1025-bit RSA Key Pair
    296    // <ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1-vec.zip>
    297    VECTOR_N(2),
    298    // RSA-PSS test vectors, pss-vect.txt, Example 3.1: A 1026-bit RSA Key Pair
    299    // <ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1-vec.zip>
    300    VECTOR_N(3),
    301    // RSA-PSS test vectors, pss-vect.txt, Example 4.1: A 1027-bit RSA Key Pair
    302    // <ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1-vec.zip>
    303    VECTOR_N(4),
    304    // RSA-PSS test vectors, pss-vect.txt, Example 5.1: A 1028-bit RSA Key Pair
    305    // <ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1-vec.zip>
    306    VECTOR_N(5),
    307    // RSA-PSS test vectors, pss-vect.txt, Example 6.1: A 1029-bit RSA Key Pair
    308    // <ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1-vec.zip>
    309    VECTOR_N(6),
    310    // RSA-PSS test vectors, pss-vect.txt, Example 7.1: A 1030-bit RSA Key Pair
    311    // <ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1-vec.zip>
    312    VECTOR_N(7),
    313    // RSA-PSS test vectors, pss-vect.txt, Example 8.1: A 1031-bit RSA Key Pair
    314    // <ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1-vec.zip>
    315    VECTOR_N(8),
    316    // RSA-PSS test vectors, pss-vect.txt, Example 9.1: A 1536-bit RSA Key Pair
    317    // <ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1-vec.zip>
    318    VECTOR_N(9),
    319    // RSA-PSS test vectors, pss-vect.txt, Example 10.1: A 2048-bit RSA Key Pair
    320    // <ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1-vec.zip>
    321    VECTOR_N(10)};
    322 
    323 INSTANTIATE_TEST_SUITE_P(RsaPssSignVerify, Pkcs11RsaPssVectorTest,
    324                         ::testing::ValuesIn(kRsaPssVectors));
    325 
    326 TEST_F(Pkcs11RsaPssTestWycheproof, RsaPss2048Sha1) { Run("2048_sha1_mgf1_20"); }
    327 TEST_F(Pkcs11RsaPssTestWycheproof, RsaPss2048Sha256_0) {
    328  Run("2048_sha256_mgf1_0");
    329 }
    330 TEST_F(Pkcs11RsaPssTestWycheproof, RsaPss2048Sha256_32) {
    331  Run("2048_sha256_mgf1_32");
    332 }
    333 TEST_F(Pkcs11RsaPssTestWycheproof, RsaPss3072Sha256) {
    334  Run("3072_sha256_mgf1_32");
    335 }
    336 TEST_F(Pkcs11RsaPssTestWycheproof, RsaPss4096Sha256) {
    337  Run("4096_sha256_mgf1_32");
    338 }
    339 TEST_F(Pkcs11RsaPssTestWycheproof, RsaPss4096Sha512) {
    340  Run("4096_sha512_mgf1_32");
    341 }
    342 TEST_F(Pkcs11RsaPssTestWycheproof, RsaPssMisc) { Run("misc"); }
    343 
    344 }  // namespace nss_test