pk11_rsaencrypt_unittest.cc (7475B)
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 <algorithm> 8 #include <cstdint> 9 10 #include "cpputil.h" 11 #include "cryptohi.h" 12 #include "json_reader.h" 13 #include "gtest/gtest.h" 14 #include "limits.h" 15 #include "nss.h" 16 #include "nss_scoped_ptrs.h" 17 #include "pk11pub.h" 18 #include "databuffer.h" 19 20 #include "testvectors/rsa_signature-vectors.h" 21 #include "testvectors/rsaencrypt_bb2048-vectors.h" 22 #include "testvectors/rsaencrypt_bb3072-vectors.h" 23 24 namespace nss_test { 25 26 class RsaDecryptWycheproofTest : public ::testing::Test { 27 protected: 28 void Run(const std::string& name) { 29 WycheproofHeader(name, "RSAES-PKCS1-v1_5", 30 "rsaes_pkcs1_decrypt_schema.json", 31 [this](JsonReader& r) { RunGroup(r); }); 32 } 33 34 void TestDecrypt(const RsaDecryptTestVector& vec) { 35 SECItem pkcs8_item = {siBuffer, toUcharPtr(vec.priv_key.data()), 36 static_cast<unsigned int>(vec.priv_key.size())}; 37 38 ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot()); 39 EXPECT_NE(nullptr, slot); 40 41 SECKEYPrivateKey* key = nullptr; 42 SECStatus rv = PK11_ImportDERPrivateKeyInfoAndReturnKey( 43 slot.get(), &pkcs8_item, nullptr, nullptr, false, false, KU_ALL, &key, 44 nullptr); 45 ASSERT_EQ(SECSuccess, rv); 46 ASSERT_NE(nullptr, key); 47 ScopedSECKEYPrivateKey priv_key(key); 48 49 // Decrypt 50 std::vector<uint8_t> decrypted(PR_MAX(1, vec.ct.size())); 51 unsigned int decrypted_len = 0; 52 rv = PK11_PrivDecryptPKCS1(priv_key.get(), decrypted.data(), &decrypted_len, 53 decrypted.size(), vec.ct.data(), vec.ct.size()); 54 55 decrypted.resize(decrypted_len); 56 if (vec.valid) { 57 ASSERT_EQ(SECSuccess, rv); 58 EXPECT_EQ(vec.msg, decrypted); 59 } else if (vec.invalid_padding) { 60 // If the padding is bad, decryption should succeed and produce 61 // (pseudo)random output. 62 ASSERT_EQ(SECSuccess, rv); 63 ASSERT_NE(vec.msg, decrypted); 64 } else { 65 ASSERT_EQ(SECFailure, rv) 66 << "Returned:" << DataBuffer(decrypted.data(), decrypted.size()); 67 } 68 }; 69 70 private: 71 void RunGroup(JsonReader& r) { 72 std::vector<RsaDecryptTestVector> tests; 73 std::vector<uint8_t> private_key; 74 while (r.NextItem()) { 75 std::string n = r.ReadLabel(); 76 if (n == "") { 77 break; 78 } 79 80 if (n == "d" || n == "e" || n == "keysize" || n == "n" || 81 n == "privateKeyJwk" || n == "privateKeyPem") { 82 r.SkipValue(); 83 } else if (n == "privateKeyPkcs8") { 84 private_key = r.ReadHex(); 85 } else if (n == "type") { 86 ASSERT_EQ("RsaesPkcs1Decrypt", r.ReadString()); 87 } else if (n == "tests") { 88 WycheproofReadTests(r, &tests, ReadTestAttr, false, 89 [](RsaDecryptTestVector& t, const std::string&, 90 const std::vector<std::string>& flags) { 91 t.invalid_padding = 92 std::find(flags.begin(), flags.end(), 93 "InvalidPkcs1Padding") != 94 flags.end(); 95 }); 96 } else { 97 FAIL() << "unknown label in group: " << n; 98 } 99 } 100 101 for (auto& t : tests) { 102 std::cout << "Running test " << t.id << std::endl; 103 t.priv_key = private_key; 104 TestDecrypt(t); 105 } 106 } 107 108 static void ReadTestAttr(RsaDecryptTestVector& t, const std::string& n, 109 JsonReader& r) { 110 if (n == "msg") { 111 t.msg = r.ReadHex(); 112 } else if (n == "ct") { 113 t.ct = r.ReadHex(); 114 } else { 115 FAIL() << "unsupported test case field: " << n; 116 } 117 } 118 }; 119 120 TEST_F(RsaDecryptWycheproofTest, Rsa2048) { Run("rsa_pkcs1_2048"); } 121 TEST_F(RsaDecryptWycheproofTest, Rsa3072) { Run("rsa_pkcs1_3072"); } 122 TEST_F(RsaDecryptWycheproofTest, Rsa4096) { Run("rsa_pkcs1_4096"); } 123 124 TEST_F(RsaDecryptWycheproofTest, Bb2048) { 125 for (auto& t : kRsaBb2048Vectors) { 126 RsaDecryptTestVector copy = t; 127 copy.priv_key = kRsaBb2048; 128 TestDecrypt(copy); 129 } 130 } 131 TEST_F(RsaDecryptWycheproofTest, Bb2049) { 132 for (auto& t : kRsaBb2049Vectors) { 133 RsaDecryptTestVector copy = t; 134 copy.priv_key = kRsaBb2049; 135 TestDecrypt(copy); 136 } 137 } 138 TEST_F(RsaDecryptWycheproofTest, Bb3072) { 139 for (auto& t : kRsaBb3072Vectors) { 140 RsaDecryptTestVector copy = t; 141 copy.priv_key = kRsaBb3072; 142 TestDecrypt(copy); 143 } 144 } 145 146 TEST(RsaEncryptTest, MessageLengths) { 147 const uint8_t spki[] = { 148 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 149 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30, 0x81, 150 0x89, 0x02, 0x81, 0x81, 0x00, 0xf8, 0xb8, 0x6c, 0x83, 0xb4, 0xbc, 0xd9, 151 0xa8, 0x57, 0xc0, 0xa5, 0xb4, 0x59, 0x76, 0x8c, 0x54, 0x1d, 0x79, 0xeb, 152 0x22, 0x52, 0x04, 0x7e, 0xd3, 0x37, 0xeb, 0x41, 0xfd, 0x83, 0xf9, 0xf0, 153 0xa6, 0x85, 0x15, 0x34, 0x75, 0x71, 0x5a, 0x84, 0xa8, 0x3c, 0xd2, 0xef, 154 0x5a, 0x4e, 0xd3, 0xde, 0x97, 0x8a, 0xdd, 0xff, 0xbb, 0xcf, 0x0a, 0xaa, 155 0x86, 0x92, 0xbe, 0xb8, 0x50, 0xe4, 0xcd, 0x6f, 0x80, 0x33, 0x30, 0x76, 156 0x13, 0x8f, 0xca, 0x7b, 0xdc, 0xec, 0x5a, 0xca, 0x63, 0xc7, 0x03, 0x25, 157 0xef, 0xa8, 0x8a, 0x83, 0x58, 0x76, 0x20, 0xfa, 0x16, 0x77, 0xd7, 0x79, 158 0x92, 0x63, 0x01, 0x48, 0x1a, 0xd8, 0x7b, 0x67, 0xf1, 0x52, 0x55, 0x49, 159 0x4e, 0xd6, 0x6e, 0x4a, 0x5c, 0xd7, 0x7a, 0x37, 0x36, 0x0c, 0xde, 0xdd, 160 0x8f, 0x44, 0xe8, 0xc2, 0xa7, 0x2c, 0x2b, 0xb5, 0xaf, 0x64, 0x4b, 0x61, 161 0x07, 0x02, 0x03, 0x01, 0x00, 0x01, 162 }; 163 164 // Import public key (use pre-generated for performance). 165 SECItem spki_item = {siBuffer, toUcharPtr(spki), sizeof(spki)}; 166 ScopedCERTSubjectPublicKeyInfo cert_spki( 167 SECKEY_DecodeDERSubjectPublicKeyInfo(&spki_item)); 168 ASSERT_TRUE(cert_spki); 169 ScopedSECKEYPublicKey pub_key(SECKEY_ExtractPublicKey(cert_spki.get())); 170 ASSERT_TRUE(pub_key); 171 172 int mod_len = SECKEY_PublicKeyStrength(pub_key.get()); 173 ASSERT_TRUE(mod_len > 0); 174 175 std::vector<uint8_t> ctxt(mod_len); 176 unsigned int ctxt_len; 177 std::vector<uint8_t> msg(mod_len, 0xff); 178 179 // Test with valid inputs 180 SECStatus rv = 181 PK11_PubEncrypt(pub_key.get(), CKM_RSA_PKCS, nullptr, ctxt.data(), 182 &ctxt_len, mod_len, msg.data(), 1, nullptr); 183 ASSERT_EQ(SECSuccess, rv); 184 185 // Maximum message length is mod_len - miniumum padding (8B) - flags (3B) 186 unsigned int max_msg_len = mod_len - 8 - 3; 187 rv = PK11_PubEncrypt(pub_key.get(), CKM_RSA_PKCS, nullptr, ctxt.data(), 188 &ctxt_len, mod_len, msg.data(), max_msg_len, nullptr); 189 ASSERT_EQ(SECSuccess, rv); 190 191 // Test one past maximum length 192 rv = 193 PK11_PubEncrypt(pub_key.get(), CKM_RSA_PKCS, nullptr, ctxt.data(), 194 &ctxt_len, mod_len, msg.data(), max_msg_len + 1, nullptr); 195 ASSERT_EQ(SECFailure, rv); 196 197 // Make sure the the length will not overflow - i.e. 198 // (padLen = modulusLen - (UINT_MAX + MINIMUM_PAD_LEN)) may overflow and 199 // result in a value that appears valid. 200 rv = PK11_PubEncrypt(pub_key.get(), CKM_RSA_PKCS, nullptr, ctxt.data(), 201 &ctxt_len, UINT_MAX, msg.data(), UINT_MAX, nullptr); 202 ASSERT_EQ(SECFailure, rv); 203 } 204 } // namespace nss_test