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