summaryrefslogtreecommitdiffstats
path: root/security/nss/gtests/pk11_gtest/pk11_signature_test.h
blob: cd46f17d745955d753da2132647f907123730add (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
/* 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 "cpputil.h"
#include "nss_scoped_ptrs.h"
#include "databuffer.h"

#include "gtest/gtest.h"

namespace nss_test {

// For test vectors.
struct Pkcs11SignatureTestParams {
  const DataBuffer pkcs8_;
  const DataBuffer spki_;
  const DataBuffer data_;
  const DataBuffer signature_;
};

class Pk11SignatureTest : public ::testing::Test {
 protected:
  Pk11SignatureTest(CK_MECHANISM_TYPE mech, SECOidTag hash_oid)
      : mechanism_(mech), hash_oid_(hash_oid) {}

  virtual const SECItem* parameters() const { return nullptr; }
  CK_MECHANISM_TYPE mechanism() const { return mechanism_; }

  ScopedSECKEYPrivateKey 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 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 ComputeHash(const DataBuffer& data, DataBuffer* hash) {
    hash->Allocate(static_cast<size_t>(HASH_ResultLenByOidTag(hash_oid_)));
    SECStatus rv =
        PK11_HashBuf(hash_oid_, hash->data(), data.data(), data.len());
    return rv == SECSuccess;
  }

  bool SignHashedData(ScopedSECKEYPrivateKey& privKey, const DataBuffer& hash,
                      DataBuffer* sig) {
    SECItem hashItem = {siBuffer, toUcharPtr(hash.data()),
                        static_cast<unsigned int>(hash.len())};
    int sigLen = PK11_SignatureLen(privKey.get());
    EXPECT_LT(0, 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);
    return rv == SECSuccess;
  }

  bool ImportPrivateKeyAndSignHashedData(const DataBuffer& pkcs8,
                                         const DataBuffer& data,
                                         DataBuffer* sig) {
    ScopedSECKEYPrivateKey privKey(ImportPrivateKey(pkcs8));
    if (!privKey) {
      return false;
    }

    DataBuffer hash;
    if (!ComputeHash(data, &hash)) {
      ADD_FAILURE() << "Failed to compute hash";
      return false;
    }
    return SignHashedData(privKey, hash, sig);
  }

  void Verify(const Pkcs11SignatureTestParams& params, const DataBuffer& sig) {
    ScopedSECKEYPublicKey pubKey(ImportPublicKey(params.spki_));
    ASSERT_TRUE(pubKey);

    DataBuffer hash;
    ASSERT_TRUE(ComputeHash(params.data_, &hash));

    // Verify.
    SECItem hashItem = {siBuffer, toUcharPtr(hash.data()),
                        static_cast<unsigned int>(hash.len())};
    SECItem sigItem = {siBuffer, toUcharPtr(sig.data()),
                       static_cast<unsigned int>(sig.len())};
    SECStatus rv = PK11_VerifyWithMechanism(
        pubKey.get(), mechanism_, parameters(), &sigItem, &hashItem, nullptr);
    EXPECT_EQ(rv, SECSuccess);
  }

  void Verify(const Pkcs11SignatureTestParams& params) {
    Verify(params, params.signature_);
  }

  void SignAndVerify(const Pkcs11SignatureTestParams& params) {
    DataBuffer sig;
    ASSERT_TRUE(
        ImportPrivateKeyAndSignHashedData(params.pkcs8_, params.data_, &sig));
    Verify(params, sig);
  }

 private:
  CK_MECHANISM_TYPE mechanism_;
  SECOidTag hash_oid_;
};

}  // namespace nss_test