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