summaryrefslogtreecommitdiff
path: root/gtests/pk11_gtest/pk11_encrypt_derive_unittest.cc
blob: 1e957c9a5de1282c8a6bf2a79e3f1edde10b3563 (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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
/* 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 "pk11pub.h"
#include "nssutil.h"
#include <stdio.h>
#include "prerror.h"
#include "nss.h"
#include "gtest/gtest.h"
#include "nss_scoped_ptrs.h"
#include "cpputil.h"
#include "databuffer.h"
#include "util.h"

#define MAX_KEY_SIZE 24

namespace nss_test {

static const uint8_t kIv[] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
                              0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
                              0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
static const uint8_t kInput[] = {
    0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x00, 0xff, 0xee, 0xdd, 0xcc,
    0xbb, 0xaa, 0x99, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x00};

class EncryptDeriveTest
    : public ::testing::Test,
      public ::testing::WithParamInterface<CK_MECHANISM_TYPE> {
 public:
  void TestEncryptDerive() {
    ScopedPK11SymKey derived_key(PK11_Derive(key_.get(), derive_mech(),
                                             derive_param(), encrypt_mech(),
                                             CKA_DECRYPT, keysize()));
    ASSERT_TRUE(derived_key);

    uint8_t derived_key_data[MAX_KEY_SIZE];
    ASSERT_GE(sizeof(derived_key_data), keysize());
    GetKeyData(derived_key, derived_key_data, keysize());
    RemoveChecksum(derived_key_data);

    uint8_t reference_key_data[MAX_KEY_SIZE];
    unsigned int reference_len = 0;
    SECStatus rv = PK11_Encrypt(key_.get(), encrypt_mech(), encrypt_param(),
                                reference_key_data, &reference_len, keysize(),
                                kInput, keysize());
    ASSERT_EQ(SECSuccess, rv);
    ASSERT_EQ(keysize(), static_cast<size_t>(reference_len));
    RemoveChecksum(reference_key_data);

    EXPECT_EQ(DataBuffer(reference_key_data, keysize()),
              DataBuffer(derived_key_data, keysize()));
  }

 protected:
  unsigned int keysize() const { return 16; }

 private:
  CK_MECHANISM_TYPE encrypt_mech() const { return GetParam(); }

  CK_MECHANISM_TYPE derive_mech() const {
    switch (encrypt_mech()) {
      case CKM_DES3_ECB:
        return CKM_DES3_ECB_ENCRYPT_DATA;
      case CKM_DES3_CBC:
        return CKM_DES3_CBC_ENCRYPT_DATA;
      case CKM_AES_ECB:
        return CKM_AES_ECB_ENCRYPT_DATA;
      case CKM_AES_CBC:
        return CKM_AES_CBC_ENCRYPT_DATA;
      case CKM_CAMELLIA_ECB:
        return CKM_CAMELLIA_ECB_ENCRYPT_DATA;
      case CKM_CAMELLIA_CBC:
        return CKM_CAMELLIA_CBC_ENCRYPT_DATA;
#ifndef NSS_DISABLE_DEPRECATED_SEED
      case CKM_SEED_ECB:
        return CKM_SEED_ECB_ENCRYPT_DATA;
      case CKM_SEED_CBC:
        return CKM_SEED_CBC_ENCRYPT_DATA;
#endif
      default:
        ADD_FAILURE() << "Unknown mechanism";
        break;
    }
    return CKM_INVALID_MECHANISM;
  }

  SECItem* derive_param() const {
    static CK_AES_CBC_ENCRYPT_DATA_PARAMS aes_data;
    static CK_DES_CBC_ENCRYPT_DATA_PARAMS des_data;
    static CK_KEY_DERIVATION_STRING_DATA string_data;
    static SECItem param = {siBuffer, NULL, 0};

    switch (encrypt_mech()) {
      case CKM_DES3_ECB:
      case CKM_AES_ECB:
      case CKM_CAMELLIA_ECB:
#ifndef NSS_DISABLE_DEPRECATED_SEED
      case CKM_SEED_ECB:
#endif
        string_data.pData = toUcharPtr(kInput);
        string_data.ulLen = keysize();
        param.data = reinterpret_cast<uint8_t*>(&string_data);
        param.len = sizeof(string_data);
        break;

      case CKM_DES3_CBC:
        des_data.pData = toUcharPtr(kInput);
        des_data.length = keysize();
        PORT_Memcpy(des_data.iv, kIv, 8);
        param.data = reinterpret_cast<uint8_t*>(&des_data);
        param.len = sizeof(des_data);
        break;

      case CKM_AES_CBC:
      case CKM_CAMELLIA_CBC:
#ifndef NSS_DISABLE_DEPRECATED_SEED
      case CKM_SEED_CBC:
#endif
        aes_data.pData = toUcharPtr(kInput);
        aes_data.length = keysize();
        PORT_Memcpy(aes_data.iv, kIv, keysize());
        param.data = reinterpret_cast<uint8_t*>(&aes_data);
        param.len = sizeof(aes_data);
        break;

      default:
        ADD_FAILURE() << "Unknown mechanism";
        break;
    }
    return &param;
  }

  SECItem* encrypt_param() const {
    static SECItem param = {siBuffer, NULL, 0};

    switch (encrypt_mech()) {
      case CKM_DES3_ECB:
      case CKM_AES_ECB:
      case CKM_CAMELLIA_ECB:
#ifndef NSS_DISABLE_DEPRECATED_SEED
      case CKM_SEED_ECB:
#endif
        // No parameter needed here.
        break;

      case CKM_DES3_CBC:
      case CKM_AES_CBC:
      case CKM_CAMELLIA_CBC:
#ifndef NSS_DISABLE_DEPRECATED_SEED
      case CKM_SEED_CBC:
#endif
        param.data = toUcharPtr(kIv);
        param.len = keysize();
        break;

      default:
        ADD_FAILURE() << "Unknown mechanism";
        break;
    }
    return &param;
  }

  virtual void SetUp() {
    slot_.reset(PK11_GetBestSlot(derive_mech(), NULL));
    ASSERT_TRUE(slot_);

    key_.reset(PK11_TokenKeyGenWithFlags(slot_.get(), encrypt_mech(), NULL,
                                         keysize(), NULL,
                                         CKF_ENCRYPT | CKF_DERIVE, 0, NULL));
    ASSERT_TRUE(key_);
  }

  void GetKeyData(ScopedPK11SymKey& key, uint8_t* buf, size_t max_len) const {
    ASSERT_EQ(SECSuccess, PK11_ExtractKeyValue(key.get()));
    SECItem* data = PK11_GetKeyData(key.get());
    ASSERT_TRUE(data);
    ASSERT_EQ(max_len, static_cast<size_t>(data->len));
    PORT_Memcpy(buf, data->data, data->len);
  }

  // Remove checksum if the key is a 3DES key.
  void RemoveChecksum(uint8_t* key_data) const {
    if (encrypt_mech() != CKM_DES3_CBC && encrypt_mech() != CKM_DES3_ECB) {
      return;
    }
    for (size_t i = 0; i < keysize(); ++i) {
      key_data[i] &= 0xfe;
    }
  }

  ScopedPK11SlotInfo slot_;
  ScopedPK11SymKey key_;
};

TEST_P(EncryptDeriveTest, Test) { TestEncryptDerive(); }

static const CK_MECHANISM_TYPE kEncryptDeriveMechanisms[] = {CKM_DES3_ECB,
                                                             CKM_DES3_CBC,
                                                             CKM_AES_ECB,
                                                             CKM_AES_ECB,
                                                             CKM_AES_CBC,
                                                             CKM_CAMELLIA_ECB,
                                                             CKM_CAMELLIA_CBC
#ifndef NSS_DISABLE_DEPRECATED_SEED
                                                             ,
                                                             CKM_SEED_ECB,
                                                             CKM_SEED_CBC
#endif
};

INSTANTIATE_TEST_SUITE_P(EncryptDeriveTests, EncryptDeriveTest,
                         ::testing::ValuesIn(kEncryptDeriveMechanisms));

// This class handles the case where 3DES takes a 192-bit key
// where all 24 octets will be used.
class EncryptDerive3Test : public EncryptDeriveTest {
 protected:
  unsigned int keysize() const { return 24; }
};

TEST_P(EncryptDerive3Test, Test) { TestEncryptDerive(); }

static const CK_MECHANISM_TYPE kDES3EncryptDeriveMechanisms[] = {CKM_DES3_ECB,
                                                                 CKM_DES3_CBC};

INSTANTIATE_TEST_SUITE_P(Encrypt3DeriveTests, EncryptDerive3Test,
                         ::testing::ValuesIn(kDES3EncryptDeriveMechanisms));

}  // namespace nss_test