pk11_signature_test.cc (6451B)
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 "prerror.h" 10 11 #include "cpputil.h" 12 #include "nss_scoped_ptrs.h" 13 #include "databuffer.h" 14 15 #include "gtest/gtest.h" 16 #include "pk11_signature_test.h" 17 18 namespace nss_test { 19 20 ScopedSECKEYPrivateKey Pk11SignatureTest::ImportPrivateKey( 21 const DataBuffer& pkcs8) { 22 ScopedPK11SlotInfo slot(PK11_GetInternalSlot()); 23 if (!slot) { 24 ADD_FAILURE() << "No slot"; 25 return nullptr; 26 } 27 28 SECItem pkcs8Item = {siBuffer, toUcharPtr(pkcs8.data()), 29 static_cast<unsigned int>(pkcs8.len())}; 30 31 SECKEYPrivateKey* key = nullptr; 32 SECStatus rv = PK11_ImportDERPrivateKeyInfoAndReturnKey( 33 slot.get(), &pkcs8Item, nullptr, nullptr, false, false, KU_ALL, &key, 34 nullptr); 35 36 if (rv != SECSuccess) { 37 return nullptr; 38 } 39 40 return ScopedSECKEYPrivateKey(key); 41 } 42 43 ScopedSECKEYPublicKey Pk11SignatureTest::ImportPublicKey( 44 const DataBuffer& spki) { 45 SECItem spkiItem = {siBuffer, toUcharPtr(spki.data()), 46 static_cast<unsigned int>(spki.len())}; 47 48 ScopedCERTSubjectPublicKeyInfo certSpki( 49 SECKEY_DecodeDERSubjectPublicKeyInfo(&spkiItem)); 50 if (!certSpki) { 51 return nullptr; 52 } 53 54 return ScopedSECKEYPublicKey(SECKEY_ExtractPublicKey(certSpki.get())); 55 } 56 57 bool Pk11SignatureTest::SignRaw(ScopedSECKEYPrivateKey& privKey, 58 const DataBuffer& hash, DataBuffer* sig) { 59 SECItem hashItem = {siBuffer, toUcharPtr(hash.data()), 60 static_cast<unsigned int>(hash.len())}; 61 unsigned int sigLen = PK11_SignatureLen(privKey.get()); 62 EXPECT_LT(0, (int)sigLen); 63 sig->Allocate(static_cast<size_t>(sigLen)); 64 SECItem sigItem = {siBuffer, toUcharPtr(sig->data()), 65 static_cast<unsigned int>(sig->len())}; 66 SECStatus rv = PK11_SignWithMechanism(privKey.get(), mechanism_, parameters(), 67 &sigItem, &hashItem); 68 EXPECT_EQ(sigLen, sigItem.len); 69 return rv == SECSuccess; 70 } 71 72 bool Pk11SignatureTest::DigestAndSign(ScopedSECKEYPrivateKey& privKey, 73 const DataBuffer& data, DataBuffer* sig) { 74 unsigned int sigLen = PK11_SignatureLen(privKey.get()); 75 bool result = true; 76 EXPECT_LT(0, (int)sigLen); 77 sig->Allocate(static_cast<size_t>(sigLen)); 78 79 // test the hash and verify interface */ 80 PK11Context* context = PK11_CreateContextByPrivKey( 81 combo_, CKA_SIGN, privKey.get(), parameters()); 82 if (context == NULL) { 83 ADD_FAILURE() << "Failed to sign data: couldn't create context" 84 << "\n" 85 << "mech=0x" << std::hex << combo_ << "\n" 86 << "Error: " << PORT_ErrorToString(PORT_GetError()); 87 return false; 88 } 89 SECStatus rv = PK11_DigestOp(context, data.data(), data.len()); 90 if (rv != SECSuccess) { 91 ADD_FAILURE() << "Failed to sign data: Update failed\n" 92 << "Error: " << PORT_ErrorToString(PORT_GetError()); 93 PK11_DestroyContext(context, PR_TRUE); 94 return false; 95 } 96 unsigned int len = sigLen; 97 rv = PK11_DigestFinal(context, sig->data(), &len, sigLen); 98 if (rv != SECSuccess) { 99 ADD_FAILURE() << "Failed to sign data: final failed\n" 100 << "Error: " << PORT_ErrorToString(PORT_GetError()); 101 result = false; 102 } 103 if (len != sigLen) { 104 ADD_FAILURE() << "sign data: unexpected len " << len << "expected" 105 << sigLen; 106 result = false; 107 } 108 PK11_DestroyContext(context, PR_TRUE); 109 return result; 110 } 111 112 bool Pk11SignatureTest::ImportPrivateKeyAndSignHashedData( 113 const DataBuffer& pkcs8, const DataBuffer& data, DataBuffer* sig, 114 DataBuffer* sig2) { 115 ScopedSECKEYPrivateKey privKey(ImportPrivateKey(pkcs8)); 116 if (!privKey) { 117 return false; 118 } 119 120 DataBuffer hash; 121 if (!ComputeHash(data, &hash)) { 122 ADD_FAILURE() << "Failed to compute hash"; 123 return false; 124 } 125 if (!SignRaw(privKey, hash, sig)) { 126 ADD_FAILURE() << "Failed to sign hashed data"; 127 return false; 128 } 129 if (!DigestAndSign(privKey, data, sig2)) { 130 /* failure was already added by SignData, with an error message */ 131 return false; 132 } 133 return true; 134 } 135 136 void Pk11SignatureTest::Verify(ScopedSECKEYPublicKey& pubKey, 137 const DataBuffer& data, const DataBuffer& sig, 138 bool valid) { 139 SECStatus rv; 140 141 SECItem sigItem = {siBuffer, toUcharPtr(sig.data()), 142 static_cast<unsigned int>(sig.len())}; 143 144 if (skip_digest_) { 145 SECItem dataItem = {siBuffer, toUcharPtr(data.data()), 146 static_cast<unsigned int>(data.len())}; 147 rv = PK11_VerifyWithMechanism(pubKey.get(), mechanism_, parameters(), 148 &sigItem, &dataItem, nullptr); 149 EXPECT_EQ(rv, valid ? SECSuccess : SECFailure); 150 return; 151 } 152 153 DataBuffer hash; 154 /* RSA single shot requires encoding the hash before calling 155 * VerifyWithMechanism. We already check that mechanism 156 * with the VFY_ interface, so just do the combined hash/Verify 157 * in that case */ 158 if (!skip_raw_) { 159 ASSERT_TRUE(ComputeHash(data, &hash)); 160 161 // Verify. 162 SECItem hashItem = {siBuffer, toUcharPtr(hash.data()), 163 static_cast<unsigned int>(hash.len())}; 164 rv = PK11_VerifyWithMechanism(pubKey.get(), mechanism_, parameters(), 165 &sigItem, &hashItem, nullptr); 166 EXPECT_EQ(rv, valid ? SECSuccess : SECFailure); 167 } 168 169 // test the hash and verify interface */ 170 PK11Context* context = PK11_CreateContextByPubKey( 171 combo_, CKA_VERIFY, pubKey.get(), parameters(), NULL); 172 /* we assert here because we'll crash if we try to continue 173 * without a context. */ 174 ASSERT_NE((void*)context, (void*)NULL) 175 << "CreateContext failed Error:" << PORT_ErrorToString(PORT_GetError()) 176 << "\n"; 177 rv = PK11_DigestOp(context, data.data(), data.len()); 178 /* expect success unconditionally here */ 179 EXPECT_EQ(rv, SECSuccess); 180 unsigned int len; 181 rv = PK11_DigestFinal(context, sigItem.data, &len, sigItem.len); 182 EXPECT_EQ(rv, valid ? SECSuccess : SECFailure) 183 << "verify failed Error:" << PORT_ErrorToString(PORT_GetError()) << "\n"; 184 PK11_DestroyContext(context, PR_TRUE); 185 } 186 } // namespace nss_test