Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/security/manager/ssl/nsKeygenHandler.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2
 *
3
 * This Source Code Form is subject to the terms of the Mozilla Public
4
 * License, v. 2.0. If a copy of the MPL was not distributed with this
5
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7
#include "nsKeygenHandler.h"
8
9
#include "cryptohi.h"
10
#include "keyhi.h"
11
#include "mozilla/Assertions.h"
12
#include "mozilla/Base64.h"
13
#include "mozilla/Casting.h"
14
15
/* Disable the "base class should be explicitly initialized in the
16
   copy constructor" warning that some bindings structs trigger while
17
   including Element.h.  Looks like it's an inherent part of -Wextra,
18
   so we can't just disable it in a targeted way in moz.build. */
19
#if defined(__clang__)
20
#pragma clang diagnostic push
21
#pragma clang diagnostic ignored "-Wextra"
22
#elif defined(__GNUC__)
23
#pragma GCC diagnostic push
24
#pragma GCC diagnostic ignored "-Wextra"
25
#endif // __clang__ || __GNUC__
26
27
#include "mozilla/dom/Element.h"
28
29
#if defined(__clang__)
30
#pragma clang diagnostic pop
31
#elif defined(__GNUC__)
32
#pragma GCC diagnostic pop
33
#endif // __clang__ || __GNUC__
34
35
#include "nsDependentString.h"
36
#include "nsIContent.h"
37
#include "nsIGenKeypairInfoDlg.h"
38
#include "nsIServiceManager.h"
39
#include "nsITokenDialogs.h"
40
#include "nsKeygenHandlerContent.h"
41
#include "nsKeygenThread.h"
42
#include "nsMemory.h"
43
#include "nsNSSHelper.h"
44
#include "nsReadableUtils.h"
45
#include "nsUnicharUtils.h"
46
#include "nsXULAppAPI.h"
47
#include "nspr.h"
48
#include "secasn1.h"
49
#include "secder.h"
50
#include "secdert.h"
51
52
using mozilla::dom::Element;
53
54
//These defines are taken from the PKCS#11 spec
55
0
#define CKM_RSA_PKCS_KEY_PAIR_GEN     0x00000000
56
0
#define CKM_DH_PKCS_KEY_PAIR_GEN      0x00000020
57
58
DERTemplate SECAlgorithmIDTemplate[] = {
59
    { DER_SEQUENCE,
60
          0, nullptr, sizeof(SECAlgorithmID) },
61
    { DER_OBJECT_ID,
62
          offsetof(SECAlgorithmID,algorithm), },
63
    { DER_OPTIONAL | DER_ANY,
64
          offsetof(SECAlgorithmID,parameters), },
65
    { 0, }
66
};
67
68
DERTemplate CERTSubjectPublicKeyInfoTemplate[] = {
69
    { DER_SEQUENCE,
70
          0, nullptr, sizeof(CERTSubjectPublicKeyInfo) },
71
    { DER_INLINE,
72
          offsetof(CERTSubjectPublicKeyInfo,algorithm),
73
          SECAlgorithmIDTemplate, },
74
    { DER_BIT_STRING,
75
          offsetof(CERTSubjectPublicKeyInfo,subjectPublicKey), },
76
    { 0, }
77
};
78
79
DERTemplate CERTPublicKeyAndChallengeTemplate[] =
80
{
81
    { DER_SEQUENCE, 0, nullptr, sizeof(CERTPublicKeyAndChallenge) },
82
    { DER_ANY, offsetof(CERTPublicKeyAndChallenge,spki), },
83
    { DER_IA5_STRING, offsetof(CERTPublicKeyAndChallenge,challenge), },
84
    { 0, }
85
};
86
87
typedef struct curveNameTagPairStr {
88
    const char *curveName;
89
    SECOidTag curveOidTag;
90
} CurveNameTagPair;
91
92
static CurveNameTagPair nameTagPair[] =
93
{
94
  { "prime192v1", SEC_OID_ANSIX962_EC_PRIME192V1 },
95
  { "prime192v2", SEC_OID_ANSIX962_EC_PRIME192V2 },
96
  { "prime192v3", SEC_OID_ANSIX962_EC_PRIME192V3 },
97
  { "prime239v1", SEC_OID_ANSIX962_EC_PRIME239V1 },
98
  { "prime239v2", SEC_OID_ANSIX962_EC_PRIME239V2 },
99
  { "prime239v3", SEC_OID_ANSIX962_EC_PRIME239V3 },
100
  { "prime256v1", SEC_OID_ANSIX962_EC_PRIME256V1 },
101
102
  { "secp112r1", SEC_OID_SECG_EC_SECP112R1},
103
  { "secp112r2", SEC_OID_SECG_EC_SECP112R2},
104
  { "secp128r1", SEC_OID_SECG_EC_SECP128R1},
105
  { "secp128r2", SEC_OID_SECG_EC_SECP128R2},
106
  { "secp160k1", SEC_OID_SECG_EC_SECP160K1},
107
  { "secp160r1", SEC_OID_SECG_EC_SECP160R1},
108
  { "secp160r2", SEC_OID_SECG_EC_SECP160R2},
109
  { "secp192k1", SEC_OID_SECG_EC_SECP192K1},
110
  { "secp192r1", SEC_OID_ANSIX962_EC_PRIME192V1 },
111
  { "nistp192", SEC_OID_ANSIX962_EC_PRIME192V1 },
112
  { "secp224k1", SEC_OID_SECG_EC_SECP224K1},
113
  { "secp224r1", SEC_OID_SECG_EC_SECP224R1},
114
  { "nistp224", SEC_OID_SECG_EC_SECP224R1},
115
  { "secp256k1", SEC_OID_SECG_EC_SECP256K1},
116
  { "secp256r1", SEC_OID_ANSIX962_EC_PRIME256V1 },
117
  { "nistp256", SEC_OID_ANSIX962_EC_PRIME256V1 },
118
  { "secp384r1", SEC_OID_SECG_EC_SECP384R1},
119
  { "nistp384", SEC_OID_SECG_EC_SECP384R1},
120
  { "secp521r1", SEC_OID_SECG_EC_SECP521R1},
121
  { "nistp521", SEC_OID_SECG_EC_SECP521R1},
122
123
  { "c2pnb163v1", SEC_OID_ANSIX962_EC_C2PNB163V1 },
124
  { "c2pnb163v2", SEC_OID_ANSIX962_EC_C2PNB163V2 },
125
  { "c2pnb163v3", SEC_OID_ANSIX962_EC_C2PNB163V3 },
126
  { "c2pnb176v1", SEC_OID_ANSIX962_EC_C2PNB176V1 },
127
  { "c2tnb191v1", SEC_OID_ANSIX962_EC_C2TNB191V1 },
128
  { "c2tnb191v2", SEC_OID_ANSIX962_EC_C2TNB191V2 },
129
  { "c2tnb191v3", SEC_OID_ANSIX962_EC_C2TNB191V3 },
130
  { "c2onb191v4", SEC_OID_ANSIX962_EC_C2ONB191V4 },
131
  { "c2onb191v5", SEC_OID_ANSIX962_EC_C2ONB191V5 },
132
  { "c2pnb208w1", SEC_OID_ANSIX962_EC_C2PNB208W1 },
133
  { "c2tnb239v1", SEC_OID_ANSIX962_EC_C2TNB239V1 },
134
  { "c2tnb239v2", SEC_OID_ANSIX962_EC_C2TNB239V2 },
135
  { "c2tnb239v3", SEC_OID_ANSIX962_EC_C2TNB239V3 },
136
  { "c2onb239v4", SEC_OID_ANSIX962_EC_C2ONB239V4 },
137
  { "c2onb239v5", SEC_OID_ANSIX962_EC_C2ONB239V5 },
138
  { "c2pnb272w1", SEC_OID_ANSIX962_EC_C2PNB272W1 },
139
  { "c2pnb304w1", SEC_OID_ANSIX962_EC_C2PNB304W1 },
140
  { "c2tnb359v1", SEC_OID_ANSIX962_EC_C2TNB359V1 },
141
  { "c2pnb368w1", SEC_OID_ANSIX962_EC_C2PNB368W1 },
142
  { "c2tnb431r1", SEC_OID_ANSIX962_EC_C2TNB431R1 },
143
144
  { "sect113r1", SEC_OID_SECG_EC_SECT113R1},
145
  { "sect113r2", SEC_OID_SECG_EC_SECT113R2},
146
  { "sect131r1", SEC_OID_SECG_EC_SECT131R1},
147
  { "sect131r2", SEC_OID_SECG_EC_SECT131R2},
148
  { "sect163k1", SEC_OID_SECG_EC_SECT163K1},
149
  { "nistk163", SEC_OID_SECG_EC_SECT163K1},
150
  { "sect163r1", SEC_OID_SECG_EC_SECT163R1},
151
  { "sect163r2", SEC_OID_SECG_EC_SECT163R2},
152
  { "nistb163", SEC_OID_SECG_EC_SECT163R2},
153
  { "sect193r1", SEC_OID_SECG_EC_SECT193R1},
154
  { "sect193r2", SEC_OID_SECG_EC_SECT193R2},
155
  { "sect233k1", SEC_OID_SECG_EC_SECT233K1},
156
  { "nistk233", SEC_OID_SECG_EC_SECT233K1},
157
  { "sect233r1", SEC_OID_SECG_EC_SECT233R1},
158
  { "nistb233", SEC_OID_SECG_EC_SECT233R1},
159
  { "sect239k1", SEC_OID_SECG_EC_SECT239K1},
160
  { "sect283k1", SEC_OID_SECG_EC_SECT283K1},
161
  { "nistk283", SEC_OID_SECG_EC_SECT283K1},
162
  { "sect283r1", SEC_OID_SECG_EC_SECT283R1},
163
  { "nistb283", SEC_OID_SECG_EC_SECT283R1},
164
  { "sect409k1", SEC_OID_SECG_EC_SECT409K1},
165
  { "nistk409", SEC_OID_SECG_EC_SECT409K1},
166
  { "sect409r1", SEC_OID_SECG_EC_SECT409R1},
167
  { "nistb409", SEC_OID_SECG_EC_SECT409R1},
168
  { "sect571k1", SEC_OID_SECG_EC_SECT571K1},
169
  { "nistk571", SEC_OID_SECG_EC_SECT571K1},
170
  { "sect571r1", SEC_OID_SECG_EC_SECT571R1},
171
  { "nistb571", SEC_OID_SECG_EC_SECT571R1},
172
173
};
174
175
mozilla::UniqueSECItem
176
DecodeECParams(const char* curve)
177
0
{
178
0
    SECOidData *oidData = nullptr;
179
0
    SECOidTag curveOidTag = SEC_OID_UNKNOWN; /* default */
180
0
    int i, numCurves;
181
0
182
0
    if (curve && *curve) {
183
0
        numCurves = sizeof(nameTagPair)/sizeof(CurveNameTagPair);
184
0
        for (i = 0; ((i < numCurves) && (curveOidTag == SEC_OID_UNKNOWN));
185
0
             i++) {
186
0
            if (PL_strcmp(curve, nameTagPair[i].curveName) == 0)
187
0
                curveOidTag = nameTagPair[i].curveOidTag;
188
0
        }
189
0
    }
190
0
191
0
    /* Return nullptr if curve name is not recognized */
192
0
    if ((curveOidTag == SEC_OID_UNKNOWN) ||
193
0
        (oidData = SECOID_FindOIDByTag(curveOidTag)) == nullptr) {
194
0
        return nullptr;
195
0
    }
196
0
197
0
    mozilla::UniqueSECItem ecparams(SECITEM_AllocItem(nullptr, nullptr,
198
0
                                                      2 + oidData->oid.len));
199
0
    if (!ecparams) {
200
0
        return nullptr;
201
0
    }
202
0
203
0
    /*
204
0
     * ecparams->data needs to contain the ASN encoding of an object ID (OID)
205
0
     * representing the named curve. The actual OID is in
206
0
     * oidData->oid.data so we simply prepend 0x06 and OID length
207
0
     */
208
0
    ecparams->data[0] = SEC_ASN1_OBJECT_ID;
209
0
    ecparams->data[1] = oidData->oid.len;
210
0
    memcpy(ecparams->data + 2, oidData->oid.data, oidData->oid.len);
211
0
212
0
    return ecparams;
213
0
}
214
215
NS_IMPL_ISUPPORTS(nsKeygenFormProcessor, nsIFormProcessor)
216
217
nsKeygenFormProcessor::nsKeygenFormProcessor()
218
0
{
219
0
   m_ctx = new PipUIContext();
220
0
}
221
222
nsresult
223
nsKeygenFormProcessor::Create(nsISupports* aOuter, const nsIID& aIID, void* *aResult)
224
0
{
225
0
  if (GeckoProcessType_Content == XRE_GetProcessType()) {
226
0
    nsCOMPtr<nsISupports> contentProcessor = new nsKeygenFormProcessorContent();
227
0
    return contentProcessor->QueryInterface(aIID, aResult);
228
0
  }
229
0
230
0
  nsresult rv;
231
0
  NS_ENSURE_NO_AGGREGATION(aOuter);
232
0
  nsKeygenFormProcessor* formProc = new nsKeygenFormProcessor();
233
0
234
0
  nsCOMPtr<nsISupports> stabilize = formProc;
235
0
  rv = formProc->Init();
236
0
  if (NS_SUCCEEDED(rv)) {
237
0
    rv = formProc->QueryInterface(aIID, aResult);
238
0
  }
239
0
  return rv;
240
0
}
241
242
nsresult
243
nsKeygenFormProcessor::Init()
244
0
{
245
0
  // Init possible key size choices.
246
0
  GetPIPNSSBundleString("HighGrade", mSECKeySizeChoiceList[0].name);
247
0
  mSECKeySizeChoiceList[0].size = 2048;
248
0
249
0
  GetPIPNSSBundleString("MediumGrade", mSECKeySizeChoiceList[1].name);
250
0
  mSECKeySizeChoiceList[1].size = 1024;
251
0
252
0
  return NS_OK;
253
0
}
254
255
nsresult
256
nsKeygenFormProcessor::GetSlot(uint32_t aMechanism, PK11SlotInfo** aSlot)
257
0
{
258
0
  return GetSlotWithMechanism(aMechanism, m_ctx, aSlot);
259
0
}
260
261
uint32_t MapGenMechToAlgoMech(uint32_t mechanism)
262
0
{
263
0
    uint32_t searchMech;
264
0
265
0
    /* We are interested in slots based on the ability to perform
266
0
       a given algorithm, not on their ability to generate keys usable
267
0
       by that algorithm. Therefore, map keygen-specific mechanism tags
268
0
       to tags for the corresponding crypto algorithm. */
269
0
    switch(mechanism)
270
0
    {
271
0
    case CKM_RSA_PKCS_KEY_PAIR_GEN:
272
0
        searchMech = CKM_RSA_PKCS;
273
0
        break;
274
0
    case CKM_RC4_KEY_GEN:
275
0
        searchMech = CKM_RC4;
276
0
        break;
277
0
    case CKM_DH_PKCS_KEY_PAIR_GEN:
278
0
        searchMech = CKM_DH_PKCS_DERIVE; /* ### mwelch  is this right? */
279
0
        break;
280
0
    case CKM_DES_KEY_GEN:
281
0
        /* What do we do about DES keygen? Right now, we're just using
282
0
           DES_KEY_GEN to look for tokens, because otherwise we'll have
283
0
           to search the token list three times. */
284
0
    case CKM_EC_KEY_PAIR_GEN:
285
0
        /* The default should also work for EC key pair generation. */
286
0
    default:
287
0
        searchMech = mechanism;
288
0
        break;
289
0
    }
290
0
    return searchMech;
291
0
}
292
293
294
nsresult
295
GetSlotWithMechanism(uint32_t aMechanism, nsIInterfaceRequestor* m_ctx,
296
                     PK11SlotInfo** aSlot)
297
0
{
298
0
    PK11SlotList * slotList = nullptr;
299
0
    char16_t** tokenNameList = nullptr;
300
0
    nsCOMPtr<nsITokenDialogs> dialogs;
301
0
    nsAutoString tokenStr;
302
0
    PK11SlotListElement *slotElement, *tmpSlot;
303
0
    uint32_t numSlots = 0, i = 0;
304
0
    bool canceled;
305
0
    nsresult rv = NS_OK;
306
0
307
0
    *aSlot = nullptr;
308
0
309
0
    // Get the slot
310
0
    slotList = PK11_GetAllTokens(MapGenMechToAlgoMech(aMechanism),
311
0
                                true, true, m_ctx);
312
0
    if (!slotList || !slotList->head) {
313
0
        rv = NS_ERROR_FAILURE;
314
0
        goto loser;
315
0
    }
316
0
317
0
    if (!slotList->head->next) {
318
0
        /* only one slot available, just return it */
319
0
        *aSlot = slotList->head->slot;
320
0
      } else {
321
0
        // Gerenate a list of slots and ask the user to choose //
322
0
        tmpSlot = slotList->head;
323
0
        while (tmpSlot) {
324
0
            numSlots++;
325
0
            tmpSlot = tmpSlot->next;
326
0
        }
327
0
328
0
        // Allocate the slot name buffer //
329
0
        tokenNameList = static_cast<char16_t**>(moz_xmalloc(sizeof(char16_t *) * numSlots));
330
0
331
0
        i = 0;
332
0
        slotElement = PK11_GetFirstSafe(slotList);
333
0
        while (slotElement) {
334
0
            tokenNameList[i] = UTF8ToNewUnicode(nsDependentCString(PK11_GetTokenName(slotElement->slot)));
335
0
            slotElement = PK11_GetNextSafe(slotList, slotElement, false);
336
0
            if (tokenNameList[i])
337
0
                i++;
338
0
            else {
339
0
                // OOM. adjust numSlots so we don't free unallocated memory.
340
0
                numSlots = i;
341
0
                PK11_FreeSlotListElement(slotList, slotElement);
342
0
                rv = NS_ERROR_OUT_OF_MEMORY;
343
0
                goto loser;
344
0
            }
345
0
        }
346
0
347
0
        // Throw up the token list dialog and get back the token.
348
0
        rv = getNSSDialogs(getter_AddRefs(dialogs), NS_GET_IID(nsITokenDialogs),
349
0
                           NS_TOKENDIALOGS_CONTRACTID);
350
0
351
0
        if (NS_FAILED(rv)) {
352
0
            goto loser;
353
0
        }
354
0
355
0
    if (!tokenNameList || !*tokenNameList) {
356
0
        rv = NS_ERROR_OUT_OF_MEMORY;
357
0
    } else {
358
0
        rv = dialogs->ChooseToken(m_ctx, (const char16_t**)tokenNameList,
359
0
                                  numSlots, tokenStr, &canceled);
360
0
    }
361
0
    if (NS_FAILED(rv)) goto loser;
362
0
363
0
    if (canceled) { rv = NS_ERROR_NOT_AVAILABLE; goto loser; }
364
0
365
0
        // Get the slot //
366
0
        slotElement = PK11_GetFirstSafe(slotList);
367
0
        while (slotElement) {
368
0
            if (tokenStr.Equals(NS_ConvertUTF8toUTF16(PK11_GetTokenName(slotElement->slot)))) {
369
0
                *aSlot = slotElement->slot;
370
0
                PK11_FreeSlotListElement(slotList, slotElement);
371
0
                break;
372
0
            }
373
0
            slotElement = PK11_GetNextSafe(slotList, slotElement, false);
374
0
        }
375
0
        if(!(*aSlot)) {
376
0
            rv = NS_ERROR_FAILURE;
377
0
            goto loser;
378
0
        }
379
0
      }
380
0
381
0
      // Get a reference to the slot //
382
0
      PK11_ReferenceSlot(*aSlot);
383
0
loser:
384
0
      if (slotList) {
385
0
          PK11_FreeSlotList(slotList);
386
0
      }
387
0
      if (tokenNameList) {
388
0
          NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(numSlots, tokenNameList);
389
0
      }
390
0
      return rv;
391
0
}
392
393
nsresult
394
nsKeygenFormProcessor::GetPublicKey(const nsAString& aValue,
395
                                    const nsAString& aChallenge,
396
                                    const nsString& aKeyType,
397
                                    nsAString& aOutPublicKey,
398
                                    const nsAString& aKeyParams)
399
0
{
400
0
    nsresult rv = NS_ERROR_FAILURE;
401
0
    nsAutoCString keystring;
402
0
    char *keyparamsString = nullptr;
403
0
    uint32_t keyGenMechanism;
404
0
    PK11SlotInfo *slot = nullptr;
405
0
    PK11RSAGenParams rsaParams;
406
0
    mozilla::UniqueSECItem ecParams;
407
0
    SECOidTag algTag;
408
0
    int keysize = 0;
409
0
    void *params = nullptr; // Non-owning.
410
0
    SECKEYPrivateKey *privateKey = nullptr;
411
0
    SECKEYPublicKey *publicKey = nullptr;
412
0
    CERTSubjectPublicKeyInfo *spkInfo = nullptr;
413
0
    SECStatus srv = SECFailure;
414
0
    SECItem spkiItem;
415
0
    SECItem pkacItem;
416
0
    SECItem signedItem;
417
0
    nsDependentCSubstring signedItemStr;
418
0
    CERTPublicKeyAndChallenge pkac;
419
0
    pkac.challenge.data = nullptr;
420
0
    nsCOMPtr<nsIGeneratingKeypairInfoDialogs> dialogs;
421
0
    nsKeygenThread *KeygenRunnable = 0;
422
0
    nsCOMPtr<nsIKeygenThread> runnable;
423
0
424
0
    // permanent and sensitive flags for keygen
425
0
    PK11AttrFlags attrFlags = PK11_ATTR_TOKEN | PK11_ATTR_SENSITIVE | PK11_ATTR_PRIVATE;
426
0
427
0
    UniquePLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
428
0
    if (!arena) {
429
0
        goto loser;
430
0
    }
431
0
432
0
    // Get the key size //
433
0
    for (size_t i = 0; i < number_of_key_size_choices; ++i) {
434
0
        if (aValue.Equals(mSECKeySizeChoiceList[i].name)) {
435
0
            keysize = mSECKeySizeChoiceList[i].size;
436
0
            break;
437
0
        }
438
0
    }
439
0
    if (!keysize) {
440
0
        goto loser;
441
0
    }
442
0
443
0
    // Set the keygen mechanism
444
0
    if (aKeyType.IsEmpty() || aKeyType.LowerCaseEqualsLiteral("rsa")) {
445
0
        keyGenMechanism = CKM_RSA_PKCS_KEY_PAIR_GEN;
446
0
    } else if (aKeyType.LowerCaseEqualsLiteral("ec")) {
447
0
        keyparamsString = ToNewCString(aKeyParams);
448
0
        if (!keyparamsString) {
449
0
            rv = NS_ERROR_OUT_OF_MEMORY;
450
0
            goto loser;
451
0
        }
452
0
453
0
        keyGenMechanism = CKM_EC_KEY_PAIR_GEN;
454
0
        /* ecParams are initialized later */
455
0
    } else {
456
0
        goto loser;
457
0
    }
458
0
459
0
    // Get the slot
460
0
    rv = GetSlot(keyGenMechanism, &slot);
461
0
    if (NS_FAILED(rv)) {
462
0
        goto loser;
463
0
    }
464
0
    switch (keyGenMechanism) {
465
0
        case CKM_RSA_PKCS_KEY_PAIR_GEN:
466
0
            rsaParams.keySizeInBits = keysize;
467
0
            rsaParams.pe = DEFAULT_RSA_KEYGEN_PE;
468
0
            algTag = DEFAULT_RSA_KEYGEN_ALG;
469
0
            params = &rsaParams;
470
0
            break;
471
0
        case CKM_EC_KEY_PAIR_GEN:
472
0
            /* XXX We ought to rethink how the KEYGEN tag is
473
0
             * displayed. The pulldown selections presented
474
0
             * to the user must depend on the keytype.
475
0
             * The displayed selection could be picked
476
0
             * from the keyparams attribute (this is currently called
477
0
             * the pqg attribute).
478
0
             * For now, we pick ecparams from the keyparams field
479
0
             * if it specifies a valid supported curve, or else
480
0
             * we pick one of secp384r1, secp256r1 or secp192r1
481
0
             * respectively depending on the user's selection
482
0
             * (High, Medium, Low).
483
0
             * (RSA uses RSA-2048, RSA-1024 and RSA-512 for historical
484
0
             * reasons, while ECC choices represent a stronger mapping)
485
0
             * NOTE: The user's selection
486
0
             * is silently ignored when a valid curve is presented
487
0
             * in keyparams.
488
0
             */
489
0
            ecParams = DecodeECParams(keyparamsString);
490
0
            if (!ecParams) {
491
0
                /* The keyparams attribute did not specify a valid
492
0
                 * curve name so use a curve based on the keysize.
493
0
                 * NOTE: Here keysize is used only as an indication of
494
0
                 * High/Medium/Low strength; elliptic curve
495
0
                 * cryptography uses smaller keys than RSA to provide
496
0
                 * equivalent security.
497
0
                 */
498
0
                switch (keysize) {
499
0
                case 2048:
500
0
                    ecParams = DecodeECParams("secp384r1");
501
0
                    break;
502
0
                case 1024:
503
0
                case 512:
504
0
                    ecParams = DecodeECParams("secp256r1");
505
0
                    break;
506
0
                }
507
0
            }
508
0
            MOZ_ASSERT(ecParams);
509
0
            params = ecParams.get();
510
0
            /* XXX The signature algorithm ought to choose the hashing
511
0
             * algorithm based on key size once ECDSA variations based
512
0
             * on SHA256 SHA384 and SHA512 are standardized.
513
0
             */
514
0
            algTag = SEC_OID_ANSIX962_ECDSA_SIGNATURE_WITH_SHA1_DIGEST;
515
0
            break;
516
0
      default:
517
0
          goto loser;
518
0
      }
519
0
520
0
    /* Make sure token is initialized. */
521
0
    rv = setPassword(slot, m_ctx);
522
0
    if (NS_FAILED(rv))
523
0
        goto loser;
524
0
525
0
    srv = PK11_Authenticate(slot, true, m_ctx);
526
0
    if (srv != SECSuccess) {
527
0
        goto loser;
528
0
    }
529
0
530
0
    rv = getNSSDialogs(getter_AddRefs(dialogs),
531
0
                       NS_GET_IID(nsIGeneratingKeypairInfoDialogs),
532
0
                       NS_GENERATINGKEYPAIRINFODIALOGS_CONTRACTID);
533
0
534
0
    if (NS_SUCCEEDED(rv)) {
535
0
        KeygenRunnable = new nsKeygenThread();
536
0
        NS_IF_ADDREF(KeygenRunnable);
537
0
    }
538
0
539
0
    if (NS_FAILED(rv) || !KeygenRunnable) {
540
0
        rv = NS_OK;
541
0
        privateKey = PK11_GenerateKeyPairWithFlags(slot, keyGenMechanism, params,
542
0
                                                   &publicKey, attrFlags, m_ctx);
543
0
    } else {
544
0
        KeygenRunnable->SetParams( slot, attrFlags, nullptr, 0,
545
0
                                   keyGenMechanism, params, m_ctx );
546
0
547
0
        runnable = do_QueryInterface(KeygenRunnable);
548
0
        if (runnable) {
549
0
            rv = dialogs->DisplayGeneratingKeypairInfo(m_ctx, runnable);
550
0
            // We call join on the thread so we can be sure that no
551
0
            // simultaneous access to the passed parameters will happen.
552
0
            KeygenRunnable->Join();
553
0
554
0
            if (NS_SUCCEEDED(rv)) {
555
0
                PK11SlotInfo *used_slot = nullptr;
556
0
                rv = KeygenRunnable->ConsumeResult(&used_slot, &privateKey, &publicKey);
557
0
                if (NS_SUCCEEDED(rv) && used_slot) {
558
0
                  PK11_FreeSlot(used_slot);
559
0
                }
560
0
            }
561
0
        }
562
0
    }
563
0
564
0
    if (NS_FAILED(rv) || !privateKey) {
565
0
        goto loser;
566
0
    }
567
0
    // just in case we'll need to authenticate to the db -jp //
568
0
    privateKey->wincx = m_ctx;
569
0
570
0
    /*
571
0
     * Create a subject public key info from the public key.
572
0
     */
573
0
    spkInfo = SECKEY_CreateSubjectPublicKeyInfo(publicKey);
574
0
    if ( !spkInfo ) {
575
0
        goto loser;
576
0
    }
577
0
578
0
    /*
579
0
     * Now DER encode the whole subjectPublicKeyInfo.
580
0
     */
581
0
    srv = DER_Encode(arena.get(), &spkiItem, CERTSubjectPublicKeyInfoTemplate,
582
0
                     spkInfo);
583
0
    if (srv != SECSuccess) {
584
0
        goto loser;
585
0
    }
586
0
587
0
    /*
588
0
     * set up the PublicKeyAndChallenge data structure, then DER encode it
589
0
     */
590
0
    pkac.spki = spkiItem;
591
0
    pkac.challenge.len = aChallenge.Length();
592
0
    pkac.challenge.data = (unsigned char *)ToNewCString(aChallenge);
593
0
    if (!pkac.challenge.data) {
594
0
        rv = NS_ERROR_OUT_OF_MEMORY;
595
0
        goto loser;
596
0
    }
597
0
598
0
    srv = DER_Encode(arena.get(), &pkacItem, CERTPublicKeyAndChallengeTemplate,
599
0
                     &pkac);
600
0
    if (srv != SECSuccess) {
601
0
        goto loser;
602
0
    }
603
0
604
0
    /*
605
0
     * now sign the DER encoded PublicKeyAndChallenge
606
0
     */
607
0
    srv = SEC_DerSignData(arena.get(), &signedItem, pkacItem.data, pkacItem.len,
608
0
                          privateKey, algTag);
609
0
    if (srv != SECSuccess) {
610
0
        goto loser;
611
0
    }
612
0
613
0
    /*
614
0
     * Convert the signed public key and challenge into base64/ascii.
615
0
     */
616
0
    signedItemStr.Assign(
617
0
        mozilla::BitwiseCast<char*, unsigned char*>(signedItem.data),
618
0
        signedItem.len);
619
0
    rv = mozilla::Base64Encode(signedItemStr, keystring);
620
0
    if (NS_FAILED(rv)) {
621
0
        goto loser;
622
0
    }
623
0
624
0
    CopyASCIItoUTF16(keystring, aOutPublicKey);
625
0
626
0
    rv = NS_OK;
627
0
628
0
loser:
629
0
    if (srv != SECSuccess) {
630
0
        if ( privateKey ) {
631
0
            PK11_DestroyTokenObject(privateKey->pkcs11Slot,privateKey->pkcs11ID);
632
0
        }
633
0
        if ( publicKey ) {
634
0
            PK11_DestroyTokenObject(publicKey->pkcs11Slot,publicKey->pkcs11ID);
635
0
        }
636
0
    }
637
0
    if ( spkInfo ) {
638
0
        SECKEY_DestroySubjectPublicKeyInfo(spkInfo);
639
0
    }
640
0
    if ( publicKey ) {
641
0
        SECKEY_DestroyPublicKey(publicKey);
642
0
    }
643
0
    if ( privateKey ) {
644
0
        SECKEY_DestroyPrivateKey(privateKey);
645
0
    }
646
0
    if (slot) {
647
0
        PK11_FreeSlot(slot);
648
0
    }
649
0
    if (KeygenRunnable) {
650
0
        NS_RELEASE(KeygenRunnable);
651
0
    }
652
0
    if (keyparamsString) {
653
0
        free(keyparamsString);
654
0
    }
655
0
    if (pkac.challenge.data) {
656
0
        free(pkac.challenge.data);
657
0
    }
658
0
    return rv;
659
0
}
660
661
// static
662
void
663
nsKeygenFormProcessor::ExtractParams(Element* aElement,
664
                                     nsAString& challengeValue,
665
                                     nsAString& keyTypeValue,
666
                                     nsAString& keyParamsValue)
667
0
{
668
0
    aElement->GetAttribute(NS_LITERAL_STRING("keytype"), keyTypeValue);
669
0
    if (keyTypeValue.IsEmpty()) {
670
0
        // If this field is not present, we default to rsa.
671
0
        keyTypeValue.AssignLiteral("rsa");
672
0
    }
673
0
674
0
    aElement->GetAttribute(NS_LITERAL_STRING("pqg"),
675
0
                           keyParamsValue);
676
0
    /* XXX We can still support the pqg attribute in the keygen
677
0
     * tag for backward compatibility while introducing a more
678
0
     * general attribute named keyparams.
679
0
     */
680
0
    if (keyParamsValue.IsEmpty()) {
681
0
        aElement->GetAttribute(NS_LITERAL_STRING("keyparams"),
682
0
                               keyParamsValue);
683
0
    }
684
0
685
0
    aElement->GetAttribute(NS_LITERAL_STRING("challenge"), challengeValue);
686
0
}
687
688
nsresult
689
nsKeygenFormProcessor::ProcessValue(Element* aElement,
690
                                    const nsAString& aName,
691
                                    nsAString& aValue)
692
0
{
693
0
    nsAutoString challengeValue;
694
0
    nsAutoString keyTypeValue;
695
0
    nsAutoString keyParamsValue;
696
0
    ExtractParams(aElement, challengeValue, keyTypeValue, keyParamsValue);
697
0
698
0
    return GetPublicKey(aValue, challengeValue, keyTypeValue,
699
0
                        aValue, keyParamsValue);
700
0
}
701
702
nsresult
703
nsKeygenFormProcessor::ProcessValueIPC(const nsAString& aOldValue,
704
                                       const nsAString& aChallenge,
705
                                       const nsAString& aKeyType,
706
                                       const nsAString& aKeyParams,
707
                                       nsAString& newValue)
708
0
{
709
0
    return GetPublicKey(aOldValue, aChallenge, PromiseFlatString(aKeyType),
710
0
                        newValue, aKeyParams);
711
0
}
712
713
nsresult
714
nsKeygenFormProcessor::ProvideContent(const nsAString& aFormType,
715
                                      nsTArray<nsString>& aContent,
716
                                      nsAString& aAttribute)
717
0
{
718
0
  if (Compare(aFormType, NS_LITERAL_STRING("SELECT"),
719
0
              nsCaseInsensitiveStringComparator()) == 0) {
720
0
721
0
    for (size_t i = 0; i < number_of_key_size_choices; ++i) {
722
0
      aContent.AppendElement(mSECKeySizeChoiceList[i].name);
723
0
    }
724
0
    aAttribute.AssignLiteral("-mozilla-keygen");
725
0
  }
726
0
  return NS_OK;
727
0
}
728