/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /* * This file PKCS #12 fuctions that should really be moved to the * PKCS #12 directory, however we can't do that in a point release * because that will break binary compatibility, so we keep them here for now. */ #include "seccomon.h" #include "secmod.h" #include "secmodi.h" #include "secmodti.h" #include "secmodt.h" #include "pkcs11.h" #include "pk11func.h" #include "secitem.h" #include "keyhi.h" #include "secoid.h" #include "secasn1.h" #include "secerr.h" #include "prerror.h" /* These data structures should move to a common .h file shared between the * wrappers and the pkcs 12 code. */ /* ** RSA Raw Private Key structures */ /* member names from PKCS#1, section 7.2 */ struct SECKEYRSAPrivateKeyStr { PLArenaPool *arena; SECItem version; SECItem modulus; SECItem publicExponent; SECItem privateExponent; SECItem prime1; SECItem prime2; SECItem exponent1; SECItem exponent2; SECItem coefficient; }; typedef struct SECKEYRSAPrivateKeyStr SECKEYRSAPrivateKey; /* ** DSA Raw Private Key structures */ struct SECKEYDSAPrivateKeyStr { SECKEYPQGParams params; SECItem privateValue; }; typedef struct SECKEYDSAPrivateKeyStr SECKEYDSAPrivateKey; /* ** Diffie-Hellman Raw Private Key structures ** Structure member names suggested by PKCS#3. */ struct SECKEYDHPrivateKeyStr { PLArenaPool *arena; SECItem prime; SECItem base; SECItem privateValue; }; typedef struct SECKEYDHPrivateKeyStr SECKEYDHPrivateKey; /* ** Elliptic Curve Private Key structures ** */ struct SECKEYECPrivateKeyStr { PLArenaPool *arena; SECItem version; SECItem curveOID; /* optional/ignored */ SECItem publicValue; /* required (for now) */ SECItem privateValue; }; typedef struct SECKEYECPrivateKeyStr SECKEYECPrivateKey; /* ** raw private key object */ struct SECKEYRawPrivateKeyStr { PLArenaPool *arena; KeyType keyType; union { SECKEYRSAPrivateKey rsa; SECKEYDSAPrivateKey dsa; SECKEYDHPrivateKey dh; SECKEYECPrivateKey ec; } u; }; typedef struct SECKEYRawPrivateKeyStr SECKEYRawPrivateKey; SEC_ASN1_MKSUB(SEC_AnyTemplate) SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate) /* ASN1 Templates for new decoder/encoder */ /* * Attribute value for PKCS8 entries (static?) */ const SEC_ASN1Template SECKEY_AttributeTemplate[] = { { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SECKEYAttribute) }, { SEC_ASN1_OBJECT_ID, offsetof(SECKEYAttribute, attrType) }, { SEC_ASN1_SET_OF | SEC_ASN1_XTRN, offsetof(SECKEYAttribute, attrValue), SEC_ASN1_SUB(SEC_AnyTemplate) }, { 0 } }; const SEC_ASN1Template SECKEY_SetOfAttributeTemplate[] = { { SEC_ASN1_SET_OF, 0, SECKEY_AttributeTemplate }, }; const SEC_ASN1Template SECKEY_PrivateKeyInfoTemplate[] = { { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SECKEYPrivateKeyInfo) }, { SEC_ASN1_INTEGER, offsetof(SECKEYPrivateKeyInfo, version) }, { SEC_ASN1_INLINE | SEC_ASN1_XTRN, offsetof(SECKEYPrivateKeyInfo, algorithm), SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) }, { SEC_ASN1_OCTET_STRING, offsetof(SECKEYPrivateKeyInfo, privateKey) }, { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0, offsetof(SECKEYPrivateKeyInfo, attributes), SECKEY_SetOfAttributeTemplate }, { 0 } }; const SEC_ASN1Template SECKEY_PointerToPrivateKeyInfoTemplate[] = { { SEC_ASN1_POINTER, 0, SECKEY_PrivateKeyInfoTemplate } }; const SEC_ASN1Template SECKEY_RSAPrivateKeyExportTemplate[] = { { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SECKEYRawPrivateKey) }, { SEC_ASN1_INTEGER, offsetof(SECKEYRawPrivateKey, u.rsa.version) }, { SEC_ASN1_INTEGER, offsetof(SECKEYRawPrivateKey, u.rsa.modulus) }, { SEC_ASN1_INTEGER, offsetof(SECKEYRawPrivateKey, u.rsa.publicExponent) }, { SEC_ASN1_INTEGER, offsetof(SECKEYRawPrivateKey, u.rsa.privateExponent) }, { SEC_ASN1_INTEGER, offsetof(SECKEYRawPrivateKey, u.rsa.prime1) }, { SEC_ASN1_INTEGER, offsetof(SECKEYRawPrivateKey, u.rsa.prime2) }, { SEC_ASN1_INTEGER, offsetof(SECKEYRawPrivateKey, u.rsa.exponent1) }, { SEC_ASN1_INTEGER, offsetof(SECKEYRawPrivateKey, u.rsa.exponent2) }, { SEC_ASN1_INTEGER, offsetof(SECKEYRawPrivateKey, u.rsa.coefficient) }, { 0 } }; const SEC_ASN1Template SECKEY_DSAPrivateKeyExportTemplate[] = { { SEC_ASN1_INTEGER, offsetof(SECKEYRawPrivateKey, u.dsa.privateValue) }, }; const SEC_ASN1Template SECKEY_DHPrivateKeyExportTemplate[] = { { SEC_ASN1_INTEGER, offsetof(SECKEYRawPrivateKey, u.dh.privateValue) }, { SEC_ASN1_INTEGER, offsetof(SECKEYRawPrivateKey, u.dh.base) }, { SEC_ASN1_INTEGER, offsetof(SECKEYRawPrivateKey, u.dh.prime) }, }; SEC_ASN1_MKSUB(SEC_BitStringTemplate) SEC_ASN1_MKSUB(SEC_ObjectIDTemplate) const SEC_ASN1Template SECKEY_ECPrivateKeyExportTemplate[] = { { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SECKEYRawPrivateKey) }, { SEC_ASN1_INTEGER, offsetof(SECKEYRawPrivateKey, u.ec.version) }, { SEC_ASN1_OCTET_STRING, offsetof(SECKEYRawPrivateKey, u.ec.privateValue) }, /* This value will always be ignored. u.ec.curveOID will always be * overriden with the outer AlgorithmID.parameters. */ { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_EXPLICIT | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 0, offsetof(SECKEYRawPrivateKey, u.ec.curveOID), SEC_ASN1_SUB(SEC_ObjectIDTemplate) }, /* The public value is optional per RFC, but required in NSS. We * can't do scalar mult on ECs to get a raw point with PK11 APIs. */ { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_EXPLICIT | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 1, offsetof(SECKEYRawPrivateKey, u.ec.publicValue), SEC_ASN1_SUB(SEC_BitStringTemplate) }, { 0 } }; const SEC_ASN1Template SECKEY_EncryptedPrivateKeyInfoTemplate[] = { { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SECKEYEncryptedPrivateKeyInfo) }, { SEC_ASN1_INLINE | SEC_ASN1_XTRN, offsetof(SECKEYEncryptedPrivateKeyInfo, algorithm), SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) }, { SEC_ASN1_OCTET_STRING, offsetof(SECKEYEncryptedPrivateKeyInfo, encryptedData) }, { 0 } }; const SEC_ASN1Template SECKEY_PointerToEncryptedPrivateKeyInfoTemplate[] = { { SEC_ASN1_POINTER, 0, SECKEY_EncryptedPrivateKeyInfoTemplate } }; SEC_ASN1_CHOOSER_IMPLEMENT(SECKEY_EncryptedPrivateKeyInfoTemplate) SEC_ASN1_CHOOSER_IMPLEMENT(SECKEY_PointerToEncryptedPrivateKeyInfoTemplate) SEC_ASN1_CHOOSER_IMPLEMENT(SECKEY_PrivateKeyInfoTemplate) SEC_ASN1_CHOOSER_IMPLEMENT(SECKEY_PointerToPrivateKeyInfoTemplate) /* * See bugzilla bug 125359 * Since NSS (via PKCS#11) wants to handle big integers as unsigned ints, * all of the templates above that en/decode into integers must be converted * from ASN.1's signed integer type. This is done by marking either the * source or destination (encoding or decoding, respectively) type as * siUnsignedInteger. */ static void prepare_rsa_priv_key_export_for_asn1(SECKEYRawPrivateKey *key) { key->u.rsa.modulus.type = siUnsignedInteger; key->u.rsa.publicExponent.type = siUnsignedInteger; key->u.rsa.privateExponent.type = siUnsignedInteger; key->u.rsa.prime1.type = siUnsignedInteger; key->u.rsa.prime2.type = siUnsignedInteger; key->u.rsa.exponent1.type = siUnsignedInteger; key->u.rsa.exponent2.type = siUnsignedInteger; key->u.rsa.coefficient.type = siUnsignedInteger; } static void prepare_dsa_priv_key_export_for_asn1(SECKEYRawPrivateKey *key) { key->u.dsa.privateValue.type = siUnsignedInteger; key->u.dsa.params.prime.type = siUnsignedInteger; key->u.dsa.params.subPrime.type = siUnsignedInteger; key->u.dsa.params.base.type = siUnsignedInteger; } static void prepare_dh_priv_key_export_for_asn1(SECKEYRawPrivateKey *key) { key->u.dh.privateValue.type = siUnsignedInteger; key->u.dh.prime.type = siUnsignedInteger; key->u.dh.base.type = siUnsignedInteger; } static void prepare_ec_priv_key_export_for_asn1(SECKEYRawPrivateKey *key) { key->u.ec.version.type = siUnsignedInteger; key->u.ec.curveOID.type = siUnsignedInteger; key->u.ec.privateValue.type = siUnsignedInteger; key->u.ec.publicValue.type = siUnsignedInteger; } SECStatus PK11_ImportDERPrivateKeyInfo(PK11SlotInfo *slot, SECItem *derPKI, SECItem *nickname, SECItem *publicValue, PRBool isPerm, PRBool isPrivate, unsigned int keyUsage, void *wincx) { return PK11_ImportDERPrivateKeyInfoAndReturnKey(slot, derPKI, nickname, publicValue, isPerm, isPrivate, keyUsage, NULL, wincx); } SECStatus PK11_ImportDERPrivateKeyInfoAndReturnKey(PK11SlotInfo *slot, SECItem *derPKI, SECItem *nickname, SECItem *publicValue, PRBool isPerm, PRBool isPrivate, unsigned int keyUsage, SECKEYPrivateKey **privk, void *wincx) { SECKEYPrivateKeyInfo *pki = NULL; PLArenaPool *temparena = NULL; SECStatus rv = SECFailure; temparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); if (!temparena) return rv; pki = PORT_ArenaZNew(temparena, SECKEYPrivateKeyInfo); if (!pki) { PORT_FreeArena(temparena, PR_FALSE); return rv; } pki->arena = temparena; rv = SEC_ASN1DecodeItem(pki->arena, pki, SECKEY_PrivateKeyInfoTemplate, derPKI); if (rv != SECSuccess) { /* If SEC_ASN1DecodeItem fails, we cannot assume anything about the * validity of the data in pki. The best we can do is free the arena * and return. */ PORT_FreeArena(temparena, PR_TRUE); return rv; } if (pki->privateKey.data == NULL) { /* If SEC_ASN1DecodeItems succeeds but SECKEYPrivateKeyInfo.privateKey * is a zero-length octet string, free the arena and return a failure * to avoid trying to zero the corresponding SECItem in * SECKEY_DestroyPrivateKeyInfo(). */ PORT_FreeArena(temparena, PR_TRUE); PORT_SetError(SEC_ERROR_BAD_KEY); return SECFailure; } rv = PK11_ImportPrivateKeyInfoAndReturnKey(slot, pki, nickname, publicValue, isPerm, isPrivate, keyUsage, privk, wincx); /* this zeroes the key and frees the arena */ SECKEY_DestroyPrivateKeyInfo(pki, PR_TRUE /*freeit*/); return rv; } SECStatus PK11_ImportAndReturnPrivateKey(PK11SlotInfo *slot, SECKEYRawPrivateKey *lpk, SECItem *nickname, SECItem *publicValue, PRBool isPerm, PRBool isPrivate, unsigned int keyUsage, SECKEYPrivateKey **privk, void *wincx) { CK_BBOOL cktrue = CK_TRUE; CK_BBOOL ckfalse = CK_FALSE; CK_OBJECT_CLASS keyClass = CKO_PRIVATE_KEY; CK_KEY_TYPE keyType = CKK_RSA; CK_OBJECT_HANDLE objectID; CK_ATTRIBUTE theTemplate[20]; int templateCount = 0; SECStatus rv = SECFailure; CK_ATTRIBUTE *attrs; CK_ATTRIBUTE *signedattr = NULL; int signedcount = 0; CK_ATTRIBUTE *ap; SECItem *ck_id = NULL; attrs = theTemplate; PK11_SETATTRS(attrs, CKA_CLASS, &keyClass, sizeof(keyClass)); attrs++; PK11_SETATTRS(attrs, CKA_KEY_TYPE, &keyType, sizeof(keyType)); attrs++; PK11_SETATTRS(attrs, CKA_TOKEN, isPerm ? &cktrue : &ckfalse, sizeof(CK_BBOOL)); attrs++; PK11_SETATTRS(attrs, CKA_SENSITIVE, isPrivate ? &cktrue : &ckfalse, sizeof(CK_BBOOL)); attrs++; PK11_SETATTRS(attrs, CKA_PRIVATE, isPrivate ? &cktrue : &ckfalse, sizeof(CK_BBOOL)); attrs++; switch (lpk->keyType) { case rsaKey: keyType = CKK_RSA; PK11_SETATTRS(attrs, CKA_UNWRAP, (keyUsage & KU_KEY_ENCIPHERMENT) ? &cktrue : &ckfalse, sizeof(CK_BBOOL)); attrs++; PK11_SETATTRS(attrs, CKA_DECRYPT, (keyUsage & KU_DATA_ENCIPHERMENT) ? &cktrue : &ckfalse, sizeof(CK_BBOOL)); attrs++; PK11_SETATTRS(attrs, CKA_SIGN, (keyUsage & KU_DIGITAL_SIGNATURE) ? &cktrue : &ckfalse, sizeof(CK_BBOOL)); attrs++; PK11_SETATTRS(attrs, CKA_SIGN_RECOVER, (keyUsage & KU_DIGITAL_SIGNATURE) ? &cktrue : &ckfalse, sizeof(CK_BBOOL)); attrs++; ck_id = PK11_MakeIDFromPubKey(&lpk->u.rsa.modulus); if (ck_id == NULL) { goto loser; } PK11_SETATTRS(attrs, CKA_ID, ck_id->data, ck_id->len); attrs++; if (nickname) { PK11_SETATTRS(attrs, CKA_LABEL, nickname->data, nickname->len); attrs++; } signedattr = attrs; PK11_SETATTRS(attrs, CKA_MODULUS, lpk->u.rsa.modulus.data, lpk->u.rsa.modulus.len); attrs++; PK11_SETATTRS(attrs, CKA_PUBLIC_EXPONENT, lpk->u.rsa.publicExponent.data, lpk->u.rsa.publicExponent.len); attrs++; PK11_SETATTRS(attrs, CKA_PRIVATE_EXPONENT, lpk->u.rsa.privateExponent.data, lpk->u.rsa.privateExponent.len); attrs++; PK11_SETATTRS(attrs, CKA_PRIME_1, lpk->u.rsa.prime1.data, lpk->u.rsa.prime1.len); attrs++; PK11_SETATTRS(attrs, CKA_PRIME_2, lpk->u.rsa.prime2.data, lpk->u.rsa.prime2.len); attrs++; PK11_SETATTRS(attrs, CKA_EXPONENT_1, lpk->u.rsa.exponent1.data, lpk->u.rsa.exponent1.len); attrs++; PK11_SETATTRS(attrs, CKA_EXPONENT_2, lpk->u.rsa.exponent2.data, lpk->u.rsa.exponent2.len); attrs++; PK11_SETATTRS(attrs, CKA_COEFFICIENT, lpk->u.rsa.coefficient.data, lpk->u.rsa.coefficient.len); attrs++; break; case dsaKey: keyType = CKK_DSA; /* To make our intenal PKCS #11 module work correctly with * our database, we need to pass in the public key value for * this dsa key. We have a netscape only CKA_ value to do this. * Only send it to internal slots */ if (publicValue == NULL) { goto loser; } if (PK11_IsInternal(slot)) { PK11_SETATTRS(attrs, CKA_NSS_DB, publicValue->data, publicValue->len); attrs++; } PK11_SETATTRS(attrs, CKA_SIGN, &cktrue, sizeof(CK_BBOOL)); attrs++; PK11_SETATTRS(attrs, CKA_SIGN_RECOVER, &cktrue, sizeof(CK_BBOOL)); attrs++; if (nickname) { PK11_SETATTRS(attrs, CKA_LABEL, nickname->data, nickname->len); attrs++; } ck_id = PK11_MakeIDFromPubKey(publicValue); if (ck_id == NULL) { goto loser; } PK11_SETATTRS(attrs, CKA_ID, ck_id->data, ck_id->len); attrs++; signedattr = attrs; PK11_SETATTRS(attrs, CKA_PRIME, lpk->u.dsa.params.prime.data, lpk->u.dsa.params.prime.len); attrs++; PK11_SETATTRS(attrs, CKA_SUBPRIME, lpk->u.dsa.params.subPrime.data, lpk->u.dsa.params.subPrime.len); attrs++; PK11_SETATTRS(attrs, CKA_BASE, lpk->u.dsa.params.base.data, lpk->u.dsa.params.base.len); attrs++; PK11_SETATTRS(attrs, CKA_VALUE, lpk->u.dsa.privateValue.data, lpk->u.dsa.privateValue.len); attrs++; break; case dhKey: keyType = CKK_DH; /* To make our intenal PKCS #11 module work correctly with * our database, we need to pass in the public key value for * this dh key. We have a netscape only CKA_ value to do this. * Only send it to internal slots */ if (PK11_IsInternal(slot)) { PK11_SETATTRS(attrs, CKA_NSS_DB, publicValue->data, publicValue->len); attrs++; } PK11_SETATTRS(attrs, CKA_DERIVE, &cktrue, sizeof(CK_BBOOL)); attrs++; if (nickname) { PK11_SETATTRS(attrs, CKA_LABEL, nickname->data, nickname->len); attrs++; } ck_id = PK11_MakeIDFromPubKey(publicValue); if (ck_id == NULL) { goto loser; } PK11_SETATTRS(attrs, CKA_ID, ck_id->data, ck_id->len); attrs++; signedattr = attrs; PK11_SETATTRS(attrs, CKA_PRIME, lpk->u.dh.prime.data, lpk->u.dh.prime.len); attrs++; PK11_SETATTRS(attrs, CKA_BASE, lpk->u.dh.base.data, lpk->u.dh.base.len); attrs++; PK11_SETATTRS(attrs, CKA_VALUE, lpk->u.dh.privateValue.data, lpk->u.dh.privateValue.len); attrs++; break; case ecKey: keyType = CKK_EC; if (lpk->u.ec.publicValue.len == 0) { goto loser; } if (PK11_IsInternal(slot)) { PK11_SETATTRS(attrs, CKA_NSS_DB, lpk->u.ec.publicValue.data, lpk->u.ec.publicValue.len); attrs++; } PK11_SETATTRS(attrs, CKA_SIGN, (keyUsage & KU_DIGITAL_SIGNATURE) ? &cktrue : &ckfalse, sizeof(CK_BBOOL)); attrs++; PK11_SETATTRS(attrs, CKA_SIGN_RECOVER, (keyUsage & KU_DIGITAL_SIGNATURE) ? &cktrue : &ckfalse, sizeof(CK_BBOOL)); attrs++; PK11_SETATTRS(attrs, CKA_DERIVE, (keyUsage & KU_KEY_AGREEMENT) ? &cktrue : &ckfalse, sizeof(CK_BBOOL)); attrs++; if (nickname) { PK11_SETATTRS(attrs, CKA_LABEL, nickname->data, nickname->len); attrs++; } ck_id = PK11_MakeIDFromPubKey(&lpk->u.ec.publicValue); if (ck_id == NULL) { goto loser; } PK11_SETATTRS(attrs, CKA_ID, ck_id->data, ck_id->len); attrs++; /* No signed attrs for EC */ /* curveOID always is a copy of AlgorithmID.parameters. */ PK11_SETATTRS(attrs, CKA_EC_PARAMS, lpk->u.ec.curveOID.data, lpk->u.ec.curveOID.len); attrs++; PK11_SETATTRS(attrs, CKA_VALUE, lpk->u.ec.privateValue.data, lpk->u.ec.privateValue.len); attrs++; PK11_SETATTRS(attrs, CKA_EC_POINT, lpk->u.ec.publicValue.data, lpk->u.ec.publicValue.len); attrs++; break; default: PORT_SetError(SEC_ERROR_BAD_KEY); goto loser; } templateCount = attrs - theTemplate; PORT_Assert(templateCount <= sizeof(theTemplate) / sizeof(CK_ATTRIBUTE)); if (lpk->keyType != ecKey) { PORT_Assert(signedattr); signedcount = attrs - signedattr; for (ap = signedattr; signedcount; ap++, signedcount--) { pk11_SignedToUnsigned(ap); } } rv = PK11_CreateNewObject(slot, CK_INVALID_HANDLE, theTemplate, templateCount, isPerm, &objectID); /* create and return a SECKEYPrivateKey */ if (rv == SECSuccess && privk != NULL) { *privk = PK11_MakePrivKey(slot, lpk->keyType, !isPerm, objectID, wincx); if (*privk == NULL) { rv = SECFailure; } } loser: if (ck_id) { SECITEM_ZfreeItem(ck_id, PR_TRUE); } return rv; } SECStatus PK11_ImportPrivateKeyInfoAndReturnKey(PK11SlotInfo *slot, SECKEYPrivateKeyInfo *pki, SECItem *nickname, SECItem *publicValue, PRBool isPerm, PRBool isPrivate, unsigned int keyUsage, SECKEYPrivateKey **privk, void *wincx) { SECStatus rv = SECFailure; SECKEYRawPrivateKey *lpk = NULL; const SEC_ASN1Template *keyTemplate, *paramTemplate; void *paramDest = NULL; PLArenaPool *arena = NULL; arena = PORT_NewArena(2048); if (!arena) { return SECFailure; } /* need to change this to use RSA/DSA keys */ lpk = (SECKEYRawPrivateKey *)PORT_ArenaZAlloc(arena, sizeof(SECKEYRawPrivateKey)); if (lpk == NULL) { goto loser; } lpk->arena = arena; switch (SECOID_GetAlgorithmTag(&pki->algorithm)) { case SEC_OID_PKCS1_RSA_ENCRYPTION: prepare_rsa_priv_key_export_for_asn1(lpk); keyTemplate = SECKEY_RSAPrivateKeyExportTemplate; paramTemplate = NULL; paramDest = NULL; lpk->keyType = rsaKey; break; case SEC_OID_ANSIX9_DSA_SIGNATURE: prepare_dsa_priv_key_export_for_asn1(lpk); keyTemplate = SECKEY_DSAPrivateKeyExportTemplate; paramTemplate = SECKEY_PQGParamsTemplate; paramDest = &(lpk->u.dsa.params); lpk->keyType = dsaKey; break; case SEC_OID_X942_DIFFIE_HELMAN_KEY: if (!publicValue) { goto loser; } prepare_dh_priv_key_export_for_asn1(lpk); keyTemplate = SECKEY_DHPrivateKeyExportTemplate; paramTemplate = NULL; paramDest = NULL; lpk->keyType = dhKey; break; case SEC_OID_ANSIX962_EC_PUBLIC_KEY: prepare_ec_priv_key_export_for_asn1(lpk); keyTemplate = SECKEY_ECPrivateKeyExportTemplate; paramTemplate = NULL; paramDest = NULL; lpk->keyType = ecKey; break; default: keyTemplate = NULL; paramTemplate = NULL; paramDest = NULL; break; } if (!keyTemplate) { goto loser; } /* decode the private key and any algorithm parameters */ rv = SEC_QuickDERDecodeItem(arena, lpk, keyTemplate, &pki->privateKey); if (rv != SECSuccess) { goto loser; } if (lpk->keyType == ecKey) { /* Convert length in bits to length in bytes. */ lpk->u.ec.publicValue.len >>= 3; /* Always override curveOID, we're ignoring any given value. */ rv = SECITEM_CopyItem(arena, &lpk->u.ec.curveOID, &pki->algorithm.parameters); if (rv != SECSuccess) { goto loser; } } if (paramDest && paramTemplate) { rv = SEC_ASN1DecodeItem(arena, paramDest, paramTemplate, &(pki->algorithm.parameters)); if (rv != SECSuccess) { goto loser; } } rv = PK11_ImportAndReturnPrivateKey(slot, lpk, nickname, publicValue, isPerm, isPrivate, keyUsage, privk, wincx); loser: if (arena != NULL) { PORT_FreeArena(arena, PR_TRUE); } return rv; } SECStatus PK11_ImportPrivateKeyInfo(PK11SlotInfo *slot, SECKEYPrivateKeyInfo *pki, SECItem *nickname, SECItem *publicValue, PRBool isPerm, PRBool isPrivate, unsigned int keyUsage, void *wincx) { return PK11_ImportPrivateKeyInfoAndReturnKey(slot, pki, nickname, publicValue, isPerm, isPrivate, keyUsage, NULL, wincx); } SECItem * PK11_ExportDERPrivateKeyInfo(SECKEYPrivateKey *pk, void *wincx) { SECKEYPrivateKeyInfo *pki = PK11_ExportPrivKeyInfo(pk, wincx); SECItem *derPKI; if (!pki) { return NULL; } derPKI = SEC_ASN1EncodeItem(NULL, NULL, pki, SECKEY_PrivateKeyInfoTemplate); SECKEY_DestroyPrivateKeyInfo(pki, PR_TRUE); return derPKI; } static PRBool ReadAttribute(SECKEYPrivateKey *key, CK_ATTRIBUTE_TYPE type, PLArenaPool *arena, SECItem *output) { SECStatus rv = PK11_ReadAttribute(key->pkcs11Slot, key->pkcs11ID, type, arena, output); return rv == SECSuccess; } /* * The caller is responsible for freeing the return value by passing it to * SECKEY_DestroyPrivateKeyInfo(..., PR_TRUE). */ SECKEYPrivateKeyInfo * PK11_ExportPrivKeyInfo(SECKEYPrivateKey *pk, void *wincx) { /* PrivateKeyInfo version (always zero) */ const unsigned char pkiVersion = 0; /* RSAPrivateKey version (always zero) */ const unsigned char rsaVersion = 0; /* ECPrivateKey version (always one) */ const unsigned char ecVersion = 1; PLArenaPool *arena = NULL; SECKEYRawPrivateKey rawKey; SECKEYPrivateKeyInfo *pki; SECItem *encoded; const SEC_ASN1Template *keyTemplate; SECStatus rv; arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); if (!arena) { goto loser; } memset(&rawKey, 0, sizeof(rawKey)); rawKey.keyType = pk->keyType; pki = PORT_ArenaZNew(arena, SECKEYPrivateKeyInfo); if (!pki) { goto loser; } switch (pk->keyType) { case rsaKey: { rawKey.u.rsa.version.type = siUnsignedInteger; rawKey.u.rsa.version.data = (unsigned char *)PORT_ArenaAlloc(arena, 1); if (!rawKey.u.rsa.version.data) { goto loser; } rawKey.u.rsa.version.data[0] = rsaVersion; rawKey.u.rsa.version.len = 1; /* Read the component attributes of the private key */ prepare_rsa_priv_key_export_for_asn1(&rawKey); if (!ReadAttribute(pk, CKA_MODULUS, arena, &rawKey.u.rsa.modulus) || !ReadAttribute(pk, CKA_PUBLIC_EXPONENT, arena, &rawKey.u.rsa.publicExponent) || !ReadAttribute(pk, CKA_PRIVATE_EXPONENT, arena, &rawKey.u.rsa.privateExponent) || !ReadAttribute(pk, CKA_PRIME_1, arena, &rawKey.u.rsa.prime1) || !ReadAttribute(pk, CKA_PRIME_2, arena, &rawKey.u.rsa.prime2) || !ReadAttribute(pk, CKA_EXPONENT_1, arena, &rawKey.u.rsa.exponent1) || !ReadAttribute(pk, CKA_EXPONENT_2, arena, &rawKey.u.rsa.exponent2) || !ReadAttribute(pk, CKA_COEFFICIENT, arena, &rawKey.u.rsa.coefficient)) { goto loser; } keyTemplate = SECKEY_RSAPrivateKeyExportTemplate; rv = SECOID_SetAlgorithmID(arena, &pki->algorithm, SEC_OID_PKCS1_RSA_ENCRYPTION, NULL); if (rv != SECSuccess) { goto loser; } } break; case ecKey: { rawKey.u.ec.version.type = siUnsignedInteger; rawKey.u.ec.version.data = (unsigned char *)PORT_ArenaAlloc(arena, 1); if (!rawKey.u.ec.version.data) { goto loser; } rawKey.u.ec.version.data[0] = ecVersion; rawKey.u.ec.version.len = 1; SECItem curveOID; /* Read the component attributes of the private key */ prepare_ec_priv_key_export_for_asn1(&rawKey); if (!ReadAttribute(pk, CKA_VALUE, arena, &rawKey.u.ec.privateValue) || !ReadAttribute(pk, CKA_EC_PARAMS, arena, &curveOID)) { goto loser; } if (!ReadAttribute(pk, CKA_EC_POINT, arena, &rawKey.u.ec.publicValue)) { SECKEYPublicKey *pubk = SECKEY_ConvertToPublicKey(pk); if (pubk == NULL) goto loser; rv = SECITEM_CopyItem(arena, &rawKey.u.ec.publicValue, &pubk->u.ec.publicValue); SECKEY_DestroyPublicKey(pubk); if (rv != SECSuccess) { goto loser; } } keyTemplate = SECKEY_ECPrivateKeyExportTemplate; /* Convert length in bytes to length in bits. */ rawKey.u.ec.publicValue.len <<= 3; rv = SECOID_SetAlgorithmID(arena, &pki->algorithm, SEC_OID_ANSIX962_EC_PUBLIC_KEY, &curveOID); if (rv != SECSuccess) { goto loser; } } break; default: { PORT_SetError(PR_NOT_IMPLEMENTED_ERROR); goto loser; } } encoded = SEC_ASN1EncodeItem(arena, &pki->privateKey, &rawKey, keyTemplate); if (!encoded) { goto loser; } pki->version.type = siUnsignedInteger; pki->version.data = (unsigned char *)PORT_ArenaAlloc(arena, 1); if (!pki->version.data) { goto loser; } pki->version.data[0] = pkiVersion; pki->version.len = 1; pki->arena = arena; return pki; loser: if (arena) { PORT_FreeArena(arena, PR_TRUE); } return NULL; }