summaryrefslogtreecommitdiffstats
path: root/security/nss/gtests/pk11_gtest/pk11_signature_test.cc
diff options
context:
space:
mode:
Diffstat (limited to 'security/nss/gtests/pk11_gtest/pk11_signature_test.cc')
-rw-r--r--security/nss/gtests/pk11_gtest/pk11_signature_test.cc179
1 files changed, 179 insertions, 0 deletions
diff --git a/security/nss/gtests/pk11_gtest/pk11_signature_test.cc b/security/nss/gtests/pk11_gtest/pk11_signature_test.cc
new file mode 100644
index 0000000000..c9700707fe
--- /dev/null
+++ b/security/nss/gtests/pk11_gtest/pk11_signature_test.cc
@@ -0,0 +1,179 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include <memory>
+#include "nss.h"
+#include "pk11pub.h"
+#include "sechash.h"
+#include "prerror.h"
+
+#include "cpputil.h"
+#include "nss_scoped_ptrs.h"
+#include "databuffer.h"
+
+#include "gtest/gtest.h"
+#include "pk11_signature_test.h"
+
+namespace nss_test {
+
+ScopedSECKEYPrivateKey Pk11SignatureTest::ImportPrivateKey(
+ const DataBuffer& pkcs8) {
+ ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
+ if (!slot) {
+ ADD_FAILURE() << "No slot";
+ return nullptr;
+ }
+
+ SECItem pkcs8Item = {siBuffer, toUcharPtr(pkcs8.data()),
+ static_cast<unsigned int>(pkcs8.len())};
+
+ SECKEYPrivateKey* key = nullptr;
+ SECStatus rv = PK11_ImportDERPrivateKeyInfoAndReturnKey(
+ slot.get(), &pkcs8Item, nullptr, nullptr, false, false, KU_ALL, &key,
+ nullptr);
+
+ if (rv != SECSuccess) {
+ return nullptr;
+ }
+
+ return ScopedSECKEYPrivateKey(key);
+}
+
+ScopedSECKEYPublicKey Pk11SignatureTest::ImportPublicKey(
+ const DataBuffer& spki) {
+ SECItem spkiItem = {siBuffer, toUcharPtr(spki.data()),
+ static_cast<unsigned int>(spki.len())};
+
+ ScopedCERTSubjectPublicKeyInfo certSpki(
+ SECKEY_DecodeDERSubjectPublicKeyInfo(&spkiItem));
+ if (!certSpki) {
+ return nullptr;
+ }
+
+ return ScopedSECKEYPublicKey(SECKEY_ExtractPublicKey(certSpki.get()));
+}
+
+bool Pk11SignatureTest::SignHashedData(ScopedSECKEYPrivateKey& privKey,
+ const DataBuffer& hash,
+ DataBuffer* sig) {
+ SECItem hashItem = {siBuffer, toUcharPtr(hash.data()),
+ static_cast<unsigned int>(hash.len())};
+ unsigned int sigLen = PK11_SignatureLen(privKey.get());
+ EXPECT_LT(0, (int)sigLen);
+ sig->Allocate(static_cast<size_t>(sigLen));
+ SECItem sigItem = {siBuffer, toUcharPtr(sig->data()),
+ static_cast<unsigned int>(sig->len())};
+ SECStatus rv = PK11_SignWithMechanism(privKey.get(), mechanism_, parameters(),
+ &sigItem, &hashItem);
+ EXPECT_EQ(sigLen, sigItem.len);
+ return rv == SECSuccess;
+}
+
+bool Pk11SignatureTest::SignData(ScopedSECKEYPrivateKey& privKey,
+ const DataBuffer& data, DataBuffer* sig) {
+ unsigned int sigLen = PK11_SignatureLen(privKey.get());
+ bool result = true;
+ EXPECT_LT(0, (int)sigLen);
+ sig->Allocate(static_cast<size_t>(sigLen));
+
+ // test the hash and verify interface */
+ PK11Context* context = PK11_CreateContextByPrivKey(
+ combo_, CKA_SIGN, privKey.get(), parameters());
+ if (context == NULL) {
+ ADD_FAILURE() << "Failed to sign data: couldn't create context"
+ << "\n"
+ << "mech=0x" << std::hex << combo_ << "\n"
+ << "Error: " << PORT_ErrorToString(PORT_GetError());
+ return false;
+ }
+ SECStatus rv = PK11_DigestOp(context, data.data(), data.len());
+ if (rv != SECSuccess) {
+ ADD_FAILURE() << "Failed to sign data: Update failed\n"
+ << "Error: " << PORT_ErrorToString(PORT_GetError());
+ PK11_DestroyContext(context, PR_TRUE);
+ return false;
+ }
+ unsigned int len = sigLen;
+ rv = PK11_DigestFinal(context, sig->data(), &len, sigLen);
+ if (rv != SECSuccess) {
+ ADD_FAILURE() << "Failed to sign data: final failed\n"
+ << "Error: " << PORT_ErrorToString(PORT_GetError());
+ result = false;
+ }
+ if (len != sigLen) {
+ ADD_FAILURE() << "sign data: unexpected len " << len << "expected"
+ << sigLen;
+ result = false;
+ }
+ PK11_DestroyContext(context, PR_TRUE);
+ return result;
+}
+
+bool Pk11SignatureTest::ImportPrivateKeyAndSignHashedData(
+ const DataBuffer& pkcs8, const DataBuffer& data, DataBuffer* sig,
+ DataBuffer* sig2) {
+ ScopedSECKEYPrivateKey privKey(ImportPrivateKey(pkcs8));
+ if (!privKey) {
+ return false;
+ }
+
+ DataBuffer hash;
+ if (!ComputeHash(data, &hash)) {
+ ADD_FAILURE() << "Failed to compute hash";
+ return false;
+ }
+ if (!SignHashedData(privKey, hash, sig)) {
+ ADD_FAILURE() << "Failed to sign hashed data";
+ return false;
+ }
+ if (!SignData(privKey, data, sig2)) {
+ /* failure was already added by SignData, with an error message */
+ return false;
+ }
+ return true;
+}
+
+void Pk11SignatureTest::Verify(ScopedSECKEYPublicKey& pubKey,
+ const DataBuffer& data, const DataBuffer& sig,
+ bool valid) {
+ SECStatus rv;
+ DataBuffer hash;
+
+ SECItem sigItem = {siBuffer, toUcharPtr(sig.data()),
+ static_cast<unsigned int>(sig.len())};
+
+ /* RSA single shot requires encoding the hash before calling
+ * VerifyWithMechanism. We already check that mechanism
+ * with the VFY_ interface, so just do the combined hash/Verify
+ * in that case */
+ if (!skip_raw_) {
+ ASSERT_TRUE(ComputeHash(data, &hash));
+
+ // Verify.
+ SECItem hashItem = {siBuffer, toUcharPtr(hash.data()),
+ static_cast<unsigned int>(hash.len())};
+ rv = PK11_VerifyWithMechanism(pubKey.get(), mechanism_, parameters(),
+ &sigItem, &hashItem, nullptr);
+ EXPECT_EQ(rv, valid ? SECSuccess : SECFailure);
+ }
+
+ // test the hash and verify interface */
+ PK11Context* context = PK11_CreateContextByPubKey(
+ combo_, CKA_VERIFY, pubKey.get(), parameters(), NULL);
+ /* we assert here because we'll crash if we try to continue
+ * without a context. */
+ ASSERT_NE((void*)context, (void*)NULL)
+ << "CreateContext failed Error:" << PORT_ErrorToString(PORT_GetError())
+ << "\n";
+ rv = PK11_DigestOp(context, data.data(), data.len());
+ /* expect success unconditionally here */
+ EXPECT_EQ(rv, SECSuccess);
+ unsigned int len;
+ rv = PK11_DigestFinal(context, sigItem.data, &len, sigItem.len);
+ EXPECT_EQ(rv, valid ? SECSuccess : SECFailure)
+ << "verify failed Error:" << PORT_ErrorToString(PORT_GetError()) << "\n";
+ PK11_DestroyContext(context, PR_TRUE);
+}
+
+} // namespace nss_test