Coverage Report

Created: 2026-10-13 06:23

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/nss/lib/pk11wrap/pk11pk12.c
Line
Count
Source
1
2
/* This Source Code Form is subject to the terms of the Mozilla Public
3
 * License, v. 2.0. If a copy of the MPL was not distributed with this
4
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
/*
6
 * This file PKCS #12 fuctions that should really be moved to the
7
 * PKCS #12 directory, however we can't do that in a point release
8
 * because that will break binary compatibility, so we keep them here for now.
9
 */
10
11
#include "seccomon.h"
12
#include "secmod.h"
13
#include "secmodi.h"
14
#include "secmodti.h"
15
#include "secmodt.h"
16
#include "pkcs11.h"
17
#include "pk11func.h"
18
#include "secitem.h"
19
#include "keyhi.h"
20
#include "keyi.h"
21
#include "secoid.h"
22
#include "secasn1.h"
23
#include "secerr.h"
24
#include "prerror.h"
25
#include "secder.h"
26
27
/* These data structures should move to a common .h file shared between the
28
 * wrappers and the pkcs 12 code. */
29
30
/*
31
** RSA Raw Private Key structures
32
*/
33
34
/* member names from PKCS#1, section 7.2 */
35
struct SECKEYRSAPrivateKeyStr {
36
    PLArenaPool *arena;
37
    SECItem version;
38
    SECItem modulus;
39
    SECItem publicExponent;
40
    SECItem privateExponent;
41
    SECItem prime1;
42
    SECItem prime2;
43
    SECItem exponent1;
44
    SECItem exponent2;
45
    SECItem coefficient;
46
};
47
typedef struct SECKEYRSAPrivateKeyStr SECKEYRSAPrivateKey;
48
49
/*
50
** DSA Raw Private Key structures
51
*/
52
53
struct SECKEYDSAPrivateKeyStr {
54
    SECKEYPQGParams params;
55
    SECItem privateValue;
56
};
57
typedef struct SECKEYDSAPrivateKeyStr SECKEYDSAPrivateKey;
58
59
/*
60
** Diffie-Hellman Raw Private Key structures
61
** Structure member names suggested by PKCS#3.
62
*/
63
struct SECKEYDHPrivateKeyStr {
64
    PLArenaPool *arena;
65
    SECItem prime;
66
    SECItem base;
67
    SECItem privateValue;
68
};
69
typedef struct SECKEYDHPrivateKeyStr SECKEYDHPrivateKey;
70
71
/*
72
** Elliptic Curve Private Key structures
73
** <https://tools.ietf.org/html/rfc5915#section-3>
74
*/
75
struct SECKEYECPrivateKeyStr {
76
    PLArenaPool *arena;
77
    SECItem version;
78
    SECItem curveOID;    /* optional/ignored */
79
    SECItem publicValue; /* required (for now) */
80
    SECItem privateValue;
81
};
82
typedef struct SECKEYECPrivateKeyStr SECKEYECPrivateKey;
83
84
struct SECKEYPQSeedPrivateKeyStr {
85
    SECOidTag params;
86
    SECItem privateValue;
87
    SECItem seed;
88
};
89
typedef struct SECKEYPQSeedPrivateKeyStr SECKEYPQSeedPrivateKey;
90
typedef struct SECKEYPQSeedPrivateKeyStr SECKEYMLDSAPrivateKey;
91
typedef struct SECKEYPQSeedPrivateKeyStr SECKEYMLKEMPrivateKey;
92
93
/*
94
** raw private key object
95
*/
96
struct SECKEYRawPrivateKeyStr {
97
    PLArenaPool *arena;
98
    KeyType keyType;
99
    union {
100
        SECKEYRSAPrivateKey rsa;
101
        SECKEYDSAPrivateKey dsa;
102
        SECKEYDHPrivateKey dh;
103
        SECKEYECPrivateKey ec;
104
        SECKEYPQSeedPrivateKey pq;
105
        SECKEYMLDSAPrivateKey mldsa;
106
        SECKEYMLKEMPrivateKey mlkem;
107
    } u;
108
};
109
typedef struct SECKEYRawPrivateKeyStr SECKEYRawPrivateKey;
110
111
SEC_ASN1_MKSUB(SEC_AnyTemplate)
112
SEC_ASN1_MKSUB(SEC_BitStringTemplate)
113
SEC_ASN1_MKSUB(SEC_ObjectIDTemplate)
114
SEC_ASN1_MKSUB(SEC_OctetStringTemplate)
115
SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate)
116
117
/* ASN1 Templates for new decoder/encoder */
118
/*
119
 * Attribute value for PKCS8 entries (static?)
120
 */
121
const SEC_ASN1Template SECKEY_AttributeTemplate[] = {
122
    { SEC_ASN1_SEQUENCE,
123
      0, NULL, sizeof(SECKEYAttribute) },
124
    { SEC_ASN1_OBJECT_ID, offsetof(SECKEYAttribute, attrType) },
125
    { SEC_ASN1_SET_OF | SEC_ASN1_XTRN, offsetof(SECKEYAttribute, attrValue),
126
      SEC_ASN1_SUB(SEC_AnyTemplate) },
127
    { 0 }
128
};
129
130
const SEC_ASN1Template SECKEY_SetOfAttributeTemplate[] = {
131
    { SEC_ASN1_SET_OF, 0, SECKEY_AttributeTemplate },
132
};
133
134
/*
135
 * keep the publicly exported version one of this template.
136
 * We use v2 for decode only, since it can decode both v1 and
137
 * v2. We encode with v1.
138
 */
139
const SEC_ASN1Template SECKEY_PrivateKeyInfoTemplate[] = {
140
    { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SECKEYPrivateKeyInfo) },
141
    { SEC_ASN1_INTEGER, offsetof(SECKEYPrivateKeyInfo, version) },
142
    { SEC_ASN1_INLINE | SEC_ASN1_XTRN,
143
      offsetof(SECKEYPrivateKeyInfo, algorithm),
144
      SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
145
    { SEC_ASN1_OCTET_STRING, offsetof(SECKEYPrivateKeyInfo, privateKey) },
146
    { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0,
147
      offsetof(SECKEYPrivateKeyInfo, attributes),
148
      SECKEY_SetOfAttributeTemplate },
149
    { 0 }
150
};
151
152
/* keep the V2 struct private. In case we need to add new parameters in the future */
153
struct SECKEYPrivateKeyInfoV2Str {
154
    SECKEYPrivateKeyInfo v1;
155
    SECItem publicKey;
156
};
157
158
typedef struct SECKEYPrivateKeyInfoV2Str SECKEYPrivateKeyInfoV2;
159
160
/* PrivateKeyInfo is a public value, so we can't add parameters. so we need a new template
161
 * To hold the publicKey */
162
static const SEC_ASN1Template seckey_PrivateKeyInfoV2Template[] = {
163
    { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SECKEYPrivateKeyInfoV2) },
164
    { SEC_ASN1_INTEGER, offsetof(SECKEYPrivateKeyInfoV2, v1.version) },
165
    { SEC_ASN1_INLINE | SEC_ASN1_XTRN,
166
      offsetof(SECKEYPrivateKeyInfoV2, v1.algorithm),
167
      SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
168
    { SEC_ASN1_OCTET_STRING, offsetof(SECKEYPrivateKeyInfoV2, v1.privateKey) },
169
    { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0,
170
      offsetof(SECKEYPrivateKeyInfoV2, v1.attributes),
171
      SECKEY_SetOfAttributeTemplate },
172
    { SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 1,
173
      offsetof(SECKEYPrivateKeyInfoV2, publicKey),
174
      SEC_ASN1_SUB(SEC_BitStringTemplate) },
175
    { 0 }
176
};
177
178
const SEC_ASN1Template SECKEY_PointerToPrivateKeyInfoTemplate[] = {
179
    { SEC_ASN1_POINTER, 0, SECKEY_PrivateKeyInfoTemplate }
180
};
181
182
const SEC_ASN1Template SECKEY_RSAPrivateKeyExportTemplate[] = {
183
    { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SECKEYRawPrivateKey) },
184
    { SEC_ASN1_INTEGER, offsetof(SECKEYRawPrivateKey, u.rsa.version) },
185
    { SEC_ASN1_INTEGER, offsetof(SECKEYRawPrivateKey, u.rsa.modulus) },
186
    { SEC_ASN1_INTEGER, offsetof(SECKEYRawPrivateKey, u.rsa.publicExponent) },
187
    { SEC_ASN1_INTEGER, offsetof(SECKEYRawPrivateKey, u.rsa.privateExponent) },
188
    { SEC_ASN1_INTEGER, offsetof(SECKEYRawPrivateKey, u.rsa.prime1) },
189
    { SEC_ASN1_INTEGER, offsetof(SECKEYRawPrivateKey, u.rsa.prime2) },
190
    { SEC_ASN1_INTEGER, offsetof(SECKEYRawPrivateKey, u.rsa.exponent1) },
191
    { SEC_ASN1_INTEGER, offsetof(SECKEYRawPrivateKey, u.rsa.exponent2) },
192
    { SEC_ASN1_INTEGER, offsetof(SECKEYRawPrivateKey, u.rsa.coefficient) },
193
    { 0 }
194
};
195
196
const SEC_ASN1Template SECKEY_DSAPrivateKeyExportTemplate[] = {
197
    { SEC_ASN1_INTEGER, offsetof(SECKEYRawPrivateKey, u.dsa.privateValue) },
198
};
199
200
const SEC_ASN1Template SECKEY_DHPrivateKeyExportTemplate[] = {
201
    { SEC_ASN1_INTEGER, offsetof(SECKEYRawPrivateKey, u.dh.privateValue) },
202
    { SEC_ASN1_INTEGER, offsetof(SECKEYRawPrivateKey, u.dh.base) },
203
    { SEC_ASN1_INTEGER, offsetof(SECKEYRawPrivateKey, u.dh.prime) },
204
};
205
206
const SEC_ASN1Template SECKEY_PQPrivateKeyBothExportTemplate[] = {
207
    { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SECKEYRawPrivateKey) },
208
    { SEC_ASN1_OCTET_STRING, offsetof(SECKEYRawPrivateKey, u.pq.seed) },
209
    { SEC_ASN1_OCTET_STRING, offsetof(SECKEYRawPrivateKey, u.pq.privateValue) },
210
    { 0 }
211
};
212
213
const SEC_ASN1Template SECKEY_PQPrivateKeySeedExportTemplate[] = {
214
    { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 0, // NOLINT(misc-redundant-expression)
215
      offsetof(SECKEYRawPrivateKey, u.pq.seed),
216
      SEC_ASN1_SUB(SEC_OctetStringTemplate) },
217
    { 0 }
218
};
219
220
const SEC_ASN1Template SECKEY_PQPrivateKeyKeyExportTemplate[] = {
221
    { SEC_ASN1_OCTET_STRING, offsetof(SECKEYRawPrivateKey, u.pq.privateValue) },
222
    { 0 }
223
};
224
225
const SEC_ASN1Template SECKEY_ECPrivateKeyExportTemplate[] = {
226
    { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SECKEYRawPrivateKey) },
227
    { SEC_ASN1_INTEGER, offsetof(SECKEYRawPrivateKey, u.ec.version) },
228
    { SEC_ASN1_OCTET_STRING,
229
      offsetof(SECKEYRawPrivateKey, u.ec.privateValue) },
230
    /* This value will always be ignored. u.ec.curveOID will always be
231
     * overriden with the outer AlgorithmID.parameters. */
232
    { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED |
233
          SEC_ASN1_EXPLICIT | SEC_ASN1_CONTEXT_SPECIFIC |
234
          SEC_ASN1_XTRN | 0,
235
      offsetof(SECKEYRawPrivateKey, u.ec.curveOID),
236
      SEC_ASN1_SUB(SEC_ObjectIDTemplate) },
237
    /* The public value is optional per RFC, but required in NSS. We
238
     * can't do scalar mult on ECs to get a raw point with PK11 APIs. */
239
    { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED |
240
          SEC_ASN1_EXPLICIT | SEC_ASN1_CONTEXT_SPECIFIC |
241
          SEC_ASN1_XTRN | 1,
242
      offsetof(SECKEYRawPrivateKey, u.ec.publicValue),
243
      SEC_ASN1_SUB(SEC_BitStringTemplate) },
244
    { 0 }
245
};
246
247
/* The template operates a private key consisting only of private key. */
248
const SEC_ASN1Template SECKEY_ECRawPrivateKeyTemplate[] = {
249
    { SEC_ASN1_OCTET_STRING,
250
      offsetof(SECKEYRawPrivateKey, u.ec.privateValue) },
251
    { 0 }
252
};
253
254
const SEC_ASN1Template SECKEY_EncryptedPrivateKeyInfoTemplate[] = {
255
    { SEC_ASN1_SEQUENCE,
256
      0, NULL, sizeof(SECKEYEncryptedPrivateKeyInfo) },
257
    { SEC_ASN1_INLINE | SEC_ASN1_XTRN,
258
      offsetof(SECKEYEncryptedPrivateKeyInfo, algorithm),
259
      SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
260
    { SEC_ASN1_OCTET_STRING,
261
      offsetof(SECKEYEncryptedPrivateKeyInfo, encryptedData) },
262
    { 0 }
263
};
264
265
const SEC_ASN1Template SECKEY_PointerToEncryptedPrivateKeyInfoTemplate[] = {
266
    { SEC_ASN1_POINTER, 0, SECKEY_EncryptedPrivateKeyInfoTemplate }
267
};
268
269
SEC_ASN1_CHOOSER_IMPLEMENT(SECKEY_EncryptedPrivateKeyInfoTemplate)
270
SEC_ASN1_CHOOSER_IMPLEMENT(SECKEY_PointerToEncryptedPrivateKeyInfoTemplate)
271
SEC_ASN1_CHOOSER_IMPLEMENT(SECKEY_PrivateKeyInfoTemplate)
272
SEC_ASN1_CHOOSER_IMPLEMENT(SECKEY_PointerToPrivateKeyInfoTemplate)
273
274
/*
275
 * See bugzilla bug 125359
276
 * Since NSS (via PKCS#11) wants to handle big integers as unsigned ints,
277
 * all of the templates above that en/decode into integers must be converted
278
 * from ASN.1's signed integer type.  This is done by marking either the
279
 * source or destination (encoding or decoding, respectively) type as
280
 * siUnsignedInteger.
281
 */
282
283
static void
284
prepare_rsa_priv_key_export_for_asn1(SECKEYRawPrivateKey *key)
285
1.44k
{
286
1.44k
    key->u.rsa.modulus.type = siUnsignedInteger;
287
1.44k
    key->u.rsa.publicExponent.type = siUnsignedInteger;
288
1.44k
    key->u.rsa.privateExponent.type = siUnsignedInteger;
289
1.44k
    key->u.rsa.prime1.type = siUnsignedInteger;
290
1.44k
    key->u.rsa.prime2.type = siUnsignedInteger;
291
1.44k
    key->u.rsa.exponent1.type = siUnsignedInteger;
292
1.44k
    key->u.rsa.exponent2.type = siUnsignedInteger;
293
1.44k
    key->u.rsa.coefficient.type = siUnsignedInteger;
294
1.44k
}
295
296
static void
297
prepare_dsa_priv_key_export_for_asn1(SECKEYRawPrivateKey *key)
298
1.67k
{
299
1.67k
    key->u.dsa.privateValue.type = siUnsignedInteger;
300
1.67k
    key->u.dsa.params.prime.type = siUnsignedInteger;
301
1.67k
    key->u.dsa.params.subPrime.type = siUnsignedInteger;
302
1.67k
    key->u.dsa.params.base.type = siUnsignedInteger;
303
1.67k
}
304
305
static void
306
prepare_dh_priv_key_export_for_asn1(SECKEYRawPrivateKey *key)
307
0
{
308
0
    key->u.dh.privateValue.type = siUnsignedInteger;
309
0
    key->u.dh.prime.type = siUnsignedInteger;
310
0
    key->u.dh.base.type = siUnsignedInteger;
311
0
}
312
313
static void
314
prepare_ec_priv_key_export_for_asn1(SECKEYRawPrivateKey *key)
315
156
{
316
156
    key->u.ec.version.type = siUnsignedInteger;
317
156
    key->u.ec.curveOID.type = siUnsignedInteger;
318
156
    key->u.ec.privateValue.type = siUnsignedInteger;
319
156
    key->u.ec.publicValue.type = siUnsignedInteger;
320
156
}
321
322
/*
323
 * Finish off a private key we just imported: give it a CKA_ID, and, if it is
324
 * a token key, a matching public key on the token.
325
 *
326
 * publicValue is what the caller had to work with at import time, and may be
327
 * NULL. If it is, we ask the token to regenerate the public key from the
328
 * private key and take the public value from that.
329
 */
330
static SECStatus
331
pk11_SetIDAndPublicKey(SECKEYPrivateKey *privKey, const SECItem *publicValue,
332
                       PRBool isPerm)
333
1.79k
{
334
1.79k
    SECKEYPublicKey *pubKey = NULL;
335
1.79k
    SECItem *ck_id = NULL;
336
1.79k
    SECStatus rv = SECFailure;
337
338
1.79k
    if (publicValue == NULL) {
339
        /* if the token had to derive a public key object to answer this, it
340
         * belongs to pubKey and goes away with it. */
341
1.73k
        pubKey = SECKEY_ConvertToPublicKey(privKey);
342
1.73k
        if (pubKey == NULL) {
343
1.67k
            goto loser;
344
1.67k
        }
345
60
        publicValue = PK11_GetPublicValueFromPublicKey(pubKey);
346
60
        if (publicValue == NULL) {
347
0
            goto loser;
348
0
        }
349
60
        ck_id = PK11_MakeIDFromPubKey(publicValue);
350
60
        if (ck_id == NULL) {
351
0
            goto loser;
352
0
        }
353
60
        rv = PK11_WriteRawAttribute(PK11_TypePrivKey, privKey, CKA_ID, ck_id);
354
60
        if (rv != SECSuccess) {
355
0
            goto loser;
356
0
        }
357
60
    }
358
359
    /* if we are importing a token object, create the corresponding public
360
     * key, just as PK11_ImportEncryptedPrivateKeyInfoAndReturnKey does. */
361
128
    rv = SECSuccess;
362
128
    if (isPerm) {
363
2
        rv = SECKEY_SetPublicValue(privKey, publicValue);
364
2
    }
365
366
1.79k
loser:
367
1.79k
    if (pubKey) {
368
60
        SECKEY_DestroyPublicKey(pubKey);
369
60
    }
370
1.79k
    if (ck_id) {
371
60
        SECITEM_ZfreeItem(ck_id, PR_TRUE);
372
60
    }
373
1.79k
    return rv;
374
128
}
375
376
SECStatus
377
PK11_ImportDERPrivateKeyInfo(PK11SlotInfo *slot, SECItem *derPKI,
378
                             SECItem *nickname, const SECItem *publicValue, PRBool isPerm,
379
                             PRBool isPrivate, unsigned int keyUsage, void *wincx)
380
0
{
381
0
    return PK11_ImportDERPrivateKeyInfoAndReturnKey(slot, derPKI,
382
0
                                                    nickname, publicValue,
383
0
                                                    isPerm, isPrivate, keyUsage,
384
0
                                                    NULL, wincx);
385
0
}
386
387
SECKEYPrivateKeyInfo *
388
_PK11_DERPrivateKeyToPrivateKeyInfo(SECItem *derPKI)
389
5.60k
{
390
5.60k
    SECKEYPrivateKeyInfoV2 *pkiV2 = NULL;
391
5.60k
    PLArenaPool *temparena = NULL;
392
5.60k
    SECStatus rv = SECFailure;
393
5.60k
    unsigned long version = 0;
394
395
5.60k
    temparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
396
5.60k
    if (!temparena) {
397
0
        return NULL;
398
0
    }
399
400
5.60k
    pkiV2 = PORT_ArenaZNew(temparena, SECKEYPrivateKeyInfoV2);
401
5.60k
    if (!pkiV2) {
402
0
        goto loser;
403
0
    }
404
5.60k
    pkiV2->v1.arena = temparena;
405
406
5.60k
    rv = SEC_ASN1DecodeItem(pkiV2->v1.arena, pkiV2, seckey_PrivateKeyInfoV2Template,
407
5.60k
                            derPKI);
408
5.60k
    if (rv != SECSuccess) {
409
        /* If SEC_ASN1DecodeItem fails, we cannot assume anything about the
410
         * validity of the data in pki. The best we can do is free the arena
411
         * and return. */
412
2.07k
        goto loser;
413
2.07k
    }
414
    /* do some sanity checks on the decoded key */
415
3.53k
    if (SEC_ASN1DecodeInteger(&pkiV2->v1.version, &version) != SECSuccess) {
416
2
        goto loser; /* error already set */
417
2
    }
418
3.53k
    if ((version > 1) || ((version == 0) && (pkiV2->publicKey.data != NULL))) {
419
90
        PORT_SetError(SEC_ERROR_BAD_DER);
420
90
        goto loser;
421
90
    }
422
423
3.44k
    return &(pkiV2->v1);
424
425
2.16k
loser:
426
2.16k
    PORT_FreeArena(temparena, PR_TRUE);
427
2.16k
    return NULL;
428
3.53k
}
429
430
SECStatus
431
PK11_ImportDERPrivateKeyInfoAndReturnKey(PK11SlotInfo *slot, SECItem *derPKI,
432
                                         SECItem *nickname, const SECItem *publicValue,
433
                                         PRBool isPerm, PRBool isPrivate, unsigned int keyUsage,
434
                                         SECKEYPrivateKey **privk, void *wincx)
435
5.60k
{
436
5.60k
    SECKEYPrivateKeyInfo *pki = _PK11_DERPrivateKeyToPrivateKeyInfo(derPKI);
437
5.60k
    SECStatus rv = SECFailure;
438
439
5.60k
    if (pki == NULL) {
440
2.16k
        return rv;
441
2.16k
    }
442
3.44k
    if (pki->privateKey.data == NULL || pki->privateKey.len == 0) {
443
        /* If SEC_ASN1DecodeItems succeeds but SECKEYPrivateKeyInfo.privateKey
444
         * is a zero-length octet string, free the arena and return a failure
445
         * to avoid trying to zero the corresponding SECItem in
446
         * SECKEY_DestroyPrivateKeyInfo(). */
447
7
        PORT_FreeArena(pki->arena, PR_TRUE);
448
7
        PORT_SetError(SEC_ERROR_BAD_KEY);
449
7
        return SECFailure;
450
7
    }
451
452
    /* if we want to be able to read the public key for v2 decodes, we need
453
     * a new PK11_Import that takes the V2 struct, and the old entry can
454
     * create a V2 struct with a NULL public key */
455
3.43k
    rv = PK11_ImportPrivateKeyInfoAndReturnKey(slot, pki, nickname,
456
3.43k
                                               publicValue, isPerm, isPrivate,
457
3.43k
                                               keyUsage, privk, wincx);
458
459
    /* this zeroes the key and frees the arena */
460
3.43k
    SECKEY_DestroyPrivateKeyInfo(pki, PR_TRUE /*freeit*/);
461
3.43k
    return rv;
462
3.44k
}
463
464
SECStatus
465
PK11_ImportAndReturnPrivateKey(PK11SlotInfo *slot, SECKEYRawPrivateKey *lpk,
466
                               SECItem *nickname, const SECItem *publicValue, PRBool isPerm,
467
                               PRBool isPrivate, unsigned int keyUsage, SECKEYPrivateKey **privk,
468
                               void *wincx)
469
3.19k
{
470
3.19k
    CK_BBOOL cktrue = CK_TRUE;
471
3.19k
    CK_BBOOL ckfalse = CK_FALSE;
472
3.19k
    CK_OBJECT_CLASS keyClass = CKO_PRIVATE_KEY;
473
3.19k
    CK_KEY_TYPE keyType = CKK_RSA;
474
3.19k
    CK_OBJECT_HANDLE objectID;
475
3.19k
    CK_ATTRIBUTE theTemplate[20];
476
3.19k
    int templateCount = 0;
477
3.19k
    SECStatus rv = SECFailure;
478
3.19k
    CK_ATTRIBUTE *attrs;
479
3.19k
    CK_ATTRIBUTE *signedattr = NULL;
480
3.19k
    int signedcount = 0;
481
3.19k
    CK_ATTRIBUTE *ap;
482
3.19k
    SECItem *ck_id = NULL;
483
3.19k
    CK_ULONG paramSet;
484
3.19k
    SECKEYPrivateKey *privKey = NULL;
485
    /* the public value we end up using: either the caller's or one carried
486
     * in the PrivateKeyInfo. If we have neither, we leave this NULL and let
487
     * the token regenerate the public key once the private key is imported */
488
3.19k
    const SECItem *pubValue = publicValue;
489
490
3.19k
    attrs = theTemplate;
491
492
3.19k
    PK11_SETATTRS(attrs, CKA_CLASS, &keyClass, sizeof(keyClass));
493
3.19k
    attrs++;
494
3.19k
    PK11_SETATTRS(attrs, CKA_KEY_TYPE, &keyType, sizeof(keyType));
495
3.19k
    attrs++;
496
3.19k
    PK11_SETATTRS(attrs, CKA_TOKEN, isPerm ? &cktrue : &ckfalse,
497
3.19k
                  sizeof(CK_BBOOL));
498
3.19k
    attrs++;
499
3.19k
    PK11_SETATTRS(attrs, CKA_SENSITIVE, isPrivate ? &cktrue : &ckfalse,
500
3.19k
                  sizeof(CK_BBOOL));
501
3.19k
    attrs++;
502
3.19k
    PK11_SETATTRS(attrs, CKA_PRIVATE, isPrivate ? &cktrue : &ckfalse,
503
3.19k
                  sizeof(CK_BBOOL));
504
3.19k
    attrs++;
505
506
3.19k
    switch (lpk->keyType) {
507
1.38k
        case rsaKey:
508
1.38k
            keyType = CKK_RSA;
509
1.38k
            PK11_SETATTRS(attrs, CKA_UNWRAP, (keyUsage & KU_KEY_ENCIPHERMENT) ? &cktrue : &ckfalse,
510
1.38k
                          sizeof(CK_BBOOL));
511
1.38k
            attrs++;
512
1.38k
            PK11_SETATTRS(attrs, CKA_DECRYPT, (keyUsage & KU_DATA_ENCIPHERMENT) ? &cktrue : &ckfalse,
513
1.38k
                          sizeof(CK_BBOOL));
514
1.38k
            attrs++;
515
1.38k
            PK11_SETATTRS(attrs, CKA_SIGN, (keyUsage & KU_DIGITAL_SIGNATURE) ? &cktrue : &ckfalse,
516
1.38k
                          sizeof(CK_BBOOL));
517
1.38k
            attrs++;
518
1.38k
            PK11_SETATTRS(attrs, CKA_SIGN_RECOVER,
519
1.38k
                          (keyUsage & KU_DIGITAL_SIGNATURE) ? &cktrue
520
1.38k
                                                            : &ckfalse,
521
1.38k
                          sizeof(CK_BBOOL));
522
1.38k
            attrs++;
523
1.38k
            pubValue = &lpk->u.rsa.modulus;
524
1.38k
            ck_id = PK11_MakeIDFromPubKey(pubValue);
525
1.38k
            if (ck_id == NULL) {
526
0
                goto loser;
527
0
            }
528
1.38k
            PK11_SETATTRS(attrs, CKA_ID, ck_id->data, ck_id->len);
529
1.38k
            attrs++;
530
1.38k
            if (nickname) {
531
0
                PK11_SETATTRS(attrs, CKA_LABEL, nickname->data, nickname->len);
532
0
                attrs++;
533
0
            }
534
1.38k
            signedattr = attrs;
535
1.38k
            PK11_SETATTRS(attrs, CKA_MODULUS, lpk->u.rsa.modulus.data,
536
1.38k
                          lpk->u.rsa.modulus.len);
537
1.38k
            attrs++;
538
1.38k
            PK11_SETATTRS(attrs, CKA_PUBLIC_EXPONENT,
539
1.38k
                          lpk->u.rsa.publicExponent.data,
540
1.38k
                          lpk->u.rsa.publicExponent.len);
541
1.38k
            attrs++;
542
1.38k
            PK11_SETATTRS(attrs, CKA_PRIVATE_EXPONENT,
543
1.38k
                          lpk->u.rsa.privateExponent.data,
544
1.38k
                          lpk->u.rsa.privateExponent.len);
545
1.38k
            attrs++;
546
1.38k
            PK11_SETATTRS(attrs, CKA_PRIME_1,
547
1.38k
                          lpk->u.rsa.prime1.data,
548
1.38k
                          lpk->u.rsa.prime1.len);
549
1.38k
            attrs++;
550
1.38k
            PK11_SETATTRS(attrs, CKA_PRIME_2,
551
1.38k
                          lpk->u.rsa.prime2.data,
552
1.38k
                          lpk->u.rsa.prime2.len);
553
1.38k
            attrs++;
554
1.38k
            PK11_SETATTRS(attrs, CKA_EXPONENT_1,
555
1.38k
                          lpk->u.rsa.exponent1.data,
556
1.38k
                          lpk->u.rsa.exponent1.len);
557
1.38k
            attrs++;
558
1.38k
            PK11_SETATTRS(attrs, CKA_EXPONENT_2,
559
1.38k
                          lpk->u.rsa.exponent2.data,
560
1.38k
                          lpk->u.rsa.exponent2.len);
561
1.38k
            attrs++;
562
1.38k
            PK11_SETATTRS(attrs, CKA_COEFFICIENT,
563
1.38k
                          lpk->u.rsa.coefficient.data,
564
1.38k
                          lpk->u.rsa.coefficient.len);
565
1.38k
            attrs++;
566
1.38k
            break;
567
1.67k
        case dsaKey:
568
1.67k
            keyType = CKK_DSA;
569
1.67k
            PK11_SETATTRS(attrs, CKA_SIGN, &cktrue, sizeof(CK_BBOOL));
570
1.67k
            attrs++;
571
1.67k
            PK11_SETATTRS(attrs, CKA_SIGN_RECOVER, &ckfalse, sizeof(CK_BBOOL));
572
1.67k
            attrs++;
573
1.67k
            if (nickname) {
574
0
                PK11_SETATTRS(attrs, CKA_LABEL, nickname->data, nickname->len);
575
0
                attrs++;
576
0
            }
577
            /* To make our intenal PKCS #11 module work correctly with
578
             * our database, we need to pass in the public key value for
579
             * this dsa key. We have a netscape only CKA_ value to do this.
580
             * Only send it to internal slots */
581
1.67k
            if (pubValue != NULL) {
582
0
                if (PK11_IsInternal(slot)) {
583
0
                    PK11_SETATTRS(attrs, CKA_NSS_DB,
584
0
                                  pubValue->data, pubValue->len);
585
0
                    attrs++;
586
0
                }
587
0
                ck_id = PK11_MakeIDFromPubKey(pubValue);
588
0
                if (ck_id == NULL) {
589
0
                    goto loser;
590
0
                }
591
0
                PK11_SETATTRS(attrs, CKA_ID, ck_id->data, ck_id->len);
592
0
                attrs++;
593
0
            }
594
1.67k
            signedattr = attrs;
595
1.67k
            PK11_SETATTRS(attrs, CKA_PRIME, lpk->u.dsa.params.prime.data,
596
1.67k
                          lpk->u.dsa.params.prime.len);
597
1.67k
            attrs++;
598
1.67k
            PK11_SETATTRS(attrs, CKA_SUBPRIME, lpk->u.dsa.params.subPrime.data,
599
1.67k
                          lpk->u.dsa.params.subPrime.len);
600
1.67k
            attrs++;
601
1.67k
            PK11_SETATTRS(attrs, CKA_BASE, lpk->u.dsa.params.base.data,
602
1.67k
                          lpk->u.dsa.params.base.len);
603
1.67k
            attrs++;
604
1.67k
            PK11_SETATTRS(attrs, CKA_VALUE, lpk->u.dsa.privateValue.data,
605
1.67k
                          lpk->u.dsa.privateValue.len);
606
1.67k
            attrs++;
607
1.67k
            break;
608
0
        case dhKey:
609
0
            keyType = CKK_DH;
610
0
            PK11_SETATTRS(attrs, CKA_DERIVE, &cktrue, sizeof(CK_BBOOL));
611
0
            attrs++;
612
0
            if (nickname) {
613
0
                PK11_SETATTRS(attrs, CKA_LABEL, nickname->data, nickname->len);
614
0
                attrs++;
615
0
            }
616
            /* To make our intenal PKCS #11 module work correctly with
617
             * our database, we need to pass in the public key value for
618
             * this dh key. We have a netscape only CKA_ value to do this.
619
             * Only send it to internal slots */
620
0
            if (pubValue != NULL) {
621
0
                if (PK11_IsInternal(slot)) {
622
0
                    PK11_SETATTRS(attrs, CKA_NSS_DB,
623
0
                                  pubValue->data, pubValue->len);
624
0
                    attrs++;
625
0
                }
626
0
                ck_id = PK11_MakeIDFromPubKey(pubValue);
627
0
                if (ck_id == NULL) {
628
0
                    goto loser;
629
0
                }
630
0
                PK11_SETATTRS(attrs, CKA_ID, ck_id->data, ck_id->len);
631
0
                attrs++;
632
0
            }
633
0
            signedattr = attrs;
634
0
            PK11_SETATTRS(attrs, CKA_PRIME, lpk->u.dh.prime.data,
635
0
                          lpk->u.dh.prime.len);
636
0
            attrs++;
637
0
            PK11_SETATTRS(attrs, CKA_BASE, lpk->u.dh.base.data,
638
0
                          lpk->u.dh.base.len);
639
0
            attrs++;
640
0
            PK11_SETATTRS(attrs, CKA_VALUE, lpk->u.dh.privateValue.data,
641
0
                          lpk->u.dh.privateValue.len);
642
0
            attrs++;
643
0
            break;
644
85
        case ecKey:
645
85
            keyType = CKK_EC;
646
85
            PK11_SETATTRS(attrs, CKA_SIGN, (keyUsage & KU_DIGITAL_SIGNATURE) ? &cktrue : &ckfalse,
647
85
                          sizeof(CK_BBOOL));
648
85
            attrs++;
649
85
            PK11_SETATTRS(attrs, CKA_SIGN_RECOVER, &ckfalse,
650
85
                          sizeof(CK_BBOOL));
651
85
            attrs++;
652
85
            PK11_SETATTRS(attrs, CKA_DERIVE, (keyUsage & KU_KEY_AGREEMENT) ? &cktrue : &ckfalse,
653
85
                          sizeof(CK_BBOOL));
654
85
            attrs++;
655
85
            if (nickname) {
656
0
                PK11_SETATTRS(attrs, CKA_LABEL, nickname->data, nickname->len);
657
0
                attrs++;
658
0
            }
659
            /* the public value is optional in an ECPrivateKey. Without it we
660
             * have to wait until the key is on the token and let the token
661
             * regenerate the public key for us (below). */
662
85
            if (lpk->u.ec.publicValue.len != 0) {
663
47
                pubValue = &lpk->u.ec.publicValue;
664
47
            }
665
85
            if (pubValue != NULL) {
666
47
                if (PK11_IsInternal(slot)) {
667
47
                    PK11_SETATTRS(attrs, CKA_NSS_DB,
668
47
                                  pubValue->data, pubValue->len);
669
47
                    attrs++;
670
47
                }
671
47
                ck_id = PK11_MakeIDFromPubKey(pubValue);
672
47
                if (ck_id == NULL) {
673
0
                    goto loser;
674
0
                }
675
47
                PK11_SETATTRS(attrs, CKA_ID, ck_id->data, ck_id->len);
676
47
                attrs++;
677
47
                PK11_SETATTRS(attrs, CKA_EC_POINT, pubValue->data,
678
47
                              pubValue->len);
679
47
                attrs++;
680
47
            }
681
            /* No signed attrs for EC */
682
            /* curveOID always is a copy of AlgorithmID.parameters. */
683
85
            PK11_SETATTRS(attrs, CKA_EC_PARAMS, lpk->u.ec.curveOID.data,
684
85
                          lpk->u.ec.curveOID.len);
685
85
            attrs++;
686
85
            PK11_SETATTRS(attrs, CKA_VALUE, lpk->u.ec.privateValue.data,
687
85
                          lpk->u.ec.privateValue.len);
688
85
            attrs++;
689
85
            break;
690
37
        case edKey:
691
37
            keyType = CKK_EC_EDWARDS;
692
37
            PK11_SETATTRS(attrs, CKA_SIGN, &cktrue, sizeof(CK_BBOOL));
693
37
            attrs++;
694
37
            if (nickname) {
695
0
                PK11_SETATTRS(attrs, CKA_LABEL, nickname->data, nickname->len);
696
0
                attrs++;
697
0
            }
698
            /* a CurvePrivateKey carries no public value, so unless the caller
699
             * handed us one we have to let the token regenerate the public
700
             * key for us (below). */
701
37
            if (pubValue != NULL) {
702
0
                ck_id = PK11_MakeIDFromPubKey(pubValue);
703
0
                if (ck_id == NULL) {
704
0
                    goto loser;
705
0
                }
706
0
                PK11_SETATTRS(attrs, CKA_ID, ck_id->data, ck_id->len);
707
0
                attrs++;
708
0
            }
709
710
            /* No signed attrs for EC */
711
            /* curveOID always is a copy of AlgorithmID.parameters. */
712
37
            PK11_SETATTRS(attrs, CKA_EC_PARAMS, lpk->u.ec.curveOID.data,
713
37
                          lpk->u.ec.curveOID.len);
714
37
            attrs++;
715
37
            PK11_SETATTRS(attrs, CKA_VALUE, lpk->u.ec.privateValue.data,
716
37
                          lpk->u.ec.privateValue.len);
717
37
            attrs++;
718
37
            break;
719
16
        case ecMontKey:
720
16
            keyType = CKK_EC_MONTGOMERY;
721
722
16
            PK11_SETATTRS(attrs, CKA_DERIVE, &cktrue, sizeof(CK_BBOOL));
723
16
            attrs++;
724
725
16
            if (nickname) {
726
0
                PK11_SETATTRS(attrs, CKA_LABEL, nickname->data, nickname->len);
727
0
                attrs++;
728
0
            }
729
            /* a CurvePrivateKey carries no public value, so unless the caller
730
             * handed us one we have to let the token regenerate the public
731
             * key for us (below). */
732
16
            if (pubValue != NULL) {
733
0
                ck_id = PK11_MakeIDFromPubKey(pubValue);
734
0
                if (ck_id == NULL) {
735
0
                    goto loser;
736
0
                }
737
0
                PK11_SETATTRS(attrs, CKA_ID, ck_id->data, ck_id->len);
738
0
                attrs++;
739
0
            }
740
741
            /* No signed attrs for EC */
742
            /* curveOID always is a copy of AlgorithmID.parameters. */
743
16
            PK11_SETATTRS(attrs, CKA_EC_PARAMS, lpk->u.ec.curveOID.data,
744
16
                          lpk->u.ec.curveOID.len);
745
16
            attrs++;
746
747
16
            PK11_SETATTRS(attrs, CKA_VALUE, lpk->u.ec.privateValue.data,
748
16
                          lpk->u.ec.privateValue.len);
749
16
            attrs++;
750
16
            break;
751
0
        case mldsaKey:
752
0
            keyType = CKK_ML_DSA;
753
            /* we need at least one of these to import into PKCS #11.
754
             * if we have only one, it may still fail, but that is up
755
             * to the token */
756
0
            if ((lpk->u.mldsa.seed.len == 0) &&
757
0
                (lpk->u.mldsa.privateValue.len == 0)) {
758
0
                PORT_SetError(SEC_ERROR_BAD_KEY);
759
0
                goto loser;
760
0
            }
761
0
            PK11_SETATTRS(attrs, CKA_SIGN, &cktrue, sizeof(CK_BBOOL));
762
0
            attrs++;
763
0
            PK11_SETATTRS(attrs, CKA_SIGN_RECOVER, &ckfalse, sizeof(CK_BBOOL));
764
0
            attrs++;
765
            /* the public value is optional in an ML-DSA PrivateKey. Without
766
             * it we have to wait until the key is on the token and let the
767
             * token regenerate the public key for us (below). CKA_NSS_DB is
768
             * an artifact of the old dbm database, which never supported
769
             * ML-DSA, so we don't set it here. */
770
0
            if (pubValue != NULL) {
771
0
                ck_id = PK11_MakeIDFromPubKey(pubValue);
772
0
                if (ck_id == NULL) {
773
0
                    goto loser;
774
0
                }
775
0
                PK11_SETATTRS(attrs, CKA_ID, ck_id->data, ck_id->len);
776
0
                attrs++;
777
0
            }
778
0
            if (nickname) {
779
0
                PK11_SETATTRS(attrs, CKA_LABEL, nickname->data, nickname->len);
780
0
                attrs++;
781
0
            }
782
0
            paramSet = SECKEY_GetMLDSAPkcs11ParamSetByOidTag(lpk->u.mldsa.params);
783
0
            PK11_SETATTRS(attrs, CKA_PARAMETER_SET, (unsigned char *)&paramSet,
784
0
                          sizeof(CK_ML_DSA_PARAMETER_SET_TYPE));
785
0
            attrs++;
786
0
            if (lpk->u.mldsa.seed.len) {
787
0
                PK11_SETATTRS(attrs, CKA_SEED, lpk->u.mldsa.seed.data,
788
0
                              lpk->u.mldsa.seed.len);
789
0
                attrs++;
790
0
            }
791
0
            if (lpk->u.mldsa.privateValue.len) {
792
0
                PK11_SETATTRS(attrs, CKA_VALUE, lpk->u.mldsa.privateValue.data,
793
0
                              lpk->u.mldsa.privateValue.len);
794
0
                attrs++;
795
0
            }
796
0
            break;
797
0
        case kyberKey:
798
0
            keyType = CKK_ML_KEM;
799
            /* we need at least one of these to import into PKCS #11.
800
             * if we have only one, it may still fail, but that is up
801
             * to the token */
802
0
            if ((lpk->u.mlkem.seed.len == 0) &&
803
0
                (lpk->u.mlkem.privateValue.len == 0)) {
804
0
                PORT_SetError(SEC_ERROR_BAD_KEY);
805
0
                goto loser;
806
0
            }
807
0
            PK11_SETATTRS(attrs, CKA_DECAPSULATE, &cktrue, sizeof(CK_BBOOL));
808
0
            attrs++;
809
            /* the public value is optional in an ML-KEM PrivateKey. Without
810
             * it we have to wait until the key is on the token and let the
811
             * token regenerate the public key for us (below). CKA_NSS_DB is
812
             * an artifact of the old dbm database, which never supported
813
             * ML-KEM, so we don't set it here. */
814
0
            if (pubValue != NULL) {
815
0
                ck_id = PK11_MakeIDFromPubKey(pubValue);
816
0
                if (ck_id == NULL) {
817
0
                    goto loser;
818
0
                }
819
0
                PK11_SETATTRS(attrs, CKA_ID, ck_id->data, ck_id->len);
820
0
                attrs++;
821
0
            }
822
0
            if (nickname) {
823
0
                PK11_SETATTRS(attrs, CKA_LABEL, nickname->data, nickname->len);
824
0
                attrs++;
825
0
            }
826
0
            paramSet = seckey_GetMLKEMPkcs11ParamsByKyberParams(
827
0
                seckey_GetKyberParamsByOidTag(lpk->u.mlkem.params));
828
0
            PK11_SETATTRS(attrs, CKA_PARAMETER_SET, (unsigned char *)&paramSet,
829
0
                          sizeof(CK_ML_KEM_PARAMETER_SET_TYPE));
830
0
            attrs++;
831
0
            if (lpk->u.mlkem.seed.len) {
832
0
                PK11_SETATTRS(attrs, CKA_SEED, lpk->u.mlkem.seed.data,
833
0
                              lpk->u.mlkem.seed.len);
834
0
                attrs++;
835
0
            }
836
0
            if (lpk->u.mlkem.privateValue.len) {
837
0
                PK11_SETATTRS(attrs, CKA_VALUE, lpk->u.mlkem.privateValue.data,
838
0
                              lpk->u.mlkem.privateValue.len);
839
0
                attrs++;
840
0
            }
841
0
            break;
842
0
        default:
843
0
            PORT_SetError(SEC_ERROR_BAD_KEY);
844
0
            goto loser;
845
3.19k
    }
846
3.19k
    templateCount = attrs - theTemplate;
847
3.19k
    PORT_Assert(templateCount <= sizeof(theTemplate) / sizeof(CK_ATTRIBUTE));
848
    /* we used to assert unless the key didn't need signedattrs, but that's
849
     * now true of almost all modern keys, so now if the key has signedattrs
850
     * the just need to set the value */
851
3.19k
    if (signedattr) {
852
3.05k
        signedcount = attrs - signedattr;
853
20.8k
        for (ap = signedattr; signedcount; ap++, signedcount--) {
854
17.7k
            pk11_SignedToUnsigned(ap);
855
17.7k
        }
856
3.05k
    }
857
858
3.19k
    rv = PK11_CreateNewObject(slot, CK_INVALID_HANDLE,
859
3.19k
                              theTemplate, templateCount, isPerm, &objectID);
860
3.19k
    if (rv != SECSuccess) {
861
1.39k
        goto loser;
862
1.39k
    }
863
864
1.79k
    privKey = pk11_MakePrivKey(slot, lpk->keyType, !isPerm, objectID, wincx);
865
1.79k
    if (privKey == NULL) {
866
0
        rv = SECFailure;
867
0
        goto loser;
868
0
    }
869
870
    /* Best effort. A token needn't be able to regenerate a public key from a
871
     * private one (softoken can only do it for ML-DSA if it has the seed),
872
     * and it needn't support permanent public keys either. Without a CKA_ID
873
     * the key can't be found again, but it is still usable through the
874
     * handle we return here. */
875
1.79k
    (void)pk11_SetIDAndPublicKey(privKey, pubValue, isPerm);
876
877
1.79k
    if (privk != NULL) {
878
1.79k
        *privk = privKey;
879
1.79k
        privKey = NULL;
880
1.79k
    }
881
3.19k
loser:
882
3.19k
    if (privKey) {
883
0
        SECKEY_DestroyPrivateKey(privKey);
884
0
    }
885
3.19k
    if (ck_id) {
886
1.43k
        SECITEM_ZfreeItem(ck_id, PR_TRUE);
887
1.43k
    }
888
3.19k
    return rv;
889
1.79k
}
890
891
SECStatus
892
PK11_ImportPrivateKeyInfoAndReturnKey(PK11SlotInfo *slot,
893
                                      SECKEYPrivateKeyInfo *pki, SECItem *nickname, const SECItem *publicValue,
894
                                      PRBool isPerm, PRBool isPrivate, unsigned int keyUsage,
895
                                      SECKEYPrivateKey **privk, void *wincx)
896
3.43k
{
897
3.43k
    SECStatus rv = SECFailure;
898
3.43k
    SECKEYRawPrivateKey *lpk = NULL;
899
3.43k
    const SEC_ASN1Template *keyTemplate, *paramTemplate;
900
3.43k
    void *paramDest = NULL;
901
3.43k
    PLArenaPool *arena = NULL;
902
3.43k
    SECOidTag algTag;
903
904
3.43k
    arena = PORT_NewArena(2048);
905
3.43k
    if (!arena) {
906
0
        return SECFailure;
907
0
    }
908
909
    /* need to change this to use RSA/DSA keys */
910
3.43k
    lpk = (SECKEYRawPrivateKey *)PORT_ArenaZAlloc(arena,
911
3.43k
                                                  sizeof(SECKEYRawPrivateKey));
912
3.43k
    if (lpk == NULL) {
913
0
        goto loser;
914
0
    }
915
3.43k
    lpk->arena = arena;
916
917
3.43k
    algTag = SECOID_GetAlgorithmTag(&pki->algorithm);
918
3.43k
    switch (algTag) {
919
1.41k
        case SEC_OID_PKCS1_RSA_ENCRYPTION:
920
1.42k
        case SEC_OID_PKCS1_RSA_PSS_SIGNATURE:
921
            /* An id-RSASSA-PSS PrivateKeyInfo wraps an ordinary RSAPrivateKey,
922
             * identical to rsaEncryption; only the algorithm OID (and optional
923
             * PSS parameters, which don't affect the raw key) differ. NSS
924
             * represents RSA-PSS keys as rsaKey/CKK_RSA, so decode it as RSA. */
925
1.42k
            prepare_rsa_priv_key_export_for_asn1(lpk);
926
1.42k
            keyTemplate = SECKEY_RSAPrivateKeyExportTemplate;
927
1.42k
            paramTemplate = NULL;
928
1.42k
            paramDest = NULL;
929
1.42k
            lpk->keyType = rsaKey;
930
1.42k
            break;
931
1.67k
        case SEC_OID_ANSIX9_DSA_SIGNATURE:
932
1.67k
            prepare_dsa_priv_key_export_for_asn1(lpk);
933
1.67k
            keyTemplate = SECKEY_DSAPrivateKeyExportTemplate;
934
1.67k
            paramTemplate = SECKEY_PQGParamsTemplate;
935
1.67k
            paramDest = &(lpk->u.dsa.params);
936
1.67k
            lpk->keyType = dsaKey;
937
1.67k
            break;
938
1
        case SEC_OID_X942_DIFFIE_HELMAN_KEY:
939
1
            if (!publicValue) {
940
1
                goto loser;
941
1
            }
942
0
            prepare_dh_priv_key_export_for_asn1(lpk);
943
0
            keyTemplate = SECKEY_DHPrivateKeyExportTemplate;
944
0
            paramTemplate = NULL;
945
0
            paramDest = NULL;
946
0
            lpk->keyType = dhKey;
947
0
            break;
948
101
        case SEC_OID_ED25519_PUBLIC_KEY:
949
101
            keyTemplate = SECKEY_ECRawPrivateKeyTemplate;
950
101
            paramTemplate = NULL;
951
101
            paramDest = NULL;
952
101
            lpk->keyType = edKey;
953
101
            break;
954
37
        case SEC_OID_X25519:
955
37
            keyTemplate = SECKEY_ECRawPrivateKeyTemplate;
956
37
            paramTemplate = NULL;
957
37
            paramDest = NULL;
958
37
            lpk->keyType = ecMontKey;
959
37
            break;
960
121
        case SEC_OID_ANSIX962_EC_PUBLIC_KEY:
961
121
            prepare_ec_priv_key_export_for_asn1(lpk);
962
121
            keyTemplate = SECKEY_ECPrivateKeyExportTemplate;
963
121
            paramTemplate = NULL;
964
121
            paramDest = NULL;
965
121
            lpk->keyType = ecKey;
966
121
            break;
967
0
        case SEC_OID_ML_DSA_44:
968
0
        case SEC_OID_ML_DSA_65:
969
0
        case SEC_OID_ML_DSA_87:
970
0
            lpk->keyType = mldsaKey;
971
0
            lpk->u.mldsa.params = algTag;
972
0
            goto handlePQKey;
973
0
        case SEC_OID_ML_KEM_512:
974
0
        case SEC_OID_ML_KEM_768:
975
0
        case SEC_OID_ML_KEM_1024:
976
0
            lpk->keyType = kyberKey;
977
0
            lpk->u.mlkem.params = algTag;
978
0
        handlePQKey:
979
0
            if (pki->privateKey.data == NULL || pki->privateKey.len == 0) {
980
0
                PORT_SetError(SEC_ERROR_BAD_KEY);
981
0
                goto loser;
982
0
            }
983
            /* choice */
984
0
            switch (pki->privateKey.data[0]) {
985
0
                case SEC_ASN1_CONTEXT_SPECIFIC | 0:
986
0
                    keyTemplate = SECKEY_PQPrivateKeySeedExportTemplate;
987
0
                    break;
988
0
                case SEC_ASN1_OCTET_STRING:
989
0
                    keyTemplate = SECKEY_PQPrivateKeyKeyExportTemplate;
990
0
                    break;
991
0
                case SEC_ASN1_CONSTRUCTED | SEC_ASN1_SEQUENCE:
992
0
                    keyTemplate = SECKEY_PQPrivateKeyBothExportTemplate;
993
0
                    break;
994
0
                default:
995
0
                    keyTemplate = NULL;
996
0
                    PORT_SetError(SEC_ERROR_BAD_DER);
997
0
                    break;
998
0
            }
999
0
            paramTemplate = NULL;
1000
0
            paramDest = NULL;
1001
0
            break;
1002
73
        default:
1003
73
            keyTemplate = NULL;
1004
73
            paramTemplate = NULL;
1005
73
            paramDest = NULL;
1006
73
            break;
1007
3.43k
    }
1008
1009
3.43k
    if (!keyTemplate) {
1010
73
        goto loser;
1011
73
    }
1012
1013
    /* decode the private key and any algorithm parameters */
1014
3.36k
    rv = SEC_QuickDERDecodeItem(arena, lpk, keyTemplate, &pki->privateKey);
1015
3.36k
    if (rv != SECSuccess) {
1016
160
        goto loser;
1017
160
    }
1018
1019
3.20k
    if (lpk->keyType == ecKey) {
1020
        /* Convert length in bits to length in bytes. */
1021
85
        lpk->u.ec.publicValue.len >>= 3;
1022
1023
        /* Always override curveOID, we're ignoring any given value. */
1024
85
        rv = SECITEM_CopyItem(arena, &lpk->u.ec.curveOID,
1025
85
                              &pki->algorithm.parameters);
1026
85
        if (rv != SECSuccess) {
1027
0
            goto loser;
1028
0
        }
1029
85
    }
1030
1031
3.20k
    if (lpk->keyType == edKey || lpk->keyType == ecMontKey) {
1032
        /* SECKEY_ECRawPrivateKeyTemplate (used for both key types) does not reference
1033
           publicKey, curveOID, ec verion. */
1034
54
        if (pki->algorithm.parameters.len != 0) {
1035
            /* Currently supporting only (Pure)Ed25519/X25519 .*/
1036
1
            PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG);
1037
1
            goto loser;
1038
1
        }
1039
1040
53
        SECOidData *oid25519 = SECOID_FindOIDByTag(SECOID_GetAlgorithmTag(&pki->algorithm));
1041
53
        if (!oid25519) {
1042
0
            goto loser;
1043
0
        }
1044
1045
53
        if (!SECITEM_AllocItem(arena, &lpk->u.ec.curveOID, oid25519->oid.len + 2)) {
1046
0
            goto loser;
1047
0
        }
1048
53
        lpk->u.ec.curveOID.data[0] = SEC_ASN1_OBJECT_ID;
1049
53
        lpk->u.ec.curveOID.data[1] = oid25519->oid.len;
1050
53
        PORT_Memcpy(lpk->u.ec.curveOID.data + 2, oid25519->oid.data, oid25519->oid.len);
1051
53
    }
1052
1053
3.20k
    if (paramDest && paramTemplate) {
1054
1.67k
        rv = SEC_ASN1DecodeItem(arena, paramDest, paramTemplate,
1055
1.67k
                                &(pki->algorithm.parameters));
1056
1.67k
        if (rv != SECSuccess) {
1057
4
            goto loser;
1058
4
        }
1059
1.67k
    }
1060
1061
3.19k
    rv = PK11_ImportAndReturnPrivateKey(slot, lpk, nickname, publicValue, isPerm,
1062
3.19k
                                        isPrivate, keyUsage, privk, wincx);
1063
3.19k
    if (rv != SECSuccess) {
1064
1.39k
        goto loser;
1065
1.39k
    }
1066
1.79k
    PORT_FreeArena(arena, PR_TRUE);
1067
1.79k
    return SECSuccess;
1068
1069
1.63k
loser:
1070
1.63k
    PORT_FreeArena(arena, PR_TRUE);
1071
1.63k
    return SECFailure;
1072
3.19k
}
1073
1074
SECStatus
1075
PK11_ImportPrivateKeyInfo(PK11SlotInfo *slot, SECKEYPrivateKeyInfo *pki,
1076
                          SECItem *nickname, const SECItem *publicValue, PRBool isPerm,
1077
                          PRBool isPrivate, unsigned int keyUsage, void *wincx)
1078
0
{
1079
0
    return PK11_ImportPrivateKeyInfoAndReturnKey(slot, pki, nickname,
1080
0
                                                 publicValue, isPerm, isPrivate, keyUsage, NULL, wincx);
1081
0
}
1082
1083
SECItem *
1084
PK11_ExportDERPrivateKeyInfo(SECKEYPrivateKey *pk, void *wincx)
1085
1.78k
{
1086
1.78k
    SECKEYPrivateKeyInfo *pki = PK11_ExportPrivKeyInfo(pk, wincx);
1087
1.78k
    SECItem *derPKI;
1088
1089
1.78k
    if (!pki) {
1090
1.67k
        return NULL;
1091
1.67k
    }
1092
108
    derPKI = SEC_ASN1EncodeItem(NULL, NULL, pki,
1093
108
                                SECKEY_PrivateKeyInfoTemplate);
1094
108
    SECKEY_DestroyPrivateKeyInfo(pki, PR_TRUE);
1095
108
    return derPKI;
1096
1.78k
}
1097
1098
static PRBool
1099
ReadAttribute(SECKEYPrivateKey *key, CK_ATTRIBUTE_TYPE type,
1100
              PLArenaPool *arena, SECItem *output)
1101
332
{
1102
332
    SECStatus rv = PK11_ReadAttribute(key->pkcs11Slot, key->pkcs11ID, type,
1103
332
                                      arena, output);
1104
332
    return rv == SECSuccess;
1105
332
}
1106
1107
/*
1108
 * The caller is responsible for freeing the return value by passing it to
1109
 * SECKEY_DestroyPrivateKeyInfo(..., PR_TRUE).
1110
 */
1111
SECKEYPrivateKeyInfo *
1112
PK11_ExportPrivKeyInfo(SECKEYPrivateKey *pk, void *wincx)
1113
1.78k
{
1114
    /* PrivateKeyInfo version (always zero) */
1115
1.78k
    const unsigned char pkiVersion = 0;
1116
    /* RSAPrivateKey version (always zero) */
1117
1.78k
    const unsigned char rsaVersion = 0;
1118
    /* ECPrivateKey version (always one) */
1119
1.78k
    const unsigned char ecVersion = 1;
1120
1.78k
    PLArenaPool *arena = NULL;
1121
1.78k
    SECKEYRawPrivateKey rawKey;
1122
1.78k
    SECKEYPrivateKeyInfo *pki;
1123
1.78k
    SECItem *encoded;
1124
1.78k
    const SEC_ASN1Template *keyTemplate;
1125
1.78k
    SECStatus rv;
1126
1127
1.78k
    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
1128
1.78k
    if (!arena) {
1129
0
        goto loser;
1130
0
    }
1131
1.78k
    memset(&rawKey, 0, sizeof(rawKey));
1132
1.78k
    rawKey.keyType = pk->keyType;
1133
1.78k
    pki = PORT_ArenaZNew(arena, SECKEYPrivateKeyInfo);
1134
1.78k
    if (!pki) {
1135
0
        goto loser;
1136
0
    }
1137
1138
1.78k
    switch (pk->keyType) {
1139
22
        case rsaKey: {
1140
22
            rawKey.u.rsa.version.type = siUnsignedInteger;
1141
22
            rawKey.u.rsa.version.data = (unsigned char *)PORT_ArenaAlloc(arena, 1);
1142
22
            if (!rawKey.u.rsa.version.data) {
1143
0
                goto loser;
1144
0
            }
1145
1146
22
            rawKey.u.rsa.version.data[0] = rsaVersion;
1147
22
            rawKey.u.rsa.version.len = 1;
1148
1149
            /* Read the component attributes of the private key */
1150
22
            prepare_rsa_priv_key_export_for_asn1(&rawKey);
1151
22
            if (!ReadAttribute(pk, CKA_MODULUS, arena, &rawKey.u.rsa.modulus) ||
1152
22
                !ReadAttribute(pk, CKA_PUBLIC_EXPONENT, arena,
1153
22
                               &rawKey.u.rsa.publicExponent) ||
1154
22
                !ReadAttribute(pk, CKA_PRIVATE_EXPONENT, arena,
1155
22
                               &rawKey.u.rsa.privateExponent) ||
1156
22
                !ReadAttribute(pk, CKA_PRIME_1, arena, &rawKey.u.rsa.prime1) ||
1157
22
                !ReadAttribute(pk, CKA_PRIME_2, arena, &rawKey.u.rsa.prime2) ||
1158
22
                !ReadAttribute(pk, CKA_EXPONENT_1, arena,
1159
22
                               &rawKey.u.rsa.exponent1) ||
1160
22
                !ReadAttribute(pk, CKA_EXPONENT_2, arena,
1161
22
                               &rawKey.u.rsa.exponent2) ||
1162
22
                !ReadAttribute(pk, CKA_COEFFICIENT, arena,
1163
22
                               &rawKey.u.rsa.coefficient)) {
1164
0
                goto loser;
1165
0
            }
1166
1167
22
            keyTemplate = SECKEY_RSAPrivateKeyExportTemplate;
1168
1169
22
            rv = SECOID_SetAlgorithmID(arena, &pki->algorithm, SEC_OID_PKCS1_RSA_ENCRYPTION, NULL);
1170
22
            if (rv != SECSuccess) {
1171
0
                goto loser;
1172
0
            }
1173
1174
22
        } break;
1175
35
        case ecKey: {
1176
35
            rawKey.u.ec.version.type = siUnsignedInteger;
1177
35
            rawKey.u.ec.version.data = (unsigned char *)PORT_ArenaAlloc(arena, 1);
1178
35
            if (!rawKey.u.ec.version.data) {
1179
0
                goto loser;
1180
0
            }
1181
35
            rawKey.u.ec.version.data[0] = ecVersion;
1182
35
            rawKey.u.ec.version.len = 1;
1183
1184
35
            SECItem curveOID;
1185
            /* Read the component attributes of the private key */
1186
35
            prepare_ec_priv_key_export_for_asn1(&rawKey);
1187
35
            if (!ReadAttribute(pk, CKA_VALUE, arena,
1188
35
                               &rawKey.u.ec.privateValue) ||
1189
35
                !ReadAttribute(pk, CKA_EC_PARAMS, arena, &curveOID)) {
1190
0
                goto loser;
1191
0
            }
1192
35
            if (!ReadAttribute(pk, CKA_EC_POINT, arena,
1193
35
                               &rawKey.u.ec.publicValue)) {
1194
7
                SECKEYPublicKey *pubk = SECKEY_ConvertToPublicKey(pk);
1195
7
                if (pubk == NULL)
1196
0
                    goto loser;
1197
7
                rv = SECITEM_CopyItem(arena, &rawKey.u.ec.publicValue, &pubk->u.ec.publicValue);
1198
7
                SECKEY_DestroyPublicKey(pubk);
1199
7
                if (rv != SECSuccess) {
1200
0
                    goto loser;
1201
0
                }
1202
7
            }
1203
1204
35
            keyTemplate = SECKEY_ECPrivateKeyExportTemplate;
1205
            /* Convert length in bytes to length in bits. */
1206
35
            rawKey.u.ec.publicValue.len <<= 3;
1207
1208
35
            rv = SECOID_SetAlgorithmID(arena, &pki->algorithm, SEC_OID_ANSIX962_EC_PUBLIC_KEY, &curveOID);
1209
35
            if (rv != SECSuccess) {
1210
0
                goto loser;
1211
0
            }
1212
1213
35
        } break;
1214
36
        case edKey: {
1215
36
            if (!ReadAttribute(pk, CKA_VALUE, arena,
1216
36
                               &rawKey.u.ec.privateValue)) {
1217
0
                goto loser;
1218
0
            }
1219
1220
36
            keyTemplate = SECKEY_ECRawPrivateKeyTemplate;
1221
            /* Currently, Ed25519 does not support any parameter.  */
1222
36
            rv = SECOID_SetAlgorithmID(arena, &pki->algorithm, SEC_OID_ED25519_PUBLIC_KEY, NULL);
1223
36
            if (rv != SECSuccess) {
1224
0
                goto loser;
1225
0
            }
1226
36
        } break;
1227
36
        case ecMontKey: {
1228
15
            if (!ReadAttribute(pk, CKA_VALUE, arena,
1229
15
                               &rawKey.u.ec.privateValue)) {
1230
0
                goto loser;
1231
0
            }
1232
1233
15
            keyTemplate = SECKEY_ECRawPrivateKeyTemplate;
1234
            /* Currently, X25519 does not support any parameter.  */
1235
15
            rv = SECOID_SetAlgorithmID(arena, &pki->algorithm, SEC_OID_X25519, NULL);
1236
15
            if (rv != SECSuccess) {
1237
0
                goto loser;
1238
0
            }
1239
15
        } break;
1240
1.67k
        default: {
1241
1.67k
            PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
1242
1.67k
            goto loser;
1243
15
        }
1244
1.78k
    }
1245
1246
108
    encoded = SEC_ASN1EncodeItem(arena, &pki->privateKey, &rawKey, keyTemplate);
1247
108
    if (!encoded) {
1248
0
        goto loser;
1249
0
    }
1250
108
    pki->version.type = siUnsignedInteger;
1251
108
    pki->version.data = (unsigned char *)PORT_ArenaAlloc(arena, 1);
1252
108
    if (!pki->version.data) {
1253
0
        goto loser;
1254
0
    }
1255
108
    pki->version.data[0] = pkiVersion;
1256
108
    pki->version.len = 1;
1257
108
    pki->arena = arena;
1258
1259
108
    return pki;
1260
1261
1.67k
loser:
1262
1.67k
    if (arena) {
1263
1.67k
        PORT_FreeArena(arena, PR_TRUE);
1264
1.67k
    }
1265
    return NULL;
1266
108
}