tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

pk11pk12.c (38750B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 /*
      5 * This file PKCS #12 fuctions that should really be moved to the
      6 * PKCS #12 directory, however we can't do that in a point release
      7 * because that will break binary compatibility, so we keep them here for now.
      8 */
      9 
     10 #include "seccomon.h"
     11 #include "secmod.h"
     12 #include "secmodi.h"
     13 #include "secmodti.h"
     14 #include "secmodt.h"
     15 #include "pkcs11.h"
     16 #include "pk11func.h"
     17 #include "secitem.h"
     18 #include "keyhi.h"
     19 #include "keyi.h"
     20 #include "secoid.h"
     21 #include "secasn1.h"
     22 #include "secerr.h"
     23 #include "prerror.h"
     24 
     25 /* These data structures should move to a common .h file shared between the
     26 * wrappers and the pkcs 12 code. */
     27 
     28 /*
     29 ** RSA Raw Private Key structures
     30 */
     31 
     32 /* member names from PKCS#1, section 7.2 */
     33 struct SECKEYRSAPrivateKeyStr {
     34    PLArenaPool *arena;
     35    SECItem version;
     36    SECItem modulus;
     37    SECItem publicExponent;
     38    SECItem privateExponent;
     39    SECItem prime1;
     40    SECItem prime2;
     41    SECItem exponent1;
     42    SECItem exponent2;
     43    SECItem coefficient;
     44 };
     45 typedef struct SECKEYRSAPrivateKeyStr SECKEYRSAPrivateKey;
     46 
     47 /*
     48 ** DSA Raw Private Key structures
     49 */
     50 
     51 struct SECKEYDSAPrivateKeyStr {
     52    SECKEYPQGParams params;
     53    SECItem privateValue;
     54 };
     55 typedef struct SECKEYDSAPrivateKeyStr SECKEYDSAPrivateKey;
     56 
     57 /*
     58 ** Diffie-Hellman Raw Private Key structures
     59 ** Structure member names suggested by PKCS#3.
     60 */
     61 struct SECKEYDHPrivateKeyStr {
     62    PLArenaPool *arena;
     63    SECItem prime;
     64    SECItem base;
     65    SECItem privateValue;
     66 };
     67 typedef struct SECKEYDHPrivateKeyStr SECKEYDHPrivateKey;
     68 
     69 /*
     70 ** Elliptic Curve Private Key structures
     71 ** <https://tools.ietf.org/html/rfc5915#section-3>
     72 */
     73 struct SECKEYECPrivateKeyStr {
     74    PLArenaPool *arena;
     75    SECItem version;
     76    SECItem curveOID;    /* optional/ignored */
     77    SECItem publicValue; /* required (for now) */
     78    SECItem privateValue;
     79 };
     80 typedef struct SECKEYECPrivateKeyStr SECKEYECPrivateKey;
     81 
     82 struct SECKEYMLDSAPrivateKeyStr {
     83    SECOidTag params;
     84    SECItem privateValue;
     85    SECItem seed;
     86 };
     87 typedef struct SECKEYMLDSAPrivateKeyStr SECKEYMLDSAPrivateKey;
     88 
     89 /*
     90 ** raw private key object
     91 */
     92 struct SECKEYRawPrivateKeyStr {
     93    PLArenaPool *arena;
     94    KeyType keyType;
     95    union {
     96        SECKEYRSAPrivateKey rsa;
     97        SECKEYDSAPrivateKey dsa;
     98        SECKEYDHPrivateKey dh;
     99        SECKEYECPrivateKey ec;
    100        SECKEYMLDSAPrivateKey mldsa;
    101    } u;
    102 };
    103 typedef struct SECKEYRawPrivateKeyStr SECKEYRawPrivateKey;
    104 
    105 SEC_ASN1_MKSUB(SEC_AnyTemplate)
    106 SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate)
    107 SEC_ASN1_MKSUB(SEC_OctetStringTemplate)
    108 
    109 /* ASN1 Templates for new decoder/encoder */
    110 /*
    111 * Attribute value for PKCS8 entries (static?)
    112 */
    113 const SEC_ASN1Template SECKEY_AttributeTemplate[] = {
    114    { SEC_ASN1_SEQUENCE,
    115      0, NULL, sizeof(SECKEYAttribute) },
    116    { SEC_ASN1_OBJECT_ID, offsetof(SECKEYAttribute, attrType) },
    117    { SEC_ASN1_SET_OF | SEC_ASN1_XTRN, offsetof(SECKEYAttribute, attrValue),
    118      SEC_ASN1_SUB(SEC_AnyTemplate) },
    119    { 0 }
    120 };
    121 
    122 const SEC_ASN1Template SECKEY_SetOfAttributeTemplate[] = {
    123    { SEC_ASN1_SET_OF, 0, SECKEY_AttributeTemplate },
    124 };
    125 
    126 const SEC_ASN1Template SECKEY_PrivateKeyInfoTemplate[] = {
    127    { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SECKEYPrivateKeyInfo) },
    128    { SEC_ASN1_INTEGER, offsetof(SECKEYPrivateKeyInfo, version) },
    129    { SEC_ASN1_INLINE | SEC_ASN1_XTRN,
    130      offsetof(SECKEYPrivateKeyInfo, algorithm),
    131      SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
    132    { SEC_ASN1_OCTET_STRING, offsetof(SECKEYPrivateKeyInfo, privateKey) },
    133    { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0,
    134      offsetof(SECKEYPrivateKeyInfo, attributes),
    135      SECKEY_SetOfAttributeTemplate },
    136    { 0 }
    137 };
    138 
    139 const SEC_ASN1Template SECKEY_PointerToPrivateKeyInfoTemplate[] = {
    140    { SEC_ASN1_POINTER, 0, SECKEY_PrivateKeyInfoTemplate }
    141 };
    142 
    143 const SEC_ASN1Template SECKEY_RSAPrivateKeyExportTemplate[] = {
    144    { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SECKEYRawPrivateKey) },
    145    { SEC_ASN1_INTEGER, offsetof(SECKEYRawPrivateKey, u.rsa.version) },
    146    { SEC_ASN1_INTEGER, offsetof(SECKEYRawPrivateKey, u.rsa.modulus) },
    147    { SEC_ASN1_INTEGER, offsetof(SECKEYRawPrivateKey, u.rsa.publicExponent) },
    148    { SEC_ASN1_INTEGER, offsetof(SECKEYRawPrivateKey, u.rsa.privateExponent) },
    149    { SEC_ASN1_INTEGER, offsetof(SECKEYRawPrivateKey, u.rsa.prime1) },
    150    { SEC_ASN1_INTEGER, offsetof(SECKEYRawPrivateKey, u.rsa.prime2) },
    151    { SEC_ASN1_INTEGER, offsetof(SECKEYRawPrivateKey, u.rsa.exponent1) },
    152    { SEC_ASN1_INTEGER, offsetof(SECKEYRawPrivateKey, u.rsa.exponent2) },
    153    { SEC_ASN1_INTEGER, offsetof(SECKEYRawPrivateKey, u.rsa.coefficient) },
    154    { 0 }
    155 };
    156 
    157 const SEC_ASN1Template SECKEY_DSAPrivateKeyExportTemplate[] = {
    158    { SEC_ASN1_INTEGER, offsetof(SECKEYRawPrivateKey, u.dsa.privateValue) },
    159 };
    160 
    161 const SEC_ASN1Template SECKEY_DHPrivateKeyExportTemplate[] = {
    162    { SEC_ASN1_INTEGER, offsetof(SECKEYRawPrivateKey, u.dh.privateValue) },
    163    { SEC_ASN1_INTEGER, offsetof(SECKEYRawPrivateKey, u.dh.base) },
    164    { SEC_ASN1_INTEGER, offsetof(SECKEYRawPrivateKey, u.dh.prime) },
    165 };
    166 
    167 const SEC_ASN1Template SECKEY_MLDSAPrivateKeyBothExportTemplate[] = {
    168    { SEC_ASN1_CHOICE, 0, NULL, sizeof(SECKEYRawPrivateKey) },
    169    { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SECKEYRawPrivateKey) },
    170    { SEC_ASN1_OCTET_STRING, offsetof(SECKEYRawPrivateKey, u.mldsa.seed) },
    171    { SEC_ASN1_OCTET_STRING, offsetof(SECKEYRawPrivateKey, u.mldsa.privateValue) },
    172    { 0 }
    173 };
    174 
    175 const SEC_ASN1Template SECKEY_MLDSAPrivateKeySeedExportTemplate[] = {
    176    { SEC_ASN1_CHOICE, 0, NULL, sizeof(SECKEYRawPrivateKey) },
    177    { SEC_ASN1_CONTEXT_SPECIFIC | 0,
    178      offsetof(SECKEYRawPrivateKey, u.mldsa.seed),
    179      SEC_ASN1_SUB(SEC_OctetStringTemplate) },
    180    { 0 }
    181 };
    182 
    183 const SEC_ASN1Template SECKEY_MLDSAPrivateKeyKeyExportTemplate[] = {
    184    { SEC_ASN1_CHOICE, 0, NULL, sizeof(SECKEYRawPrivateKey) },
    185    { SEC_ASN1_OCTET_STRING, offsetof(SECKEYRawPrivateKey, u.mldsa.privateValue) },
    186    { 0 }
    187 };
    188 
    189 SEC_ASN1_MKSUB(SEC_BitStringTemplate)
    190 SEC_ASN1_MKSUB(SEC_ObjectIDTemplate)
    191 
    192 const SEC_ASN1Template SECKEY_ECPrivateKeyExportTemplate[] = {
    193    { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SECKEYRawPrivateKey) },
    194    { SEC_ASN1_INTEGER, offsetof(SECKEYRawPrivateKey, u.ec.version) },
    195    { SEC_ASN1_OCTET_STRING,
    196      offsetof(SECKEYRawPrivateKey, u.ec.privateValue) },
    197    /* This value will always be ignored. u.ec.curveOID will always be
    198     * overriden with the outer AlgorithmID.parameters. */
    199    { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED |
    200          SEC_ASN1_EXPLICIT | SEC_ASN1_CONTEXT_SPECIFIC |
    201          SEC_ASN1_XTRN | 0,
    202      offsetof(SECKEYRawPrivateKey, u.ec.curveOID),
    203      SEC_ASN1_SUB(SEC_ObjectIDTemplate) },
    204    /* The public value is optional per RFC, but required in NSS. We
    205     * can't do scalar mult on ECs to get a raw point with PK11 APIs. */
    206    { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED |
    207          SEC_ASN1_EXPLICIT | SEC_ASN1_CONTEXT_SPECIFIC |
    208          SEC_ASN1_XTRN | 1,
    209      offsetof(SECKEYRawPrivateKey, u.ec.publicValue),
    210      SEC_ASN1_SUB(SEC_BitStringTemplate) },
    211    { 0 }
    212 };
    213 
    214 /* The template operates a private key consisting only of private key. */
    215 const SEC_ASN1Template SECKEY_ECRawPrivateKeyTemplate[] = {
    216    { SEC_ASN1_OCTET_STRING,
    217      offsetof(SECKEYRawPrivateKey, u.ec.privateValue) },
    218    { 0 }
    219 };
    220 
    221 const SEC_ASN1Template SECKEY_EncryptedPrivateKeyInfoTemplate[] = {
    222    { SEC_ASN1_SEQUENCE,
    223      0, NULL, sizeof(SECKEYEncryptedPrivateKeyInfo) },
    224    { SEC_ASN1_INLINE | SEC_ASN1_XTRN,
    225      offsetof(SECKEYEncryptedPrivateKeyInfo, algorithm),
    226      SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
    227    { SEC_ASN1_OCTET_STRING,
    228      offsetof(SECKEYEncryptedPrivateKeyInfo, encryptedData) },
    229    { 0 }
    230 };
    231 
    232 const SEC_ASN1Template SECKEY_PointerToEncryptedPrivateKeyInfoTemplate[] = {
    233    { SEC_ASN1_POINTER, 0, SECKEY_EncryptedPrivateKeyInfoTemplate }
    234 };
    235 
    236 SEC_ASN1_CHOOSER_IMPLEMENT(SECKEY_EncryptedPrivateKeyInfoTemplate)
    237 SEC_ASN1_CHOOSER_IMPLEMENT(SECKEY_PointerToEncryptedPrivateKeyInfoTemplate)
    238 SEC_ASN1_CHOOSER_IMPLEMENT(SECKEY_PrivateKeyInfoTemplate)
    239 SEC_ASN1_CHOOSER_IMPLEMENT(SECKEY_PointerToPrivateKeyInfoTemplate)
    240 
    241 /*
    242 * See bugzilla bug 125359
    243 * Since NSS (via PKCS#11) wants to handle big integers as unsigned ints,
    244 * all of the templates above that en/decode into integers must be converted
    245 * from ASN.1's signed integer type.  This is done by marking either the
    246 * source or destination (encoding or decoding, respectively) type as
    247 * siUnsignedInteger.
    248 */
    249 
    250 static void
    251 prepare_rsa_priv_key_export_for_asn1(SECKEYRawPrivateKey *key)
    252 {
    253    key->u.rsa.modulus.type = siUnsignedInteger;
    254    key->u.rsa.publicExponent.type = siUnsignedInteger;
    255    key->u.rsa.privateExponent.type = siUnsignedInteger;
    256    key->u.rsa.prime1.type = siUnsignedInteger;
    257    key->u.rsa.prime2.type = siUnsignedInteger;
    258    key->u.rsa.exponent1.type = siUnsignedInteger;
    259    key->u.rsa.exponent2.type = siUnsignedInteger;
    260    key->u.rsa.coefficient.type = siUnsignedInteger;
    261 }
    262 
    263 static void
    264 prepare_dsa_priv_key_export_for_asn1(SECKEYRawPrivateKey *key)
    265 {
    266    key->u.dsa.privateValue.type = siUnsignedInteger;
    267    key->u.dsa.params.prime.type = siUnsignedInteger;
    268    key->u.dsa.params.subPrime.type = siUnsignedInteger;
    269    key->u.dsa.params.base.type = siUnsignedInteger;
    270 }
    271 
    272 static void
    273 prepare_dh_priv_key_export_for_asn1(SECKEYRawPrivateKey *key)
    274 {
    275    key->u.dh.privateValue.type = siUnsignedInteger;
    276    key->u.dh.prime.type = siUnsignedInteger;
    277    key->u.dh.base.type = siUnsignedInteger;
    278 }
    279 
    280 static void
    281 prepare_ec_priv_key_export_for_asn1(SECKEYRawPrivateKey *key)
    282 {
    283    key->u.ec.version.type = siUnsignedInteger;
    284    key->u.ec.curveOID.type = siUnsignedInteger;
    285    key->u.ec.privateValue.type = siUnsignedInteger;
    286    key->u.ec.publicValue.type = siUnsignedInteger;
    287 }
    288 
    289 SECStatus
    290 PK11_ImportDERPrivateKeyInfo(PK11SlotInfo *slot, SECItem *derPKI,
    291                             SECItem *nickname, const SECItem *publicValue, PRBool isPerm,
    292                             PRBool isPrivate, unsigned int keyUsage, void *wincx)
    293 {
    294    return PK11_ImportDERPrivateKeyInfoAndReturnKey(slot, derPKI,
    295                                                    nickname, publicValue,
    296                                                    isPerm, isPrivate, keyUsage,
    297                                                    NULL, wincx);
    298 }
    299 
    300 SECStatus
    301 PK11_ImportDERPrivateKeyInfoAndReturnKey(PK11SlotInfo *slot, SECItem *derPKI,
    302                                         SECItem *nickname, const SECItem *publicValue,
    303                                         PRBool isPerm, PRBool isPrivate, unsigned int keyUsage,
    304                                         SECKEYPrivateKey **privk, void *wincx)
    305 {
    306    SECKEYPrivateKeyInfo *pki = NULL;
    307    PLArenaPool *temparena = NULL;
    308    SECStatus rv = SECFailure;
    309 
    310    temparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
    311    if (!temparena) {
    312        return rv;
    313    }
    314 
    315    pki = PORT_ArenaZNew(temparena, SECKEYPrivateKeyInfo);
    316    if (!pki) {
    317        PORT_FreeArena(temparena, PR_FALSE);
    318        return rv;
    319    }
    320    pki->arena = temparena;
    321 
    322    rv = SEC_ASN1DecodeItem(pki->arena, pki, SECKEY_PrivateKeyInfoTemplate,
    323                            derPKI);
    324    if (rv != SECSuccess) {
    325        /* If SEC_ASN1DecodeItem fails, we cannot assume anything about the
    326         * validity of the data in pki. The best we can do is free the arena
    327         * and return. */
    328        PORT_FreeArena(temparena, PR_TRUE);
    329        return rv;
    330    }
    331    if (pki->privateKey.data == NULL) {
    332        /* If SEC_ASN1DecodeItems succeeds but SECKEYPrivateKeyInfo.privateKey
    333         * is a zero-length octet string, free the arena and return a failure
    334         * to avoid trying to zero the corresponding SECItem in
    335         * SECKEY_DestroyPrivateKeyInfo(). */
    336        PORT_FreeArena(temparena, PR_TRUE);
    337        PORT_SetError(SEC_ERROR_BAD_KEY);
    338        return SECFailure;
    339    }
    340 
    341    rv = PK11_ImportPrivateKeyInfoAndReturnKey(slot, pki, nickname,
    342                                               publicValue, isPerm, isPrivate,
    343                                               keyUsage, privk, wincx);
    344 
    345    /* this zeroes the key and frees the arena */
    346    SECKEY_DestroyPrivateKeyInfo(pki, PR_TRUE /*freeit*/);
    347    return rv;
    348 }
    349 
    350 SECStatus
    351 PK11_ImportAndReturnPrivateKey(PK11SlotInfo *slot, SECKEYRawPrivateKey *lpk,
    352                               SECItem *nickname, const SECItem *publicValue, PRBool isPerm,
    353                               PRBool isPrivate, unsigned int keyUsage, SECKEYPrivateKey **privk,
    354                               void *wincx)
    355 {
    356    CK_BBOOL cktrue = CK_TRUE;
    357    CK_BBOOL ckfalse = CK_FALSE;
    358    CK_OBJECT_CLASS keyClass = CKO_PRIVATE_KEY;
    359    CK_KEY_TYPE keyType = CKK_RSA;
    360    CK_OBJECT_HANDLE objectID;
    361    CK_ATTRIBUTE theTemplate[20];
    362    int templateCount = 0;
    363    SECStatus rv = SECFailure;
    364    CK_ATTRIBUTE *attrs;
    365    CK_ATTRIBUTE *signedattr = NULL;
    366    int signedcount = 0;
    367    CK_ATTRIBUTE *ap;
    368    SECItem *ck_id = NULL;
    369    CK_ULONG paramSet;
    370 
    371    attrs = theTemplate;
    372 
    373    PK11_SETATTRS(attrs, CKA_CLASS, &keyClass, sizeof(keyClass));
    374    attrs++;
    375    PK11_SETATTRS(attrs, CKA_KEY_TYPE, &keyType, sizeof(keyType));
    376    attrs++;
    377    PK11_SETATTRS(attrs, CKA_TOKEN, isPerm ? &cktrue : &ckfalse,
    378                  sizeof(CK_BBOOL));
    379    attrs++;
    380    PK11_SETATTRS(attrs, CKA_SENSITIVE, isPrivate ? &cktrue : &ckfalse,
    381                  sizeof(CK_BBOOL));
    382    attrs++;
    383    PK11_SETATTRS(attrs, CKA_PRIVATE, isPrivate ? &cktrue : &ckfalse,
    384                  sizeof(CK_BBOOL));
    385    attrs++;
    386 
    387    switch (lpk->keyType) {
    388        case rsaKey:
    389            keyType = CKK_RSA;
    390            PK11_SETATTRS(attrs, CKA_UNWRAP, (keyUsage & KU_KEY_ENCIPHERMENT) ? &cktrue : &ckfalse,
    391                          sizeof(CK_BBOOL));
    392            attrs++;
    393            PK11_SETATTRS(attrs, CKA_DECRYPT, (keyUsage & KU_DATA_ENCIPHERMENT) ? &cktrue : &ckfalse,
    394                          sizeof(CK_BBOOL));
    395            attrs++;
    396            PK11_SETATTRS(attrs, CKA_SIGN, (keyUsage & KU_DIGITAL_SIGNATURE) ? &cktrue : &ckfalse,
    397                          sizeof(CK_BBOOL));
    398            attrs++;
    399            PK11_SETATTRS(attrs, CKA_SIGN_RECOVER,
    400                          (keyUsage & KU_DIGITAL_SIGNATURE) ? &cktrue
    401                                                            : &ckfalse,
    402                          sizeof(CK_BBOOL));
    403            attrs++;
    404            ck_id = PK11_MakeIDFromPubKey(&lpk->u.rsa.modulus);
    405            if (ck_id == NULL) {
    406                goto loser;
    407            }
    408            PK11_SETATTRS(attrs, CKA_ID, ck_id->data, ck_id->len);
    409            attrs++;
    410            if (nickname) {
    411                PK11_SETATTRS(attrs, CKA_LABEL, nickname->data, nickname->len);
    412                attrs++;
    413            }
    414            signedattr = attrs;
    415            PK11_SETATTRS(attrs, CKA_MODULUS, lpk->u.rsa.modulus.data,
    416                          lpk->u.rsa.modulus.len);
    417            attrs++;
    418            PK11_SETATTRS(attrs, CKA_PUBLIC_EXPONENT,
    419                          lpk->u.rsa.publicExponent.data,
    420                          lpk->u.rsa.publicExponent.len);
    421            attrs++;
    422            PK11_SETATTRS(attrs, CKA_PRIVATE_EXPONENT,
    423                          lpk->u.rsa.privateExponent.data,
    424                          lpk->u.rsa.privateExponent.len);
    425            attrs++;
    426            PK11_SETATTRS(attrs, CKA_PRIME_1,
    427                          lpk->u.rsa.prime1.data,
    428                          lpk->u.rsa.prime1.len);
    429            attrs++;
    430            PK11_SETATTRS(attrs, CKA_PRIME_2,
    431                          lpk->u.rsa.prime2.data,
    432                          lpk->u.rsa.prime2.len);
    433            attrs++;
    434            PK11_SETATTRS(attrs, CKA_EXPONENT_1,
    435                          lpk->u.rsa.exponent1.data,
    436                          lpk->u.rsa.exponent1.len);
    437            attrs++;
    438            PK11_SETATTRS(attrs, CKA_EXPONENT_2,
    439                          lpk->u.rsa.exponent2.data,
    440                          lpk->u.rsa.exponent2.len);
    441            attrs++;
    442            PK11_SETATTRS(attrs, CKA_COEFFICIENT,
    443                          lpk->u.rsa.coefficient.data,
    444                          lpk->u.rsa.coefficient.len);
    445            attrs++;
    446            break;
    447        case dsaKey:
    448            keyType = CKK_DSA;
    449            /* To make our intenal PKCS #11 module work correctly with
    450             * our database, we need to pass in the public key value for
    451             * this dsa key. We have a netscape only CKA_ value to do this.
    452             * Only send it to internal slots */
    453            if (publicValue == NULL) {
    454                goto loser;
    455            }
    456            if (PK11_IsInternal(slot)) {
    457                PK11_SETATTRS(attrs, CKA_NSS_DB,
    458                              publicValue->data, publicValue->len);
    459                attrs++;
    460            }
    461            PK11_SETATTRS(attrs, CKA_SIGN, &cktrue, sizeof(CK_BBOOL));
    462            attrs++;
    463            PK11_SETATTRS(attrs, CKA_SIGN_RECOVER, &ckfalse, sizeof(CK_BBOOL));
    464            attrs++;
    465            if (nickname) {
    466                PK11_SETATTRS(attrs, CKA_LABEL, nickname->data, nickname->len);
    467                attrs++;
    468            }
    469            ck_id = PK11_MakeIDFromPubKey(publicValue);
    470            if (ck_id == NULL) {
    471                goto loser;
    472            }
    473            PK11_SETATTRS(attrs, CKA_ID, ck_id->data, ck_id->len);
    474            attrs++;
    475            signedattr = attrs;
    476            PK11_SETATTRS(attrs, CKA_PRIME, lpk->u.dsa.params.prime.data,
    477                          lpk->u.dsa.params.prime.len);
    478            attrs++;
    479            PK11_SETATTRS(attrs, CKA_SUBPRIME, lpk->u.dsa.params.subPrime.data,
    480                          lpk->u.dsa.params.subPrime.len);
    481            attrs++;
    482            PK11_SETATTRS(attrs, CKA_BASE, lpk->u.dsa.params.base.data,
    483                          lpk->u.dsa.params.base.len);
    484            attrs++;
    485            PK11_SETATTRS(attrs, CKA_VALUE, lpk->u.dsa.privateValue.data,
    486                          lpk->u.dsa.privateValue.len);
    487            attrs++;
    488            break;
    489        case dhKey:
    490            keyType = CKK_DH;
    491            /* To make our intenal PKCS #11 module work correctly with
    492             * our database, we need to pass in the public key value for
    493             * this dh key. We have a netscape only CKA_ value to do this.
    494             * Only send it to internal slots */
    495            if (PK11_IsInternal(slot)) {
    496                PK11_SETATTRS(attrs, CKA_NSS_DB,
    497                              publicValue->data, publicValue->len);
    498                attrs++;
    499            }
    500            PK11_SETATTRS(attrs, CKA_DERIVE, &cktrue, sizeof(CK_BBOOL));
    501            attrs++;
    502            if (nickname) {
    503                PK11_SETATTRS(attrs, CKA_LABEL, nickname->data, nickname->len);
    504                attrs++;
    505            }
    506            ck_id = PK11_MakeIDFromPubKey(publicValue);
    507            if (ck_id == NULL) {
    508                goto loser;
    509            }
    510            PK11_SETATTRS(attrs, CKA_ID, ck_id->data, ck_id->len);
    511            attrs++;
    512            signedattr = attrs;
    513            PK11_SETATTRS(attrs, CKA_PRIME, lpk->u.dh.prime.data,
    514                          lpk->u.dh.prime.len);
    515            attrs++;
    516            PK11_SETATTRS(attrs, CKA_BASE, lpk->u.dh.base.data,
    517                          lpk->u.dh.base.len);
    518            attrs++;
    519            PK11_SETATTRS(attrs, CKA_VALUE, lpk->u.dh.privateValue.data,
    520                          lpk->u.dh.privateValue.len);
    521            attrs++;
    522            break;
    523        case ecKey:
    524            keyType = CKK_EC;
    525            if (lpk->u.ec.publicValue.len != 0) {
    526                if (PK11_IsInternal(slot)) {
    527                    PK11_SETATTRS(attrs, CKA_NSS_DB,
    528                                  lpk->u.ec.publicValue.data,
    529                                  lpk->u.ec.publicValue.len);
    530                    attrs++;
    531                }
    532            }
    533 
    534            PK11_SETATTRS(attrs, CKA_SIGN, (keyUsage & KU_DIGITAL_SIGNATURE) ? &cktrue : &ckfalse,
    535                          sizeof(CK_BBOOL));
    536            attrs++;
    537            PK11_SETATTRS(attrs, CKA_SIGN_RECOVER, &ckfalse,
    538                          sizeof(CK_BBOOL));
    539            attrs++;
    540            PK11_SETATTRS(attrs, CKA_DERIVE, (keyUsage & KU_KEY_AGREEMENT) ? &cktrue : &ckfalse,
    541                          sizeof(CK_BBOOL));
    542            attrs++;
    543            if (nickname) {
    544                PK11_SETATTRS(attrs, CKA_LABEL, nickname->data, nickname->len);
    545                attrs++;
    546            }
    547            ck_id = PK11_MakeIDFromPubKey(&lpk->u.ec.publicValue);
    548            if (ck_id == NULL) {
    549                goto loser;
    550            }
    551            PK11_SETATTRS(attrs, CKA_ID, ck_id->data, ck_id->len);
    552            attrs++;
    553            /* No signed attrs for EC */
    554            /* curveOID always is a copy of AlgorithmID.parameters. */
    555            PK11_SETATTRS(attrs, CKA_EC_PARAMS, lpk->u.ec.curveOID.data,
    556                          lpk->u.ec.curveOID.len);
    557            attrs++;
    558            PK11_SETATTRS(attrs, CKA_VALUE, lpk->u.ec.privateValue.data,
    559                          lpk->u.ec.privateValue.len);
    560            attrs++;
    561            PK11_SETATTRS(attrs, CKA_EC_POINT, lpk->u.ec.publicValue.data,
    562                          lpk->u.ec.publicValue.len);
    563            attrs++;
    564            break;
    565        case edKey:
    566            keyType = CKK_EC_EDWARDS;
    567            PK11_SETATTRS(attrs, CKA_SIGN, &cktrue, sizeof(CK_BBOOL));
    568            attrs++;
    569            if (nickname) {
    570                PK11_SETATTRS(attrs, CKA_LABEL, nickname->data, nickname->len);
    571                attrs++;
    572            }
    573 
    574            /* No signed attrs for EC */
    575            /* curveOID always is a copy of AlgorithmID.parameters. */
    576            PK11_SETATTRS(attrs, CKA_EC_PARAMS, lpk->u.ec.curveOID.data,
    577                          lpk->u.ec.curveOID.len);
    578            attrs++;
    579            PK11_SETATTRS(attrs, CKA_VALUE, lpk->u.ec.privateValue.data,
    580                          lpk->u.ec.privateValue.len);
    581            attrs++;
    582            break;
    583        case ecMontKey:
    584            keyType = CKK_EC_MONTGOMERY;
    585 
    586            PK11_SETATTRS(attrs, CKA_DERIVE, &cktrue, sizeof(CK_BBOOL));
    587            attrs++;
    588 
    589            if (nickname) {
    590                PK11_SETATTRS(attrs, CKA_LABEL, nickname->data, nickname->len);
    591                attrs++;
    592            }
    593 
    594            /* No signed attrs for EC */
    595            /* curveOID always is a copy of AlgorithmID.parameters. */
    596            PK11_SETATTRS(attrs, CKA_EC_PARAMS, lpk->u.ec.curveOID.data,
    597                          lpk->u.ec.curveOID.len);
    598            attrs++;
    599 
    600            PK11_SETATTRS(attrs, CKA_VALUE, lpk->u.ec.privateValue.data,
    601                          lpk->u.ec.privateValue.len);
    602            attrs++;
    603            break;
    604        case mldsaKey:
    605            keyType = CKK_ML_DSA;
    606            /* we need at least one of these to import into PKCS #11.
    607             * if we have only one, it may still fail, but that is up
    608             * to the token */
    609            if ((lpk->u.mldsa.seed.len == 0) &&
    610                (lpk->u.mldsa.privateValue.len == 0)) {
    611                PORT_SetError(SEC_ERROR_BAD_KEY);
    612                goto loser;
    613            }
    614            PK11_SETATTRS(attrs, CKA_SIGN, &cktrue, sizeof(CK_BBOOL));
    615            attrs++;
    616            PK11_SETATTRS(attrs, CKA_SIGN_RECOVER, &ckfalse, sizeof(CK_BBOOL));
    617            attrs++;
    618            /* if we have the public value, we can do more, without it
    619             * we won't be able to set the ck_id properly, which will make
    620             * this key effectively invisible. The application will need
    621             * to update the ID before it looses it's handle */
    622            if (publicValue != NULL) {
    623                if (PK11_IsInternal(slot)) {
    624                    PK11_SETATTRS(attrs, CKA_NSS_DB,
    625                                  publicValue->data, publicValue->len);
    626                    attrs++;
    627                }
    628                ck_id = PK11_MakeIDFromPubKey(publicValue);
    629                if (ck_id == NULL) {
    630                    goto loser;
    631                }
    632                PK11_SETATTRS(attrs, CKA_ID, ck_id->data, ck_id->len);
    633                attrs++;
    634            }
    635            if (nickname) {
    636                PK11_SETATTRS(attrs, CKA_LABEL, nickname->data, nickname->len);
    637                attrs++;
    638            }
    639            paramSet = SECKEY_GetMLDSAPkcs11ParamSetByOidTag(lpk->u.mldsa.params);
    640            PK11_SETATTRS(attrs, CKA_PARAMETER_SET, (unsigned char *)&paramSet,
    641                          sizeof(CK_ML_DSA_PARAMETER_SET_TYPE));
    642            attrs++;
    643            if (lpk->u.mldsa.seed.len) {
    644                PK11_SETATTRS(attrs, CKA_SEED, lpk->u.mldsa.seed.data,
    645                              lpk->u.mldsa.seed.len);
    646                attrs++;
    647            }
    648            if (lpk->u.mldsa.privateValue.len) {
    649                PK11_SETATTRS(attrs, CKA_VALUE, lpk->u.mldsa.privateValue.data,
    650                              lpk->u.mldsa.privateValue.len);
    651                attrs++;
    652            }
    653            break;
    654        default:
    655            PORT_SetError(SEC_ERROR_BAD_KEY);
    656            goto loser;
    657    }
    658    templateCount = attrs - theTemplate;
    659    PORT_Assert(templateCount <= sizeof(theTemplate) / sizeof(CK_ATTRIBUTE));
    660    /* we used to assert unless the key didn't need signedattrs, but that's
    661     * now true of almost all modern keys, so now if the key has signedattrs
    662     * the just need to set the value */
    663    if (signedattr) {
    664        signedcount = attrs - signedattr;
    665        for (ap = signedattr; signedcount; ap++, signedcount--) {
    666            pk11_SignedToUnsigned(ap);
    667        }
    668    }
    669 
    670    rv = PK11_CreateNewObject(slot, CK_INVALID_HANDLE,
    671                              theTemplate, templateCount, isPerm, &objectID);
    672 
    673    /* create and return a SECKEYPrivateKey */
    674    if (rv == SECSuccess && privk != NULL) {
    675        *privk = PK11_MakePrivKey(slot, lpk->keyType, !isPerm, objectID, wincx);
    676        if (*privk == NULL) {
    677            rv = SECFailure;
    678        }
    679    }
    680 loser:
    681    if (ck_id) {
    682        SECITEM_ZfreeItem(ck_id, PR_TRUE);
    683    }
    684    return rv;
    685 }
    686 
    687 SECStatus
    688 PK11_ImportPrivateKeyInfoAndReturnKey(PK11SlotInfo *slot,
    689                                      SECKEYPrivateKeyInfo *pki, SECItem *nickname, const SECItem *publicValue,
    690                                      PRBool isPerm, PRBool isPrivate, unsigned int keyUsage,
    691                                      SECKEYPrivateKey **privk, void *wincx)
    692 {
    693    SECStatus rv = SECFailure;
    694    SECKEYRawPrivateKey *lpk = NULL;
    695    const SEC_ASN1Template *keyTemplate, *paramTemplate;
    696    void *paramDest = NULL;
    697    PLArenaPool *arena = NULL;
    698    SECOidTag algTag;
    699 
    700    arena = PORT_NewArena(2048);
    701    if (!arena) {
    702        return SECFailure;
    703    }
    704 
    705    /* need to change this to use RSA/DSA keys */
    706    lpk = (SECKEYRawPrivateKey *)PORT_ArenaZAlloc(arena,
    707                                                  sizeof(SECKEYRawPrivateKey));
    708    if (lpk == NULL) {
    709        goto loser;
    710    }
    711    lpk->arena = arena;
    712 
    713    algTag = SECOID_GetAlgorithmTag(&pki->algorithm);
    714    switch (algTag) {
    715        case SEC_OID_PKCS1_RSA_ENCRYPTION:
    716            prepare_rsa_priv_key_export_for_asn1(lpk);
    717            keyTemplate = SECKEY_RSAPrivateKeyExportTemplate;
    718            paramTemplate = NULL;
    719            paramDest = NULL;
    720            lpk->keyType = rsaKey;
    721            break;
    722        case SEC_OID_ANSIX9_DSA_SIGNATURE:
    723            prepare_dsa_priv_key_export_for_asn1(lpk);
    724            keyTemplate = SECKEY_DSAPrivateKeyExportTemplate;
    725            paramTemplate = SECKEY_PQGParamsTemplate;
    726            paramDest = &(lpk->u.dsa.params);
    727            lpk->keyType = dsaKey;
    728            break;
    729        case SEC_OID_X942_DIFFIE_HELMAN_KEY:
    730            if (!publicValue) {
    731                goto loser;
    732            }
    733            prepare_dh_priv_key_export_for_asn1(lpk);
    734            keyTemplate = SECKEY_DHPrivateKeyExportTemplate;
    735            paramTemplate = NULL;
    736            paramDest = NULL;
    737            lpk->keyType = dhKey;
    738            break;
    739        case SEC_OID_ED25519_PUBLIC_KEY:
    740            keyTemplate = SECKEY_ECRawPrivateKeyTemplate;
    741            paramTemplate = NULL;
    742            paramDest = NULL;
    743            lpk->keyType = edKey;
    744            break;
    745        case SEC_OID_X25519:
    746            keyTemplate = SECKEY_ECRawPrivateKeyTemplate;
    747            paramTemplate = NULL;
    748            paramDest = NULL;
    749            lpk->keyType = ecMontKey;
    750            break;
    751        case SEC_OID_ANSIX962_EC_PUBLIC_KEY:
    752            prepare_ec_priv_key_export_for_asn1(lpk);
    753            keyTemplate = SECKEY_ECPrivateKeyExportTemplate;
    754            paramTemplate = NULL;
    755            paramDest = NULL;
    756            lpk->keyType = ecKey;
    757            break;
    758        case SEC_OID_ML_DSA_44:
    759        case SEC_OID_ML_DSA_65:
    760        case SEC_OID_ML_DSA_87:
    761            /* choice */
    762            switch (pki->privateKey.data[0]) {
    763                case SEC_ASN1_CONTEXT_SPECIFIC | 0:
    764                    keyTemplate = SECKEY_MLDSAPrivateKeySeedExportTemplate;
    765                    break;
    766                case SEC_ASN1_OCTET_STRING:
    767                    keyTemplate = SECKEY_MLDSAPrivateKeyKeyExportTemplate;
    768                    break;
    769                case SEC_ASN1_CONSTRUCTED | SEC_ASN1_SEQUENCE:
    770                    keyTemplate = SECKEY_MLDSAPrivateKeyBothExportTemplate;
    771                    break;
    772                default:
    773                    keyTemplate = NULL;
    774                    PORT_SetError(SEC_ERROR_BAD_DER);
    775                    break;
    776            }
    777            paramTemplate = NULL;
    778            paramDest = NULL;
    779            lpk->keyType = mldsaKey;
    780            lpk->u.mldsa.params = algTag;
    781            break;
    782        default:
    783            keyTemplate = NULL;
    784            paramTemplate = NULL;
    785            paramDest = NULL;
    786            break;
    787    }
    788 
    789    if (!keyTemplate) {
    790        goto loser;
    791    }
    792 
    793    /* decode the private key and any algorithm parameters */
    794    rv = SEC_QuickDERDecodeItem(arena, lpk, keyTemplate, &pki->privateKey);
    795    if (rv != SECSuccess) {
    796        goto loser;
    797    }
    798 
    799    if (lpk->keyType == ecKey) {
    800        /* Convert length in bits to length in bytes. */
    801        lpk->u.ec.publicValue.len >>= 3;
    802 
    803        /* Always override curveOID, we're ignoring any given value. */
    804        rv = SECITEM_CopyItem(arena, &lpk->u.ec.curveOID,
    805                              &pki->algorithm.parameters);
    806        if (rv != SECSuccess) {
    807            goto loser;
    808        }
    809    }
    810 
    811    if (lpk->keyType == edKey || lpk->keyType == ecMontKey) {
    812        /* SECKEY_ECRawPrivateKeyTemplate (used for both key types) does not reference
    813           publicKey, curveOID, ec verion. */
    814        if (pki->algorithm.parameters.len != 0) {
    815            /* Currently supporting only (Pure)Ed25519/X25519 .*/
    816            PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG);
    817            goto loser;
    818        }
    819 
    820        SECOidData *oid25519 = SECOID_FindOIDByTag(SECOID_GetAlgorithmTag(&pki->algorithm));
    821        if (!oid25519) {
    822            goto loser;
    823        }
    824 
    825        if (!SECITEM_AllocItem(arena, &lpk->u.ec.curveOID, oid25519->oid.len + 2)) {
    826            goto loser;
    827        }
    828        lpk->u.ec.curveOID.data[0] = SEC_ASN1_OBJECT_ID;
    829        lpk->u.ec.curveOID.data[1] = oid25519->oid.len;
    830        PORT_Memcpy(lpk->u.ec.curveOID.data + 2, oid25519->oid.data, oid25519->oid.len);
    831    }
    832 
    833    if (paramDest && paramTemplate) {
    834        rv = SEC_ASN1DecodeItem(arena, paramDest, paramTemplate,
    835                                &(pki->algorithm.parameters));
    836        if (rv != SECSuccess) {
    837            goto loser;
    838        }
    839    }
    840 
    841    rv = PK11_ImportAndReturnPrivateKey(slot, lpk, nickname, publicValue, isPerm,
    842                                        isPrivate, keyUsage, privk, wincx);
    843 loser:
    844    if (arena != NULL) {
    845        PORT_FreeArena(arena, PR_TRUE);
    846    }
    847 
    848    return rv;
    849 }
    850 
    851 SECStatus
    852 PK11_ImportPrivateKeyInfo(PK11SlotInfo *slot, SECKEYPrivateKeyInfo *pki,
    853                          SECItem *nickname, const SECItem *publicValue, PRBool isPerm,
    854                          PRBool isPrivate, unsigned int keyUsage, void *wincx)
    855 {
    856    return PK11_ImportPrivateKeyInfoAndReturnKey(slot, pki, nickname,
    857                                                 publicValue, isPerm, isPrivate, keyUsage, NULL, wincx);
    858 }
    859 
    860 SECItem *
    861 PK11_ExportDERPrivateKeyInfo(SECKEYPrivateKey *pk, void *wincx)
    862 {
    863    SECKEYPrivateKeyInfo *pki = PK11_ExportPrivKeyInfo(pk, wincx);
    864    SECItem *derPKI;
    865 
    866    if (!pki) {
    867        return NULL;
    868    }
    869    derPKI = SEC_ASN1EncodeItem(NULL, NULL, pki,
    870                                SECKEY_PrivateKeyInfoTemplate);
    871    SECKEY_DestroyPrivateKeyInfo(pki, PR_TRUE);
    872    return derPKI;
    873 }
    874 
    875 static PRBool
    876 ReadAttribute(SECKEYPrivateKey *key, CK_ATTRIBUTE_TYPE type,
    877              PLArenaPool *arena, SECItem *output)
    878 {
    879    SECStatus rv = PK11_ReadAttribute(key->pkcs11Slot, key->pkcs11ID, type,
    880                                      arena, output);
    881    return rv == SECSuccess;
    882 }
    883 
    884 /*
    885 * The caller is responsible for freeing the return value by passing it to
    886 * SECKEY_DestroyPrivateKeyInfo(..., PR_TRUE).
    887 */
    888 SECKEYPrivateKeyInfo *
    889 PK11_ExportPrivKeyInfo(SECKEYPrivateKey *pk, void *wincx)
    890 {
    891    /* PrivateKeyInfo version (always zero) */
    892    const unsigned char pkiVersion = 0;
    893    /* RSAPrivateKey version (always zero) */
    894    const unsigned char rsaVersion = 0;
    895    /* ECPrivateKey version (always one) */
    896    const unsigned char ecVersion = 1;
    897    PLArenaPool *arena = NULL;
    898    SECKEYRawPrivateKey rawKey;
    899    SECKEYPrivateKeyInfo *pki;
    900    SECItem *encoded;
    901    const SEC_ASN1Template *keyTemplate;
    902    SECStatus rv;
    903 
    904    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
    905    if (!arena) {
    906        goto loser;
    907    }
    908    memset(&rawKey, 0, sizeof(rawKey));
    909    rawKey.keyType = pk->keyType;
    910    pki = PORT_ArenaZNew(arena, SECKEYPrivateKeyInfo);
    911    if (!pki) {
    912        goto loser;
    913    }
    914 
    915    switch (pk->keyType) {
    916        case rsaKey: {
    917            rawKey.u.rsa.version.type = siUnsignedInteger;
    918            rawKey.u.rsa.version.data = (unsigned char *)PORT_ArenaAlloc(arena, 1);
    919            if (!rawKey.u.rsa.version.data) {
    920                goto loser;
    921            }
    922 
    923            rawKey.u.rsa.version.data[0] = rsaVersion;
    924            rawKey.u.rsa.version.len = 1;
    925 
    926            /* Read the component attributes of the private key */
    927            prepare_rsa_priv_key_export_for_asn1(&rawKey);
    928            if (!ReadAttribute(pk, CKA_MODULUS, arena, &rawKey.u.rsa.modulus) ||
    929                !ReadAttribute(pk, CKA_PUBLIC_EXPONENT, arena,
    930                               &rawKey.u.rsa.publicExponent) ||
    931                !ReadAttribute(pk, CKA_PRIVATE_EXPONENT, arena,
    932                               &rawKey.u.rsa.privateExponent) ||
    933                !ReadAttribute(pk, CKA_PRIME_1, arena, &rawKey.u.rsa.prime1) ||
    934                !ReadAttribute(pk, CKA_PRIME_2, arena, &rawKey.u.rsa.prime2) ||
    935                !ReadAttribute(pk, CKA_EXPONENT_1, arena,
    936                               &rawKey.u.rsa.exponent1) ||
    937                !ReadAttribute(pk, CKA_EXPONENT_2, arena,
    938                               &rawKey.u.rsa.exponent2) ||
    939                !ReadAttribute(pk, CKA_COEFFICIENT, arena,
    940                               &rawKey.u.rsa.coefficient)) {
    941                goto loser;
    942            }
    943 
    944            keyTemplate = SECKEY_RSAPrivateKeyExportTemplate;
    945 
    946            rv = SECOID_SetAlgorithmID(arena, &pki->algorithm, SEC_OID_PKCS1_RSA_ENCRYPTION, NULL);
    947            if (rv != SECSuccess) {
    948                goto loser;
    949            }
    950 
    951        } break;
    952        case ecKey: {
    953            rawKey.u.ec.version.type = siUnsignedInteger;
    954            rawKey.u.ec.version.data = (unsigned char *)PORT_ArenaAlloc(arena, 1);
    955            if (!rawKey.u.ec.version.data) {
    956                goto loser;
    957            }
    958            rawKey.u.ec.version.data[0] = ecVersion;
    959            rawKey.u.ec.version.len = 1;
    960 
    961            SECItem curveOID;
    962            /* Read the component attributes of the private key */
    963            prepare_ec_priv_key_export_for_asn1(&rawKey);
    964            if (!ReadAttribute(pk, CKA_VALUE, arena,
    965                               &rawKey.u.ec.privateValue) ||
    966                !ReadAttribute(pk, CKA_EC_PARAMS, arena, &curveOID)) {
    967                goto loser;
    968            }
    969            if (!ReadAttribute(pk, CKA_EC_POINT, arena,
    970                               &rawKey.u.ec.publicValue)) {
    971                SECKEYPublicKey *pubk = SECKEY_ConvertToPublicKey(pk);
    972                if (pubk == NULL)
    973                    goto loser;
    974                rv = SECITEM_CopyItem(arena, &rawKey.u.ec.publicValue, &pubk->u.ec.publicValue);
    975                SECKEY_DestroyPublicKey(pubk);
    976                if (rv != SECSuccess) {
    977                    goto loser;
    978                }
    979            }
    980 
    981            keyTemplate = SECKEY_ECPrivateKeyExportTemplate;
    982            /* Convert length in bytes to length in bits. */
    983            rawKey.u.ec.publicValue.len <<= 3;
    984 
    985            rv = SECOID_SetAlgorithmID(arena, &pki->algorithm, SEC_OID_ANSIX962_EC_PUBLIC_KEY, &curveOID);
    986            if (rv != SECSuccess) {
    987                goto loser;
    988            }
    989 
    990        } break;
    991        case edKey: {
    992            if (!ReadAttribute(pk, CKA_VALUE, arena,
    993                               &rawKey.u.ec.privateValue)) {
    994                goto loser;
    995            }
    996 
    997            keyTemplate = SECKEY_ECRawPrivateKeyTemplate;
    998            /* Currently, Ed25519 does not support any parameter.  */
    999            rv = SECOID_SetAlgorithmID(arena, &pki->algorithm, SEC_OID_ED25519_PUBLIC_KEY, NULL);
   1000            if (rv != SECSuccess) {
   1001                goto loser;
   1002            }
   1003        } break;
   1004        case ecMontKey: {
   1005            if (!ReadAttribute(pk, CKA_VALUE, arena,
   1006                               &rawKey.u.ec.privateValue)) {
   1007                goto loser;
   1008            }
   1009 
   1010            keyTemplate = SECKEY_ECRawPrivateKeyTemplate;
   1011            /* Currently, X25519 does not support any parameter.  */
   1012            rv = SECOID_SetAlgorithmID(arena, &pki->algorithm, SEC_OID_X25519, NULL);
   1013            if (rv != SECSuccess) {
   1014                goto loser;
   1015            }
   1016        } break;
   1017        default: {
   1018            PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
   1019            goto loser;
   1020        }
   1021    }
   1022 
   1023    encoded = SEC_ASN1EncodeItem(arena, &pki->privateKey, &rawKey, keyTemplate);
   1024    if (!encoded) {
   1025        goto loser;
   1026    }
   1027    pki->version.type = siUnsignedInteger;
   1028    pki->version.data = (unsigned char *)PORT_ArenaAlloc(arena, 1);
   1029    if (!pki->version.data) {
   1030        goto loser;
   1031    }
   1032    pki->version.data[0] = pkiVersion;
   1033    pki->version.len = 1;
   1034    pki->arena = arena;
   1035 
   1036    return pki;
   1037 
   1038 loser:
   1039    if (arena) {
   1040        PORT_FreeArena(arena, PR_TRUE);
   1041    }
   1042    return NULL;
   1043 }