Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/security/pkix/test/lib/pkixtestnss.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
3
/* This code is made available to you under your choice of the following sets
4
 * of licensing terms:
5
 */
6
/* This Source Code Form is subject to the terms of the Mozilla Public
7
 * License, v. 2.0. If a copy of the MPL was not distributed with this
8
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9
 */
10
/* Copyright 2013 Mozilla Contributors
11
 *
12
 * Licensed under the Apache License, Version 2.0 (the "License");
13
 * you may not use this file except in compliance with the License.
14
 * You may obtain a copy of the License at
15
 *
16
 *     http://www.apache.org/licenses/LICENSE-2.0
17
 *
18
 * Unless required by applicable law or agreed to in writing, software
19
 * distributed under the License is distributed on an "AS IS" BASIS,
20
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21
 * See the License for the specific language governing permissions and
22
 * limitations under the License.
23
 */
24
25
#include "pkixtestutil.h"
26
#include "pkixtestnss.h"
27
28
#include <limits>
29
30
#include "cryptohi.h"
31
#include "keyhi.h"
32
#include "nss.h"
33
#include "pk11pqg.h"
34
#include "pk11pub.h"
35
#include "pkix/pkixnss.h"
36
#include "pkixder.h"
37
#include "pkixutil.h"
38
#include "prinit.h"
39
#include "secerr.h"
40
#include "secitem.h"
41
42
namespace mozilla { namespace pkix { namespace test {
43
44
namespace {
45
46
inline void
47
SECITEM_FreeItem_true(SECItem* item)
48
0
{
49
0
  SECITEM_FreeItem(item, true);
50
0
}
51
52
inline void
53
SECKEY_DestroyEncryptedPrivateKeyInfo_true(SECKEYEncryptedPrivateKeyInfo* e)
54
0
{
55
0
  SECKEY_DestroyEncryptedPrivateKeyInfo(e, true);
56
0
}
57
58
typedef mozilla::pkix::ScopedPtr<SECItem, SECITEM_FreeItem_true> ScopedSECItem;
59
60
TestKeyPair* GenerateKeyPairInner();
61
62
void
63
InitNSSIfNeeded()
64
0
{
65
0
  if (NSS_NoDB_Init(nullptr) != SECSuccess) {
66
0
    abort();
67
0
  }
68
0
}
69
70
static ScopedTestKeyPair reusedKeyPair;
71
72
PRStatus
73
InitReusedKeyPair()
74
0
{
75
0
  InitNSSIfNeeded();
76
0
  reusedKeyPair.reset(GenerateKeyPairInner());
77
0
  return reusedKeyPair ? PR_SUCCESS : PR_FAILURE;
78
0
}
79
80
class NSSTestKeyPair final : public TestKeyPair
81
{
82
public:
83
  NSSTestKeyPair(const TestPublicKeyAlgorithm& aPublicKeyAlg,
84
                 const ByteString& spk,
85
                 const ByteString& aEncryptedPrivateKey,
86
                 const ByteString& aEncryptionAlgorithm,
87
                 const ByteString& aEncryptionParams)
88
    : TestKeyPair(aPublicKeyAlg, spk)
89
    , encryptedPrivateKey(aEncryptedPrivateKey)
90
    , encryptionAlgorithm(aEncryptionAlgorithm)
91
    , encryptionParams(aEncryptionParams)
92
0
  {
93
0
  }
94
95
  Result SignData(const ByteString& tbs,
96
                  const TestSignatureAlgorithm& signatureAlgorithm,
97
                  /*out*/ ByteString& signature) const override
98
0
  {
99
0
    SECOidTag oidTag;
100
0
    if (signatureAlgorithm.publicKeyAlg == RSA_PKCS1()) {
101
0
      switch (signatureAlgorithm.digestAlg) {
102
0
        case TestDigestAlgorithmID::MD2:
103
0
          oidTag = SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION;
104
0
          break;
105
0
        case TestDigestAlgorithmID::MD5:
106
0
          oidTag = SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION;
107
0
          break;
108
0
        case TestDigestAlgorithmID::SHA1:
109
0
          oidTag = SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION;
110
0
          break;
111
0
        case TestDigestAlgorithmID::SHA224:
112
0
          oidTag = SEC_OID_PKCS1_SHA224_WITH_RSA_ENCRYPTION;
113
0
          break;
114
0
        case TestDigestAlgorithmID::SHA256:
115
0
          oidTag = SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION;
116
0
          break;
117
0
        case TestDigestAlgorithmID::SHA384:
118
0
          oidTag = SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION;
119
0
          break;
120
0
        case TestDigestAlgorithmID::SHA512:
121
0
          oidTag = SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION;
122
0
          break;
123
0
        MOZILLA_PKIX_UNREACHABLE_DEFAULT_ENUM
124
0
      }
125
0
    } else {
126
0
      abort();
127
0
    }
128
0
129
0
    ScopedPtr<PK11SlotInfo, PK11_FreeSlot> slot(PK11_GetInternalSlot());
130
0
    if (!slot) {
131
0
      return MapPRErrorCodeToResult(PR_GetError());
132
0
    }
133
0
    SECItem encryptedPrivateKeyInfoItem = {
134
0
      siBuffer,
135
0
      const_cast<uint8_t*>(encryptedPrivateKey.data()),
136
0
      static_cast<unsigned int>(encryptedPrivateKey.length())
137
0
    };
138
0
    SECItem encryptionAlgorithmItem = {
139
0
      siBuffer,
140
0
      const_cast<uint8_t*>(encryptionAlgorithm.data()),
141
0
      static_cast<unsigned int>(encryptionAlgorithm.length())
142
0
    };
143
0
    SECItem encryptionParamsItem = {
144
0
      siBuffer,
145
0
      const_cast<uint8_t*>(encryptionParams.data()),
146
0
      static_cast<unsigned int>(encryptionParams.length())
147
0
    };
148
0
    SECKEYEncryptedPrivateKeyInfo encryptedPrivateKeyInfo = {
149
0
      nullptr,
150
0
      { encryptionAlgorithmItem, encryptionParamsItem },
151
0
      encryptedPrivateKeyInfoItem
152
0
    };
153
0
    SECItem passwordItem = { siBuffer, nullptr, 0 };
154
0
    SECItem publicValueItem = {
155
0
      siBuffer,
156
0
      const_cast<uint8_t*>(subjectPublicKey.data()),
157
0
      static_cast<unsigned int>(subjectPublicKey.length())
158
0
    };
159
0
    SECKEYPrivateKey* privateKey;
160
0
    // This should always be an RSA key (we'll have aborted above if we're not
161
0
    // doing an RSA signature).
162
0
    if (PK11_ImportEncryptedPrivateKeyInfoAndReturnKey(
163
0
          slot.get(), &encryptedPrivateKeyInfo, &passwordItem, nullptr,
164
0
          &publicValueItem, false, false, rsaKey, KU_ALL, &privateKey,
165
0
          nullptr) != SECSuccess) {
166
0
      return MapPRErrorCodeToResult(PR_GetError());
167
0
    }
168
0
    ScopedSECKEYPrivateKey scopedPrivateKey(privateKey);
169
0
    SECItem signatureItem;
170
0
    if (SEC_SignData(&signatureItem, tbs.data(),
171
0
                     static_cast<int>(tbs.length()),
172
0
                     scopedPrivateKey.get(), oidTag) != SECSuccess) {
173
0
      return MapPRErrorCodeToResult(PR_GetError());
174
0
    }
175
0
    signature.assign(signatureItem.data, signatureItem.len);
176
0
    SECITEM_FreeItem(&signatureItem, false);
177
0
    return Success;
178
0
  }
179
180
  TestKeyPair* Clone() const override
181
0
  {
182
0
    return new (std::nothrow) NSSTestKeyPair(publicKeyAlg,
183
0
                                             subjectPublicKey,
184
0
                                             encryptedPrivateKey,
185
0
                                             encryptionAlgorithm,
186
0
                                             encryptionParams);
187
0
  }
188
189
private:
190
  const ByteString encryptedPrivateKey;
191
  const ByteString encryptionAlgorithm;
192
  const ByteString encryptionParams;
193
};
194
195
} // namespace
196
197
// This private function is also used by Gecko's PSM test framework
198
// (OCSPCommon.cpp).
199
TestKeyPair* CreateTestKeyPair(const TestPublicKeyAlgorithm publicKeyAlg,
200
                               const ScopedSECKEYPublicKey& publicKey,
201
                               const ScopedSECKEYPrivateKey& privateKey)
202
0
{
203
0
  ScopedPtr<CERTSubjectPublicKeyInfo, SECKEY_DestroySubjectPublicKeyInfo>
204
0
    spki(SECKEY_CreateSubjectPublicKeyInfo(publicKey.get()));
205
0
  if (!spki) {
206
0
    return nullptr;
207
0
  }
208
0
  SECItem spkDER = spki->subjectPublicKey;
209
0
  DER_ConvertBitString(&spkDER); // bits to bytes
210
0
  ScopedPtr<PK11SlotInfo, PK11_FreeSlot> slot(PK11_GetInternalSlot());
211
0
  if (!slot) {
212
0
    return nullptr;
213
0
  }
214
0
  // Because NSSTestKeyPair isn't tracked by XPCOM and won't otherwise be aware
215
0
  // of shutdown, we don't have a way to release NSS resources at the
216
0
  // appropriate time. To work around this, NSSTestKeyPair doesn't hold on to
217
0
  // NSS resources. Instead, we export the generated private key part as an
218
0
  // encrypted blob (with an empty password and fairly lame encryption). When we
219
0
  // need to use it (e.g. to sign something), we decrypt it and create a
220
0
  // temporary key object.
221
0
  SECItem passwordItem = { siBuffer, nullptr, 0 };
222
0
  ScopedPtr<SECKEYEncryptedPrivateKeyInfo,
223
0
            SECKEY_DestroyEncryptedPrivateKeyInfo_true> encryptedPrivateKey(
224
0
    PK11_ExportEncryptedPrivKeyInfo(
225
0
      slot.get(), SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_3KEY_TRIPLE_DES_CBC,
226
0
      &passwordItem, privateKey.get(), 1, nullptr));
227
0
  if (!encryptedPrivateKey) {
228
0
    return nullptr;
229
0
  }
230
0
231
0
  return new (std::nothrow) NSSTestKeyPair(
232
0
    publicKeyAlg,
233
0
    ByteString(spkDER.data, spkDER.len),
234
0
    ByteString(encryptedPrivateKey->encryptedData.data,
235
0
               encryptedPrivateKey->encryptedData.len),
236
0
    ByteString(encryptedPrivateKey->algorithm.algorithm.data,
237
0
               encryptedPrivateKey->algorithm.algorithm.len),
238
0
    ByteString(encryptedPrivateKey->algorithm.parameters.data,
239
0
               encryptedPrivateKey->algorithm.parameters.len));
240
0
}
241
242
namespace {
243
244
TestKeyPair*
245
GenerateKeyPairInner()
246
0
{
247
0
  ScopedPtr<PK11SlotInfo, PK11_FreeSlot> slot(PK11_GetInternalSlot());
248
0
  if (!slot) {
249
0
    abort();
250
0
  }
251
0
252
0
  // Bug 1012786: PK11_GenerateKeyPair can fail if there is insufficient
253
0
  // entropy to generate a random key. Attempting to add some entropy and
254
0
  // retrying appears to solve this issue.
255
0
  for (uint32_t retries = 0; retries < 10; retries++) {
256
0
    PK11RSAGenParams params;
257
0
    params.keySizeInBits = 2048;
258
0
    params.pe = 3;
259
0
    SECKEYPublicKey* publicKeyTemp = nullptr;
260
0
    ScopedSECKEYPrivateKey
261
0
      privateKey(PK11_GenerateKeyPair(slot.get(), CKM_RSA_PKCS_KEY_PAIR_GEN,
262
0
                                      &params, &publicKeyTemp, false, true,
263
0
                                      nullptr));
264
0
    ScopedSECKEYPublicKey publicKey(publicKeyTemp);
265
0
    if (privateKey) {
266
0
      return CreateTestKeyPair(RSA_PKCS1(), publicKey, privateKey);
267
0
    }
268
0
269
0
    assert(!publicKeyTemp);
270
0
271
0
    if (PR_GetError() != SEC_ERROR_PKCS11_FUNCTION_FAILED) {
272
0
      break;
273
0
    }
274
0
275
0
    // Since these keys are only for testing, we don't need them to be good,
276
0
    // random keys.
277
0
    // https://xkcd.com/221/
278
0
    static const uint8_t RANDOM_NUMBER[] = { 4, 4, 4, 4, 4, 4, 4, 4 };
279
0
    if (PK11_RandomUpdate((void*) &RANDOM_NUMBER,
280
0
                          sizeof(RANDOM_NUMBER)) != SECSuccess) {
281
0
      break;
282
0
    }
283
0
  }
284
0
285
0
  abort();
286
0
}
287
288
} // namespace
289
290
TestKeyPair*
291
GenerateKeyPair()
292
0
{
293
0
  InitNSSIfNeeded();
294
0
  return GenerateKeyPairInner();
295
0
}
296
297
TestKeyPair*
298
CloneReusedKeyPair()
299
0
{
300
0
  static PRCallOnceType initCallOnce;
301
0
  if (PR_CallOnce(&initCallOnce, InitReusedKeyPair) != PR_SUCCESS) {
302
0
    abort();
303
0
  }
304
0
  assert(reusedKeyPair);
305
0
  return reusedKeyPair->Clone();
306
0
}
307
308
TestKeyPair*
309
GenerateDSSKeyPair()
310
0
{
311
0
  InitNSSIfNeeded();
312
0
313
0
  ScopedPtr<PK11SlotInfo, PK11_FreeSlot> slot(PK11_GetInternalSlot());
314
0
  if (!slot) {
315
0
    return nullptr;
316
0
  }
317
0
318
0
  ByteString p(DSS_P());
319
0
  ByteString q(DSS_Q());
320
0
  ByteString g(DSS_G());
321
0
322
0
  static const PQGParams PARAMS = {
323
0
    nullptr,
324
0
    { siBuffer,
325
0
      const_cast<uint8_t*>(p.data()),
326
0
      static_cast<unsigned int>(p.length())
327
0
    },
328
0
    { siBuffer,
329
0
      const_cast<uint8_t*>(q.data()),
330
0
      static_cast<unsigned int>(q.length())
331
0
    },
332
0
    { siBuffer,
333
0
      const_cast<uint8_t*>(g.data()),
334
0
      static_cast<unsigned int>(g.length())
335
0
    }
336
0
  };
337
0
338
0
  SECKEYPublicKey* publicKeyTemp = nullptr;
339
0
  ScopedSECKEYPrivateKey
340
0
    privateKey(PK11_GenerateKeyPair(slot.get(), CKM_DSA_KEY_PAIR_GEN,
341
0
                                    const_cast<PQGParams*>(&PARAMS),
342
0
                                    &publicKeyTemp, false, true, nullptr));
343
0
  if (!privateKey) {
344
0
    return nullptr;
345
0
  }
346
0
  ScopedSECKEYPublicKey publicKey(publicKeyTemp);
347
0
  return CreateTestKeyPair(DSS(), publicKey, privateKey);
348
0
}
349
350
Result
351
TestVerifyECDSASignedDigest(const SignedDigest& signedDigest,
352
                            Input subjectPublicKeyInfo)
353
0
{
354
0
  InitNSSIfNeeded();
355
0
  return VerifyECDSASignedDigestNSS(signedDigest, subjectPublicKeyInfo,
356
0
                                    nullptr);
357
0
}
358
359
Result
360
TestVerifyRSAPKCS1SignedDigest(const SignedDigest& signedDigest,
361
                               Input subjectPublicKeyInfo)
362
0
{
363
0
  InitNSSIfNeeded();
364
0
  return VerifyRSAPKCS1SignedDigestNSS(signedDigest, subjectPublicKeyInfo,
365
0
                                       nullptr);
366
0
}
367
368
Result
369
TestDigestBuf(Input item,
370
              DigestAlgorithm digestAlg,
371
              /*out*/ uint8_t* digestBuf,
372
              size_t digestBufLen)
373
0
{
374
0
  InitNSSIfNeeded();
375
0
  return DigestBufNSS(item, digestAlg, digestBuf, digestBufLen);
376
0
}
377
378
} } } // namespace mozilla::pkix::test