pk11_rsapkcs1_unittest.cc (12293B)
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 #include <memory> 10 #include "cryptohi.h" 11 #include "cpputil.h" 12 #include "databuffer.h" 13 #include "json_reader.h" 14 #include "gtest/gtest.h" 15 #include "nss.h" 16 #include "nss_scoped_ptrs.h" 17 #include "pk11pub.h" 18 #include "secerr.h" 19 #include "sechash.h" 20 #include "pk11_signature_test.h" 21 #include "testvectors/rsa_signature-vectors.h" 22 23 namespace nss_test { 24 25 CK_MECHANISM_TYPE RsaHashToComboMech(SECOidTag hash) { 26 switch (hash) { 27 case SEC_OID_SHA1: 28 return CKM_SHA1_RSA_PKCS; 29 case SEC_OID_SHA224: 30 return CKM_SHA224_RSA_PKCS; 31 case SEC_OID_SHA256: 32 return CKM_SHA256_RSA_PKCS; 33 case SEC_OID_SHA384: 34 return CKM_SHA384_RSA_PKCS; 35 case SEC_OID_SHA512: 36 return CKM_SHA512_RSA_PKCS; 37 default: 38 break; 39 } 40 return CKM_INVALID_MECHANISM; 41 } 42 43 class Pkcs11RsaBaseTest : public Pk11SignatureTest { 44 protected: 45 Pkcs11RsaBaseTest(SECOidTag hashOid) 46 : Pk11SignatureTest(CKM_RSA_PKCS, hashOid, RsaHashToComboMech(hashOid)) {} 47 48 void Verify(const RsaSignatureTestVector& vec) { 49 Pkcs11SignatureTestParams params = { 50 DataBuffer(), DataBuffer(vec.public_key.data(), vec.public_key.size()), 51 DataBuffer(vec.msg.data(), vec.msg.size()), 52 DataBuffer(vec.sig.data(), vec.sig.size())}; 53 Pk11SignatureTest::Verify(params, (bool)vec.valid); 54 } 55 }; 56 57 class Pkcs11RsaPkcs1WycheproofTest : public ::testing::Test { 58 protected: 59 static void ReadTestAttr(RsaSignatureTestVector& t, const std::string& n, 60 JsonReader& r) { 61 if (n == "msg") { 62 t.msg = r.ReadHex(); 63 } else if (n == "sig") { 64 t.sig = r.ReadHex(); 65 } else { 66 FAIL() << "unknown test key: " << n; 67 } 68 } 69 70 void RunGroup(JsonReader& r) { 71 std::vector<RsaSignatureTestVector> tests; 72 std::vector<uint8_t> public_key; 73 SECOidTag hash_oid = SEC_OID_UNKNOWN; 74 uint64_t keysize = 0; 75 while (r.NextItem()) { 76 std::string n = r.ReadLabel(); 77 if (n == "") { 78 break; 79 } 80 if (n == "e" || n == "keyAsn" || n == "keyJwk" || n == "keyPem" || 81 n == "n") { 82 r.SkipValue(); 83 } else if (n == "keyDer") { 84 public_key = r.ReadHex(); 85 } else if (n == "keysize") { 86 keysize = r.ReadInt(); 87 } else if (n == "type") { 88 ASSERT_EQ("RsassaPkcs1Verify", r.ReadString()); 89 } else if (n == "sha") { 90 hash_oid = r.ReadHash(); 91 } else if (n == "tests") { 92 WycheproofReadTests( 93 r, &tests, ReadTestAttr, false, 94 [keysize](RsaSignatureTestVector& t, const std::string& result, 95 const std::vector<std::string>& flags) { 96 if (result == "acceptable" && keysize >= 1024 && 97 std::find_if(flags.begin(), flags.end(), [](std::string v) { 98 return v == "SmallModulus" || v == "SmallPublicKey"; 99 }) != flags.end()) { 100 t.valid = true; 101 }; 102 }); 103 } else { 104 FAIL() << "unknown group label: " << n; 105 } 106 } 107 108 for (auto& t : tests) { 109 Pkcs11RsaBaseTestWrap test(hash_oid); 110 t.hash_oid = hash_oid; 111 t.public_key = public_key; 112 test.Run(t); 113 } 114 } 115 116 private: 117 class Pkcs11RsaBaseTestWrap : public Pkcs11RsaBaseTest { 118 public: 119 Pkcs11RsaBaseTestWrap(SECOidTag hash) : Pkcs11RsaBaseTest(hash) {} 120 void TestBody() {} 121 122 void Verify1(const RsaSignatureTestVector& vec) { 123 SECItem spki_item = {siBuffer, toUcharPtr(vec.public_key.data()), 124 static_cast<unsigned int>(vec.public_key.size())}; 125 126 ScopedCERTSubjectPublicKeyInfo cert_spki( 127 SECKEY_DecodeDERSubjectPublicKeyInfo(&spki_item)); 128 ASSERT_TRUE(cert_spki); 129 130 ScopedSECKEYPublicKey pub_key(SECKEY_ExtractPublicKey(cert_spki.get())); 131 ASSERT_TRUE(pub_key); 132 133 DataBuffer hash; 134 hash.Allocate(static_cast<size_t>(HASH_ResultLenByOidTag(vec.hash_oid))); 135 SECStatus rv = PK11_HashBuf(vec.hash_oid, toUcharPtr(hash.data()), 136 toUcharPtr(vec.msg.data()), vec.msg.size()); 137 ASSERT_EQ(rv, SECSuccess); 138 139 // Verify. 140 SECItem hash_item = {siBuffer, toUcharPtr(hash.data()), 141 static_cast<unsigned int>(hash.len())}; 142 SECItem sig_item = {siBuffer, toUcharPtr(vec.sig.data()), 143 static_cast<unsigned int>(vec.sig.size())}; 144 145 rv = VFY_VerifyDigestDirect(&hash_item, pub_key.get(), &sig_item, 146 SEC_OID_PKCS1_RSA_ENCRYPTION, vec.hash_oid, 147 nullptr); 148 EXPECT_EQ(rv, vec.valid ? SECSuccess : SECFailure); 149 }; 150 151 void Run(const RsaSignatureTestVector& vec) { 152 /* Using VFY_ interface */ 153 Verify1(vec); 154 /* Using PKCS #11 interface */ 155 setSkipRaw(true); 156 Verify(vec); 157 } 158 }; 159 }; 160 161 /* Test that PKCS #1 v1.5 verification requires a minimum of 8B 162 * of padding, per-RFC3447. The padding formula is 163 * `pad_len = em_len - t_len - 3`, where em_len is the octet length 164 * of the RSA modulus and t_len is the length of the `DigestInfo || 165 * Hash(message)` sequence. For SHA512, t_len is 83. We'll tweak the 166 * modulus size to test with a pad_len of 8 (valid) and 6 (invalid): 167 * em_len = `8 + 83 + 3` = `94*8` = 752b 168 * em_len = `6 + 83 + 3` = `92*8` = 736b 169 * Use 6 as the invalid value since modLen % 16 must be zero. 170 */ 171 TEST(RsaPkcs1Test, Pkcs1MinimumPadding) { 172 #define RSA_SHORT_KEY_LENGTH 736 173 /* if our minimum supported key length is big enough to handle 174 * our largest Hash function, we can't test a short length */ 175 #if RSA_MIN_MODULUS_BITS < RSA_SHORT_KEY_LENGTH 176 const size_t kRsaShortKeyBits = RSA_SHORT_KEY_LENGTH; 177 const size_t kRsaKeyBits = 752; 178 static const std::vector<uint8_t> kMsg{'T', 'E', 'S', 'T'}; 179 static const std::vector<uint8_t> kSha512DigestInfo{ 180 0x30, 0x51, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 181 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00, 0x04, 0x40}; 182 static const std::vector<uint8_t> kMsgSha512{ 183 0x7B, 0xFA, 0x95, 0xA6, 0x88, 0x92, 0x4C, 0x47, 0xC7, 0xD2, 0x23, 184 0x81, 0xF2, 0x0C, 0xC9, 0x26, 0xF5, 0x24, 0xBE, 0xAC, 0xB1, 0x3F, 185 0x84, 0xE2, 0x03, 0xD4, 0xBD, 0x8C, 0xB6, 0xBA, 0x2F, 0xCE, 0x81, 186 0xC5, 0x7A, 0x5F, 0x05, 0x9B, 0xF3, 0xD5, 0x09, 0x92, 0x64, 0x87, 187 0xBD, 0xE9, 0x25, 0xB3, 0xBC, 0xEE, 0x06, 0x35, 0xE4, 0xF7, 0xBA, 188 0xEB, 0xA0, 0x54, 0xE5, 0xDB, 0xA6, 0x96, 0xB2, 0xBF}; 189 190 ScopedSECKEYPrivateKey short_priv, good_priv; 191 ScopedSECKEYPublicKey short_pub, good_pub; 192 PK11RSAGenParams rsa_params; 193 rsa_params.keySizeInBits = kRsaShortKeyBits; 194 rsa_params.pe = 65537; 195 196 ScopedPK11SlotInfo slot(PK11_GetInternalSlot()); 197 ASSERT_TRUE(slot); 198 SECKEYPublicKey* p_pub_tmp = nullptr; 199 short_priv.reset(PK11_GenerateKeyPair(slot.get(), CKM_RSA_PKCS_KEY_PAIR_GEN, 200 &rsa_params, &p_pub_tmp, false, false, 201 nullptr)); 202 short_pub.reset(p_pub_tmp); 203 204 rsa_params.keySizeInBits = kRsaKeyBits; 205 good_priv.reset(PK11_GenerateKeyPair(slot.get(), CKM_RSA_PKCS_KEY_PAIR_GEN, 206 &rsa_params, &p_pub_tmp, false, false, 207 nullptr)); 208 good_pub.reset(p_pub_tmp); 209 210 size_t em_len = kRsaShortKeyBits / 8; 211 size_t t_len = kSha512DigestInfo.size() + kMsgSha512.size(); 212 size_t pad_len = em_len - t_len - 3; 213 ASSERT_EQ(6U, pad_len); 214 215 std::vector<uint8_t> invalid_pkcs; 216 invalid_pkcs.push_back(0x00); 217 invalid_pkcs.push_back(0x01); 218 invalid_pkcs.insert(invalid_pkcs.end(), pad_len, 0xff); 219 invalid_pkcs.insert(invalid_pkcs.end(), 1, 0x00); 220 invalid_pkcs.insert(invalid_pkcs.end(), kSha512DigestInfo.begin(), 221 kSha512DigestInfo.end()); 222 invalid_pkcs.insert(invalid_pkcs.end(), kMsgSha512.begin(), kMsgSha512.end()); 223 ASSERT_EQ(em_len, invalid_pkcs.size()); 224 225 // Sign it indirectly. Signing functions check for a proper pad_len. 226 std::vector<uint8_t> sig(em_len); 227 uint32_t sig_len; 228 SECStatus rv = 229 PK11_PubDecryptRaw(short_priv.get(), sig.data(), &sig_len, sig.size(), 230 invalid_pkcs.data(), invalid_pkcs.size()); 231 EXPECT_EQ(SECSuccess, rv); 232 233 // Verify it. 234 DataBuffer hash; 235 hash.Allocate(static_cast<size_t>(HASH_ResultLenByOidTag(SEC_OID_SHA512))); 236 rv = PK11_HashBuf(SEC_OID_SHA512, toUcharPtr(hash.data()), 237 toUcharPtr(kMsg.data()), kMsg.size()); 238 ASSERT_EQ(rv, SECSuccess); 239 SECItem hash_item = {siBuffer, toUcharPtr(hash.data()), 240 static_cast<unsigned int>(hash.len())}; 241 SECItem sig_item = {siBuffer, toUcharPtr(sig.data()), sig_len}; 242 /* don't let policy foil us */ 243 NSS_OptionSet(NSS_KEY_SIZE_POLICY_CLEAR_FLAGS, 244 NSS_KEY_SIZE_POLICY_VERIFY_FLAG); 245 rv = VFY_VerifyDigestDirect(&hash_item, short_pub.get(), &sig_item, 246 SEC_OID_PKCS1_RSA_ENCRYPTION, SEC_OID_SHA512, 247 nullptr); 248 EXPECT_EQ(SECFailure, rv); 249 EXPECT_EQ(SEC_ERROR_BAD_SIGNATURE, PORT_GetError()); 250 251 // Repeat the test with the sufficiently-long key. 252 em_len = kRsaKeyBits / 8; 253 t_len = kSha512DigestInfo.size() + kMsgSha512.size(); 254 pad_len = em_len - t_len - 3; 255 ASSERT_EQ(8U, pad_len); 256 257 std::vector<uint8_t> valid_pkcs; 258 valid_pkcs.push_back(0x00); 259 valid_pkcs.push_back(0x01); 260 valid_pkcs.insert(valid_pkcs.end(), pad_len, 0xff); 261 valid_pkcs.insert(valid_pkcs.end(), 1, 0x00); 262 valid_pkcs.insert(valid_pkcs.end(), kSha512DigestInfo.begin(), 263 kSha512DigestInfo.end()); 264 valid_pkcs.insert(valid_pkcs.end(), kMsgSha512.begin(), kMsgSha512.end()); 265 ASSERT_EQ(em_len, valid_pkcs.size()); 266 267 // Sign it the same way as above (even though we could use sign APIs now). 268 sig.resize(em_len); 269 rv = PK11_PubDecryptRaw(good_priv.get(), sig.data(), &sig_len, sig.size(), 270 valid_pkcs.data(), valid_pkcs.size()); 271 EXPECT_EQ(SECSuccess, rv); 272 273 // Verify it. 274 sig_item = {siBuffer, toUcharPtr(sig.data()), sig_len}; 275 rv = VFY_VerifyDigestDirect(&hash_item, good_pub.get(), &sig_item, 276 SEC_OID_PKCS1_RSA_ENCRYPTION, SEC_OID_SHA512, 277 nullptr); 278 EXPECT_EQ(SECSuccess, rv); 279 #else 280 GTEST_SKIP(); 281 #endif 282 } 283 284 TEST(RsaPkcs1Test, RequireNullParameter) { 285 // The test vectors may be verified with: 286 // 287 // openssl rsautl -keyform der -pubin -inkey spki.bin -in sig.bin | der2ascii 288 // openssl rsautl -keyform der -pubin -inkey spki.bin -in sig2.bin | der2ascii 289 290 // Import public key. 291 SECItem spki_item = {siBuffer, toUcharPtr(kSpki), sizeof(kSpki)}; 292 ScopedCERTSubjectPublicKeyInfo cert_spki( 293 SECKEY_DecodeDERSubjectPublicKeyInfo(&spki_item)); 294 ASSERT_TRUE(cert_spki); 295 ScopedSECKEYPublicKey pub_key(SECKEY_ExtractPublicKey(cert_spki.get())); 296 ASSERT_TRUE(pub_key); 297 298 SECItem hash = {siBuffer, toUcharPtr(kHash), sizeof(kHash)}; 299 300 // kSignature is a valid signature. 301 SECItem sig_item = {siBuffer, toUcharPtr(kSignature), sizeof(kSignature)}; 302 SECStatus rv = VFY_VerifyDigestDirect(&hash, pub_key.get(), &sig_item, 303 SEC_OID_PKCS1_RSA_ENCRYPTION, 304 SEC_OID_SHA256, nullptr); 305 EXPECT_EQ(SECSuccess, rv); 306 307 // kSignatureInvalid is not. 308 sig_item = {siBuffer, toUcharPtr(kSignatureInvalid), 309 sizeof(kSignatureInvalid)}; 310 rv = VFY_VerifyDigestDirect(&hash, pub_key.get(), &sig_item, 311 SEC_OID_PKCS1_RSA_ENCRYPTION, SEC_OID_SHA256, 312 nullptr); 313 #ifdef NSS_PKCS1_AllowMissingParameters 314 EXPECT_EQ(SECSuccess, rv); 315 #else 316 EXPECT_EQ(SECFailure, rv); 317 #endif 318 } 319 320 TEST_F(Pkcs11RsaPkcs1WycheproofTest, Pkcs11RsaPkcs1WycheproofTest) { 321 WycheproofHeader("rsa_signature", "RSASSA-PKCS1-v1_5", 322 "rsassa_pkcs1_verify_schema.json", 323 [this](JsonReader& r) { RunGroup(r); }); 324 } 325 326 } // namespace nss_test