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