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: #include "cryptohi.h" andre@0: #include "keyhi.h" andre@0: #include "secoid.h" andre@0: #include "secitem.h" andre@0: #include "secder.h" andre@0: #include "base64.h" andre@0: #include "secasn1.h" andre@0: #include "cert.h" andre@0: #include "pk11func.h" andre@0: #include "secerr.h" andre@0: #include "secdig.h" andre@0: #include "prtime.h" andre@0: #include "keyi.h" andre@0: andre@0: SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate) andre@0: SEC_ASN1_MKSUB(SEC_IntegerTemplate) andre@0: andre@0: const SEC_ASN1Template CERT_SubjectPublicKeyInfoTemplate[] = { andre@0: { SEC_ASN1_SEQUENCE, andre@0: 0, NULL, sizeof(CERTSubjectPublicKeyInfo) }, andre@0: { SEC_ASN1_INLINE | SEC_ASN1_XTRN, andre@0: offsetof(CERTSubjectPublicKeyInfo,algorithm), andre@0: SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) }, andre@0: { SEC_ASN1_BIT_STRING, andre@0: offsetof(CERTSubjectPublicKeyInfo,subjectPublicKey), }, andre@0: { 0, } andre@0: }; andre@0: andre@0: const SEC_ASN1Template CERT_PublicKeyAndChallengeTemplate[] = andre@0: { andre@0: { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CERTPublicKeyAndChallenge) }, andre@0: { SEC_ASN1_ANY, offsetof(CERTPublicKeyAndChallenge,spki) }, andre@0: { SEC_ASN1_IA5_STRING, offsetof(CERTPublicKeyAndChallenge,challenge) }, andre@0: { 0 } andre@0: }; andre@0: andre@0: const SEC_ASN1Template SECKEY_RSAPublicKeyTemplate[] = { andre@0: { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SECKEYPublicKey) }, andre@0: { SEC_ASN1_INTEGER, offsetof(SECKEYPublicKey,u.rsa.modulus), }, andre@0: { SEC_ASN1_INTEGER, offsetof(SECKEYPublicKey,u.rsa.publicExponent), }, andre@0: { 0, } andre@0: }; andre@0: andre@0: static const SEC_ASN1Template seckey_PointerToAlgorithmIDTemplate[] = { andre@0: { SEC_ASN1_POINTER | SEC_ASN1_XTRN, 0, andre@0: SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) } andre@0: }; andre@0: andre@0: /* Parameters for SEC_OID_PKCS1_RSA_PSS_SIGNATURE */ andre@0: const SEC_ASN1Template SECKEY_RSAPSSParamsTemplate[] = andre@0: { andre@0: { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SECKEYRSAPSSParams) }, andre@0: { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_EXPLICIT | andre@0: SEC_ASN1_CONTEXT_SPECIFIC | 0, andre@0: offsetof(SECKEYRSAPSSParams, hashAlg), andre@0: seckey_PointerToAlgorithmIDTemplate }, andre@0: { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_EXPLICIT | andre@0: SEC_ASN1_CONTEXT_SPECIFIC | 1, andre@0: offsetof(SECKEYRSAPSSParams, maskAlg), andre@0: seckey_PointerToAlgorithmIDTemplate }, andre@0: { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_EXPLICIT | andre@0: SEC_ASN1_XTRN | SEC_ASN1_CONTEXT_SPECIFIC | 2, andre@0: offsetof(SECKEYRSAPSSParams, saltLength), andre@0: SEC_ASN1_SUB(SEC_IntegerTemplate) }, andre@0: { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_EXPLICIT | andre@0: SEC_ASN1_XTRN | SEC_ASN1_CONTEXT_SPECIFIC | 3, andre@0: offsetof(SECKEYRSAPSSParams, trailerField), andre@0: SEC_ASN1_SUB(SEC_IntegerTemplate) }, andre@0: { 0 } andre@0: }; andre@0: andre@0: const SEC_ASN1Template SECKEY_DSAPublicKeyTemplate[] = { andre@0: { SEC_ASN1_INTEGER, offsetof(SECKEYPublicKey,u.dsa.publicValue), }, andre@0: { 0, } andre@0: }; andre@0: andre@0: const SEC_ASN1Template SECKEY_PQGParamsTemplate[] = { andre@0: { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SECKEYPQGParams) }, andre@0: { SEC_ASN1_INTEGER, offsetof(SECKEYPQGParams,prime) }, andre@0: { SEC_ASN1_INTEGER, offsetof(SECKEYPQGParams,subPrime) }, andre@0: { SEC_ASN1_INTEGER, offsetof(SECKEYPQGParams,base) }, andre@0: { 0, } andre@0: }; andre@0: andre@0: const SEC_ASN1Template SECKEY_DHPublicKeyTemplate[] = { andre@0: { SEC_ASN1_INTEGER, offsetof(SECKEYPublicKey,u.dh.publicValue), }, andre@0: { 0, } andre@0: }; andre@0: andre@0: const SEC_ASN1Template SECKEY_DHParamKeyTemplate[] = { andre@0: { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SECKEYPublicKey) }, andre@0: { SEC_ASN1_INTEGER, offsetof(SECKEYPublicKey,u.dh.prime), }, andre@0: { SEC_ASN1_INTEGER, offsetof(SECKEYPublicKey,u.dh.base), }, andre@0: /* XXX chrisk: this needs to be expanded for decoding of j and validationParms (RFC2459 7.3.2) */ andre@0: { SEC_ASN1_SKIP_REST }, andre@0: { 0, } andre@0: }; andre@0: andre@0: SEC_ASN1_CHOOSER_IMPLEMENT(SECKEY_DSAPublicKeyTemplate) andre@0: SEC_ASN1_CHOOSER_IMPLEMENT(SECKEY_RSAPublicKeyTemplate) andre@0: SEC_ASN1_CHOOSER_IMPLEMENT(SECKEY_RSAPSSParamsTemplate) andre@0: SEC_ASN1_CHOOSER_IMPLEMENT(CERT_SubjectPublicKeyInfoTemplate) 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: static void andre@0: prepare_rsa_pub_key_for_asn1(SECKEYPublicKey *pubk) andre@0: { andre@0: pubk->u.rsa.modulus.type = siUnsignedInteger; andre@0: pubk->u.rsa.publicExponent.type = siUnsignedInteger; andre@0: } andre@0: andre@0: static void andre@0: prepare_dsa_pub_key_for_asn1(SECKEYPublicKey *pubk) andre@0: { andre@0: pubk->u.dsa.publicValue.type = siUnsignedInteger; andre@0: } andre@0: andre@0: static void andre@0: prepare_pqg_params_for_asn1(SECKEYPQGParams *params) andre@0: { andre@0: params->prime.type = siUnsignedInteger; andre@0: params->subPrime.type = siUnsignedInteger; andre@0: params->base.type = siUnsignedInteger; andre@0: } andre@0: andre@0: static void andre@0: prepare_dh_pub_key_for_asn1(SECKEYPublicKey *pubk) andre@0: { andre@0: pubk->u.dh.prime.type = siUnsignedInteger; andre@0: pubk->u.dh.base.type = siUnsignedInteger; andre@0: pubk->u.dh.publicValue.type = siUnsignedInteger; andre@0: } andre@0: andre@0: /* Create an RSA key pair is any slot able to do so. andre@0: ** The created keys are "session" (temporary), not "token" (permanent), andre@0: ** and they are "sensitive", which makes them costly to move to another token. andre@0: */ andre@0: SECKEYPrivateKey * andre@0: SECKEY_CreateRSAPrivateKey(int keySizeInBits,SECKEYPublicKey **pubk, void *cx) andre@0: { andre@0: SECKEYPrivateKey *privk; andre@0: PK11RSAGenParams param; andre@0: PK11SlotInfo *slot = PK11_GetBestSlot(CKM_RSA_PKCS_KEY_PAIR_GEN,cx); andre@0: if (!slot) { andre@0: return NULL; andre@0: } andre@0: andre@0: param.keySizeInBits = keySizeInBits; andre@0: param.pe = 65537L; andre@0: andre@0: privk = PK11_GenerateKeyPair(slot,CKM_RSA_PKCS_KEY_PAIR_GEN,¶m,pubk, andre@0: PR_FALSE, PR_TRUE, cx); andre@0: PK11_FreeSlot(slot); andre@0: return(privk); andre@0: } andre@0: andre@0: /* Create a DH key pair in any slot able to do so, andre@0: ** This is a "session" (temporary), not "token" (permanent) key. andre@0: ** Because of the high probability that this key will need to be moved to andre@0: ** another token, and the high cost of moving "sensitive" keys, we attempt andre@0: ** to create this key pair without the "sensitive" attribute, but revert to andre@0: ** creating a "sensitive" key if necessary. andre@0: */ andre@0: SECKEYPrivateKey * andre@0: SECKEY_CreateDHPrivateKey(SECKEYDHParams *param, SECKEYPublicKey **pubk, void *cx) andre@0: { andre@0: SECKEYPrivateKey *privk; andre@0: PK11SlotInfo *slot; andre@0: andre@0: if (!param || !param->base.data || !param->prime.data || andre@0: param->prime.len < 512/8 || param->base.len == 0 || andre@0: param->base.len > param->prime.len + 1 || andre@0: (param->base.len == 1 && param->base.data[0] == 0)) { andre@0: PORT_SetError(SEC_ERROR_INVALID_ARGS); andre@0: return NULL; andre@0: } andre@0: andre@0: slot = PK11_GetBestSlot(CKM_DH_PKCS_KEY_PAIR_GEN,cx); andre@0: if (!slot) { andre@0: return NULL; andre@0: } andre@0: andre@0: privk = PK11_GenerateKeyPair(slot, CKM_DH_PKCS_KEY_PAIR_GEN, param, andre@0: pubk, PR_FALSE, PR_FALSE, cx); andre@0: if (!privk) andre@0: privk = PK11_GenerateKeyPair(slot, CKM_DH_PKCS_KEY_PAIR_GEN, param, andre@0: pubk, PR_FALSE, PR_TRUE, cx); andre@0: andre@0: PK11_FreeSlot(slot); andre@0: return(privk); andre@0: } andre@0: andre@0: /* Create an EC key pair in any slot able to do so, andre@0: ** This is a "session" (temporary), not "token" (permanent) key. andre@0: ** Because of the high probability that this key will need to be moved to andre@0: ** another token, and the high cost of moving "sensitive" keys, we attempt andre@0: ** to create this key pair without the "sensitive" attribute, but revert to andre@0: ** creating a "sensitive" key if necessary. andre@0: */ andre@0: SECKEYPrivateKey * andre@0: SECKEY_CreateECPrivateKey(SECKEYECParams *param, SECKEYPublicKey **pubk, void *cx) andre@0: { andre@0: SECKEYPrivateKey *privk; andre@0: PK11SlotInfo *slot = PK11_GetBestSlot(CKM_EC_KEY_PAIR_GEN,cx); andre@0: if (!slot) { andre@0: return NULL; andre@0: } andre@0: andre@0: privk = PK11_GenerateKeyPairWithOpFlags(slot, CKM_EC_KEY_PAIR_GEN, andre@0: param, pubk, andre@0: PK11_ATTR_SESSION | PK11_ATTR_INSENSITIVE | andre@0: PK11_ATTR_PUBLIC, andre@0: CKF_DERIVE, CKF_DERIVE|CKF_SIGN,cx); andre@0: if (!privk) andre@0: privk = PK11_GenerateKeyPairWithOpFlags(slot, CKM_EC_KEY_PAIR_GEN, andre@0: param, pubk, andre@0: PK11_ATTR_SESSION | PK11_ATTR_SENSITIVE | andre@0: PK11_ATTR_PRIVATE, andre@0: CKF_DERIVE, CKF_DERIVE|CKF_SIGN,cx); andre@0: andre@0: PK11_FreeSlot(slot); andre@0: return(privk); andre@0: } andre@0: andre@0: void andre@0: SECKEY_DestroyPrivateKey(SECKEYPrivateKey *privk) andre@0: { andre@0: if (privk) { andre@0: if (privk->pkcs11Slot) { andre@0: if (privk->pkcs11IsTemp) { andre@0: PK11_DestroyObject(privk->pkcs11Slot,privk->pkcs11ID); andre@0: } andre@0: PK11_FreeSlot(privk->pkcs11Slot); andre@0: andre@0: } andre@0: if (privk->arena) { andre@0: PORT_FreeArena(privk->arena, PR_TRUE); andre@0: } andre@0: } andre@0: } andre@0: andre@0: void andre@0: SECKEY_DestroyPublicKey(SECKEYPublicKey *pubk) andre@0: { andre@0: if (pubk) { andre@0: if (pubk->pkcs11Slot) { andre@0: if (!PK11_IsPermObject(pubk->pkcs11Slot,pubk->pkcs11ID)) { andre@0: PK11_DestroyObject(pubk->pkcs11Slot,pubk->pkcs11ID); andre@0: } andre@0: PK11_FreeSlot(pubk->pkcs11Slot); andre@0: } andre@0: if (pubk->arena) { andre@0: PORT_FreeArena(pubk->arena, PR_FALSE); andre@0: } andre@0: } andre@0: } andre@0: andre@0: SECStatus andre@0: SECKEY_CopySubjectPublicKeyInfo(PLArenaPool *arena, andre@0: CERTSubjectPublicKeyInfo *to, andre@0: CERTSubjectPublicKeyInfo *from) andre@0: { andre@0: SECStatus rv; andre@0: SECItem spk; andre@0: andre@0: rv = SECOID_CopyAlgorithmID(arena, &to->algorithm, &from->algorithm); andre@0: if (rv == SECSuccess) { andre@0: /* andre@0: * subjectPublicKey is a bit string, whose length is in bits. andre@0: * Convert the length from bits to bytes for SECITEM_CopyItem. andre@0: */ andre@0: spk = from->subjectPublicKey; andre@0: DER_ConvertBitString(&spk); andre@0: rv = SECITEM_CopyItem(arena, &to->subjectPublicKey, &spk); andre@0: /* Set the length back to bits. */ andre@0: if (rv == SECSuccess) { andre@0: to->subjectPublicKey.len = from->subjectPublicKey.len; andre@0: } andre@0: } andre@0: andre@0: return rv; andre@0: } andre@0: andre@0: /* Procedure to update the pqg parameters for a cert's public key. andre@0: * pqg parameters only need to be updated for DSA certificates. andre@0: * The procedure uses calls to itself recursively to update a certificate andre@0: * issuer's pqg parameters. Some important rules are: andre@0: * - Do nothing if the cert already has PQG parameters. andre@0: * - If the cert does not have PQG parameters, obtain them from the issuer. andre@0: * - A valid cert chain cannot have a DSA cert without andre@0: * pqg parameters that has a parent that is not a DSA cert. */ andre@0: andre@0: static SECStatus andre@0: seckey_UpdateCertPQGChain(CERTCertificate * subjectCert, int count) andre@0: { andre@0: SECStatus rv; andre@0: SECOidData *oid=NULL; andre@0: int tag; andre@0: CERTSubjectPublicKeyInfo * subjectSpki=NULL; andre@0: CERTSubjectPublicKeyInfo * issuerSpki=NULL; andre@0: CERTCertificate *issuerCert = NULL; andre@0: andre@0: rv = SECSuccess; andre@0: andre@0: /* increment cert chain length counter*/ andre@0: count++; andre@0: andre@0: /* check if cert chain length exceeds the maximum length*/ andre@0: if (count > CERT_MAX_CERT_CHAIN) { andre@0: return SECFailure; andre@0: } andre@0: andre@0: oid = SECOID_FindOID(&subjectCert->subjectPublicKeyInfo.algorithm.algorithm); andre@0: if (oid != NULL) { andre@0: tag = oid->offset; andre@0: andre@0: /* Check if cert has a DSA or EC public key. If not, return andre@0: * success since no PQG params need to be updated. andre@0: * andre@0: * Question: do we really need to do this for EC keys. They don't have andre@0: * PQG parameters, but they do have parameters. The question is does andre@0: * the child cert inherit thost parameters for EC from the parent, or andre@0: * do we always include those parameters in each cert. andre@0: */ andre@0: andre@0: if ( (tag != SEC_OID_ANSIX9_DSA_SIGNATURE) && andre@0: (tag != SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST) && andre@0: (tag != SEC_OID_NIST_DSA_SIGNATURE_WITH_SHA224_DIGEST) && andre@0: (tag != SEC_OID_NIST_DSA_SIGNATURE_WITH_SHA256_DIGEST) && andre@0: (tag != SEC_OID_BOGUS_DSA_SIGNATURE_WITH_SHA1_DIGEST) && andre@0: (tag != SEC_OID_SDN702_DSA_SIGNATURE) && andre@0: (tag != SEC_OID_ANSIX962_EC_PUBLIC_KEY) ) { andre@0: andre@0: return SECSuccess; andre@0: } andre@0: } else { andre@0: return SECFailure; /* return failure if oid is NULL */ andre@0: } andre@0: andre@0: /* if cert has PQG parameters, return success */ andre@0: andre@0: subjectSpki=&subjectCert->subjectPublicKeyInfo; andre@0: andre@0: if (subjectSpki->algorithm.parameters.len != 0) { andre@0: return SECSuccess; andre@0: } andre@0: andre@0: /* check if the cert is self-signed */ andre@0: if (subjectCert->isRoot) { andre@0: /* fail since cert is self-signed and has no pqg params. */ andre@0: return SECFailure; andre@0: } andre@0: andre@0: /* get issuer cert */ andre@0: issuerCert = CERT_FindCertIssuer(subjectCert, PR_Now(), certUsageAnyCA); andre@0: if ( ! issuerCert ) { andre@0: return SECFailure; andre@0: } andre@0: andre@0: /* if parent is not DSA, return failure since andre@0: we don't allow this case. */ andre@0: andre@0: oid = SECOID_FindOID(&issuerCert->subjectPublicKeyInfo.algorithm.algorithm); andre@0: if (oid != NULL) { andre@0: tag = oid->offset; andre@0: andre@0: /* Check if issuer cert has a DSA public key. If not, andre@0: * return failure. */ andre@0: andre@0: if ( (tag != SEC_OID_ANSIX9_DSA_SIGNATURE) && andre@0: (tag != SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST) && andre@0: (tag != SEC_OID_NIST_DSA_SIGNATURE_WITH_SHA224_DIGEST) && andre@0: (tag != SEC_OID_NIST_DSA_SIGNATURE_WITH_SHA256_DIGEST) && andre@0: (tag != SEC_OID_BOGUS_DSA_SIGNATURE_WITH_SHA1_DIGEST) && andre@0: (tag != SEC_OID_SDN702_DSA_SIGNATURE) && andre@0: (tag != SEC_OID_ANSIX962_EC_PUBLIC_KEY) ) { andre@0: rv = SECFailure; andre@0: goto loser; andre@0: } andre@0: } else { andre@0: rv = SECFailure; /* return failure if oid is NULL */ andre@0: goto loser; andre@0: } andre@0: andre@0: andre@0: /* at this point the subject cert has no pqg parameters and the andre@0: * issuer cert has a DSA public key. Update the issuer's andre@0: * pqg parameters with a recursive call to this same function. */ andre@0: andre@0: rv = seckey_UpdateCertPQGChain(issuerCert, count); andre@0: if (rv != SECSuccess) { andre@0: rv = SECFailure; andre@0: goto loser; andre@0: } andre@0: andre@0: /* ensure issuer has pqg parameters */ andre@0: andre@0: issuerSpki=&issuerCert->subjectPublicKeyInfo; andre@0: if (issuerSpki->algorithm.parameters.len == 0) { andre@0: rv = SECFailure; andre@0: } andre@0: andre@0: /* if update was successful and pqg params present, then copy the andre@0: * parameters to the subject cert's key. */ andre@0: andre@0: if (rv == SECSuccess) { andre@0: rv = SECITEM_CopyItem(subjectCert->arena, andre@0: &subjectSpki->algorithm.parameters, andre@0: &issuerSpki->algorithm.parameters); andre@0: } andre@0: andre@0: loser: andre@0: if (issuerCert) { andre@0: CERT_DestroyCertificate(issuerCert); andre@0: } andre@0: return rv; andre@0: andre@0: } andre@0: andre@0: andre@0: SECStatus andre@0: SECKEY_UpdateCertPQG(CERTCertificate * subjectCert) andre@0: { andre@0: if (!subjectCert) { andre@0: PORT_SetError(SEC_ERROR_INVALID_ARGS); andre@0: return SECFailure; andre@0: } andre@0: return seckey_UpdateCertPQGChain(subjectCert,0); andre@0: } andre@0: andre@0: andre@0: /* Decode the DSA PQG parameters. The params could be stored in two andre@0: * possible formats, the old fortezza-only wrapped format or andre@0: * the normal standard format. Store the decoded parameters in andre@0: * a V3 certificate data structure. */ andre@0: andre@0: static SECStatus andre@0: seckey_DSADecodePQG(PLArenaPool *arena, SECKEYPublicKey *pubk, andre@0: const SECItem *params) { andre@0: SECStatus rv; andre@0: SECItem newparams; andre@0: andre@0: if (params == NULL) return SECFailure; andre@0: andre@0: if (params->data == NULL) return SECFailure; andre@0: andre@0: PORT_Assert(arena); andre@0: andre@0: /* make a copy of the data into the arena so QuickDER output is valid */ andre@0: rv = SECITEM_CopyItem(arena, &newparams, params); andre@0: andre@0: /* Check if params use the standard format. andre@0: * The value 0xa1 will appear in the first byte of the parameter data andre@0: * if the PQG parameters are not using the standard format. This andre@0: * code should be changed to use a better method to detect non-standard andre@0: * parameters. */ andre@0: andre@0: if ((newparams.data[0] != 0xa1) && andre@0: (newparams.data[0] != 0xa0)) { andre@0: andre@0: if (SECSuccess == rv) { andre@0: /* PQG params are in the standard format */ andre@0: prepare_pqg_params_for_asn1(&pubk->u.dsa.params); andre@0: rv = SEC_QuickDERDecodeItem(arena, &pubk->u.dsa.params, andre@0: SECKEY_PQGParamsTemplate, andre@0: &newparams); andre@0: } andre@0: } else { andre@0: andre@0: if (SECSuccess == rv) { andre@0: /* else the old fortezza-only wrapped format is used. */ andre@0: PORT_SetError(SEC_ERROR_BAD_DER); andre@0: rv = SECFailure; andre@0: } andre@0: } andre@0: return rv; andre@0: } andre@0: andre@0: andre@0: /* Function used to make an oid tag to a key type */ andre@0: KeyType andre@0: seckey_GetKeyType (SECOidTag tag) { andre@0: KeyType keyType; andre@0: andre@0: switch (tag) { andre@0: case SEC_OID_X500_RSA_ENCRYPTION: andre@0: case SEC_OID_PKCS1_RSA_ENCRYPTION: andre@0: keyType = rsaKey; andre@0: break; andre@0: case SEC_OID_PKCS1_RSA_PSS_SIGNATURE: andre@0: keyType = rsaPssKey; andre@0: break; andre@0: case SEC_OID_PKCS1_RSA_OAEP_ENCRYPTION: andre@0: keyType = rsaOaepKey; andre@0: break; andre@0: case SEC_OID_ANSIX9_DSA_SIGNATURE: andre@0: keyType = dsaKey; andre@0: break; andre@0: case SEC_OID_MISSI_KEA_DSS_OLD: andre@0: case SEC_OID_MISSI_KEA_DSS: andre@0: case SEC_OID_MISSI_DSS_OLD: andre@0: case SEC_OID_MISSI_DSS: andre@0: keyType = fortezzaKey; andre@0: break; andre@0: case SEC_OID_MISSI_KEA: andre@0: case SEC_OID_MISSI_ALT_KEA: andre@0: keyType = keaKey; andre@0: break; andre@0: case SEC_OID_X942_DIFFIE_HELMAN_KEY: andre@0: keyType = dhKey; andre@0: break; andre@0: case SEC_OID_ANSIX962_EC_PUBLIC_KEY: andre@0: keyType = ecKey; andre@0: break; andre@0: /* accommodate applications that hand us a signature type when they andre@0: * should be handing us a cipher type */ andre@0: case SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION: andre@0: case SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION: andre@0: case SEC_OID_PKCS1_SHA224_WITH_RSA_ENCRYPTION: andre@0: case SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION: andre@0: case SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION: andre@0: case SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION: andre@0: keyType = rsaKey; andre@0: break; andre@0: default: andre@0: keyType = nullKey; andre@0: } andre@0: return keyType; andre@0: } andre@0: andre@0: /* Function used to determine what kind of cert we are dealing with. */ andre@0: KeyType andre@0: CERT_GetCertKeyType (const CERTSubjectPublicKeyInfo *spki) andre@0: { andre@0: return seckey_GetKeyType(SECOID_GetAlgorithmTag(&spki->algorithm)); andre@0: } andre@0: andre@0: static SECKEYPublicKey * andre@0: seckey_ExtractPublicKey(const CERTSubjectPublicKeyInfo *spki) andre@0: { andre@0: SECKEYPublicKey *pubk; andre@0: SECItem os, newOs, newParms; andre@0: SECStatus rv; andre@0: PLArenaPool *arena; andre@0: SECOidTag tag; andre@0: andre@0: arena = PORT_NewArena (DER_DEFAULT_CHUNKSIZE); andre@0: if (arena == NULL) andre@0: return NULL; andre@0: andre@0: pubk = (SECKEYPublicKey *) PORT_ArenaZAlloc(arena, sizeof(SECKEYPublicKey)); andre@0: if (pubk == NULL) { andre@0: PORT_FreeArena (arena, PR_FALSE); andre@0: return NULL; andre@0: } andre@0: andre@0: pubk->arena = arena; andre@0: pubk->pkcs11Slot = 0; andre@0: pubk->pkcs11ID = CK_INVALID_HANDLE; andre@0: andre@0: andre@0: /* Convert bit string length from bits to bytes */ andre@0: os = spki->subjectPublicKey; andre@0: DER_ConvertBitString (&os); andre@0: andre@0: tag = SECOID_GetAlgorithmTag(&spki->algorithm); andre@0: andre@0: /* copy the DER into the arena, since Quick DER returns data that points andre@0: into the DER input, which may get freed by the caller */ andre@0: rv = SECITEM_CopyItem(arena, &newOs, &os); andre@0: if ( rv == SECSuccess ) andre@0: switch ( tag ) { andre@0: case SEC_OID_X500_RSA_ENCRYPTION: andre@0: case SEC_OID_PKCS1_RSA_ENCRYPTION: andre@0: pubk->keyType = rsaKey; andre@0: prepare_rsa_pub_key_for_asn1(pubk); andre@0: rv = SEC_QuickDERDecodeItem(arena, pubk, SECKEY_RSAPublicKeyTemplate, &newOs); andre@0: if (rv == SECSuccess) andre@0: return pubk; andre@0: break; andre@0: case SEC_OID_ANSIX9_DSA_SIGNATURE: andre@0: case SEC_OID_SDN702_DSA_SIGNATURE: andre@0: pubk->keyType = dsaKey; andre@0: prepare_dsa_pub_key_for_asn1(pubk); andre@0: rv = SEC_QuickDERDecodeItem(arena, pubk, SECKEY_DSAPublicKeyTemplate, &newOs); andre@0: if (rv != SECSuccess) break; andre@0: andre@0: rv = seckey_DSADecodePQG(arena, pubk, andre@0: &spki->algorithm.parameters); andre@0: andre@0: if (rv == SECSuccess) return pubk; andre@0: break; andre@0: case SEC_OID_X942_DIFFIE_HELMAN_KEY: andre@0: pubk->keyType = dhKey; andre@0: prepare_dh_pub_key_for_asn1(pubk); andre@0: rv = SEC_QuickDERDecodeItem(arena, pubk, SECKEY_DHPublicKeyTemplate, &newOs); andre@0: if (rv != SECSuccess) break; andre@0: andre@0: /* copy the DER into the arena, since Quick DER returns data that points andre@0: into the DER input, which may get freed by the caller */ andre@0: rv = SECITEM_CopyItem(arena, &newParms, &spki->algorithm.parameters); andre@0: if ( rv != SECSuccess ) andre@0: break; andre@0: andre@0: rv = SEC_QuickDERDecodeItem(arena, pubk, SECKEY_DHParamKeyTemplate, andre@0: &newParms); andre@0: andre@0: if (rv == SECSuccess) return pubk; andre@0: break; andre@0: case SEC_OID_ANSIX962_EC_PUBLIC_KEY: andre@0: pubk->keyType = ecKey; andre@0: pubk->u.ec.size = 0; andre@0: andre@0: /* Since PKCS#11 directly takes the DER encoding of EC params andre@0: * and public value, we don't need any decoding here. andre@0: */ andre@0: rv = SECITEM_CopyItem(arena, &pubk->u.ec.DEREncodedParams, andre@0: &spki->algorithm.parameters); andre@0: if ( rv != SECSuccess ) andre@0: break; andre@0: rv = SECITEM_CopyItem(arena, &pubk->u.ec.publicValue, &newOs); andre@0: if (rv == SECSuccess) return pubk; andre@0: break; andre@0: andre@0: default: andre@0: PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG); andre@0: rv = SECFailure; andre@0: break; andre@0: } andre@0: andre@0: SECKEY_DestroyPublicKey (pubk); andre@0: return NULL; andre@0: } andre@0: andre@0: andre@0: /* required for JSS */ andre@0: SECKEYPublicKey * andre@0: SECKEY_ExtractPublicKey(const CERTSubjectPublicKeyInfo *spki) andre@0: { andre@0: return seckey_ExtractPublicKey(spki); andre@0: } andre@0: andre@0: SECKEYPublicKey * andre@0: CERT_ExtractPublicKey(CERTCertificate *cert) andre@0: { andre@0: SECStatus rv; andre@0: andre@0: if (!cert) { andre@0: PORT_SetError(SEC_ERROR_INVALID_ARGS); andre@0: return NULL; andre@0: } andre@0: rv = SECKEY_UpdateCertPQG(cert); andre@0: if (rv != SECSuccess) return NULL; andre@0: andre@0: return seckey_ExtractPublicKey(&cert->subjectPublicKeyInfo); andre@0: } andre@0: andre@0: int andre@0: SECKEY_ECParamsToKeySize(const SECItem *encodedParams) andre@0: { andre@0: SECOidTag tag; andre@0: SECItem oid = { siBuffer, NULL, 0}; andre@0: andre@0: /* The encodedParams data contains 0x06 (SEC_ASN1_OBJECT_ID), andre@0: * followed by the length of the curve oid and the curve oid. andre@0: */ andre@0: oid.len = encodedParams->data[1]; andre@0: oid.data = encodedParams->data + 2; andre@0: if ((tag = SECOID_FindOIDTag(&oid)) == SEC_OID_UNKNOWN) andre@0: return 0; andre@0: andre@0: switch (tag) { andre@0: case SEC_OID_SECG_EC_SECP112R1: andre@0: case SEC_OID_SECG_EC_SECP112R2: andre@0: return 112; andre@0: andre@0: case SEC_OID_SECG_EC_SECT113R1: andre@0: case SEC_OID_SECG_EC_SECT113R2: andre@0: return 113; andre@0: andre@0: case SEC_OID_SECG_EC_SECP128R1: andre@0: case SEC_OID_SECG_EC_SECP128R2: andre@0: return 128; andre@0: andre@0: case SEC_OID_SECG_EC_SECT131R1: andre@0: case SEC_OID_SECG_EC_SECT131R2: andre@0: return 131; andre@0: andre@0: case SEC_OID_SECG_EC_SECP160K1: andre@0: case SEC_OID_SECG_EC_SECP160R1: andre@0: case SEC_OID_SECG_EC_SECP160R2: andre@0: return 160; andre@0: andre@0: case SEC_OID_SECG_EC_SECT163K1: andre@0: case SEC_OID_SECG_EC_SECT163R1: andre@0: case SEC_OID_SECG_EC_SECT163R2: andre@0: case SEC_OID_ANSIX962_EC_C2PNB163V1: andre@0: case SEC_OID_ANSIX962_EC_C2PNB163V2: andre@0: case SEC_OID_ANSIX962_EC_C2PNB163V3: andre@0: return 163; andre@0: andre@0: case SEC_OID_ANSIX962_EC_C2PNB176V1: andre@0: return 176; andre@0: andre@0: case SEC_OID_ANSIX962_EC_C2TNB191V1: andre@0: case SEC_OID_ANSIX962_EC_C2TNB191V2: andre@0: case SEC_OID_ANSIX962_EC_C2TNB191V3: andre@0: case SEC_OID_ANSIX962_EC_C2ONB191V4: andre@0: case SEC_OID_ANSIX962_EC_C2ONB191V5: andre@0: return 191; andre@0: andre@0: case SEC_OID_SECG_EC_SECP192K1: andre@0: case SEC_OID_ANSIX962_EC_PRIME192V1: andre@0: case SEC_OID_ANSIX962_EC_PRIME192V2: andre@0: case SEC_OID_ANSIX962_EC_PRIME192V3: andre@0: return 192; andre@0: andre@0: case SEC_OID_SECG_EC_SECT193R1: andre@0: case SEC_OID_SECG_EC_SECT193R2: andre@0: return 193; andre@0: andre@0: case SEC_OID_ANSIX962_EC_C2PNB208W1: andre@0: return 208; andre@0: andre@0: case SEC_OID_SECG_EC_SECP224K1: andre@0: case SEC_OID_SECG_EC_SECP224R1: andre@0: return 224; andre@0: andre@0: case SEC_OID_SECG_EC_SECT233K1: andre@0: case SEC_OID_SECG_EC_SECT233R1: andre@0: return 233; andre@0: andre@0: case SEC_OID_SECG_EC_SECT239K1: andre@0: case SEC_OID_ANSIX962_EC_C2TNB239V1: andre@0: case SEC_OID_ANSIX962_EC_C2TNB239V2: andre@0: case SEC_OID_ANSIX962_EC_C2TNB239V3: andre@0: case SEC_OID_ANSIX962_EC_C2ONB239V4: andre@0: case SEC_OID_ANSIX962_EC_C2ONB239V5: andre@0: case SEC_OID_ANSIX962_EC_PRIME239V1: andre@0: case SEC_OID_ANSIX962_EC_PRIME239V2: andre@0: case SEC_OID_ANSIX962_EC_PRIME239V3: andre@0: return 239; andre@0: andre@0: case SEC_OID_SECG_EC_SECP256K1: andre@0: case SEC_OID_ANSIX962_EC_PRIME256V1: andre@0: return 256; andre@0: andre@0: case SEC_OID_ANSIX962_EC_C2PNB272W1: andre@0: return 272; andre@0: andre@0: case SEC_OID_SECG_EC_SECT283K1: andre@0: case SEC_OID_SECG_EC_SECT283R1: andre@0: return 283; andre@0: andre@0: case SEC_OID_ANSIX962_EC_C2PNB304W1: andre@0: return 304; andre@0: andre@0: case SEC_OID_ANSIX962_EC_C2TNB359V1: andre@0: return 359; andre@0: andre@0: case SEC_OID_ANSIX962_EC_C2PNB368W1: andre@0: return 368; andre@0: andre@0: case SEC_OID_SECG_EC_SECP384R1: andre@0: return 384; andre@0: andre@0: case SEC_OID_SECG_EC_SECT409K1: andre@0: case SEC_OID_SECG_EC_SECT409R1: andre@0: return 409; andre@0: andre@0: case SEC_OID_ANSIX962_EC_C2TNB431R1: andre@0: return 431; andre@0: andre@0: case SEC_OID_SECG_EC_SECP521R1: andre@0: return 521; andre@0: andre@0: case SEC_OID_SECG_EC_SECT571K1: andre@0: case SEC_OID_SECG_EC_SECT571R1: andre@0: return 571; andre@0: andre@0: default: andre@0: PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE); andre@0: return 0; andre@0: } andre@0: } andre@0: andre@0: int andre@0: SECKEY_ECParamsToBasePointOrderLen(const SECItem *encodedParams) andre@0: { andre@0: SECOidTag tag; andre@0: SECItem oid = { siBuffer, NULL, 0}; andre@0: andre@0: /* The encodedParams data contains 0x06 (SEC_ASN1_OBJECT_ID), andre@0: * followed by the length of the curve oid and the curve oid. andre@0: */ andre@0: oid.len = encodedParams->data[1]; andre@0: oid.data = encodedParams->data + 2; andre@0: if ((tag = SECOID_FindOIDTag(&oid)) == SEC_OID_UNKNOWN) andre@0: return 0; andre@0: andre@0: switch (tag) { andre@0: case SEC_OID_SECG_EC_SECP112R1: andre@0: return 112; andre@0: case SEC_OID_SECG_EC_SECP112R2: andre@0: return 110; andre@0: andre@0: case SEC_OID_SECG_EC_SECT113R1: andre@0: case SEC_OID_SECG_EC_SECT113R2: andre@0: return 113; andre@0: andre@0: case SEC_OID_SECG_EC_SECP128R1: andre@0: return 128; andre@0: case SEC_OID_SECG_EC_SECP128R2: andre@0: return 126; andre@0: andre@0: case SEC_OID_SECG_EC_SECT131R1: andre@0: case SEC_OID_SECG_EC_SECT131R2: andre@0: return 131; andre@0: andre@0: case SEC_OID_SECG_EC_SECP160K1: andre@0: case SEC_OID_SECG_EC_SECP160R1: andre@0: case SEC_OID_SECG_EC_SECP160R2: andre@0: return 161; andre@0: andre@0: case SEC_OID_SECG_EC_SECT163K1: andre@0: return 163; andre@0: case SEC_OID_SECG_EC_SECT163R1: andre@0: return 162; andre@0: case SEC_OID_SECG_EC_SECT163R2: andre@0: case SEC_OID_ANSIX962_EC_C2PNB163V1: andre@0: return 163; andre@0: case SEC_OID_ANSIX962_EC_C2PNB163V2: andre@0: case SEC_OID_ANSIX962_EC_C2PNB163V3: andre@0: return 162; andre@0: andre@0: case SEC_OID_ANSIX962_EC_C2PNB176V1: andre@0: return 161; andre@0: andre@0: case SEC_OID_ANSIX962_EC_C2TNB191V1: andre@0: return 191; andre@0: case SEC_OID_ANSIX962_EC_C2TNB191V2: andre@0: return 190; andre@0: case SEC_OID_ANSIX962_EC_C2TNB191V3: andre@0: return 189; andre@0: case SEC_OID_ANSIX962_EC_C2ONB191V4: andre@0: return 191; andre@0: case SEC_OID_ANSIX962_EC_C2ONB191V5: andre@0: return 188; andre@0: andre@0: case SEC_OID_SECG_EC_SECP192K1: andre@0: case SEC_OID_ANSIX962_EC_PRIME192V1: andre@0: case SEC_OID_ANSIX962_EC_PRIME192V2: andre@0: case SEC_OID_ANSIX962_EC_PRIME192V3: andre@0: return 192; andre@0: andre@0: case SEC_OID_SECG_EC_SECT193R1: andre@0: case SEC_OID_SECG_EC_SECT193R2: andre@0: return 193; andre@0: andre@0: case SEC_OID_ANSIX962_EC_C2PNB208W1: andre@0: return 193; andre@0: andre@0: case SEC_OID_SECG_EC_SECP224K1: andre@0: return 225; andre@0: case SEC_OID_SECG_EC_SECP224R1: andre@0: return 224; andre@0: andre@0: case SEC_OID_SECG_EC_SECT233K1: andre@0: return 232; andre@0: case SEC_OID_SECG_EC_SECT233R1: andre@0: return 233; andre@0: andre@0: case SEC_OID_SECG_EC_SECT239K1: andre@0: case SEC_OID_ANSIX962_EC_C2TNB239V1: andre@0: return 238; andre@0: case SEC_OID_ANSIX962_EC_C2TNB239V2: andre@0: return 237; andre@0: case SEC_OID_ANSIX962_EC_C2TNB239V3: andre@0: return 236; andre@0: case SEC_OID_ANSIX962_EC_C2ONB239V4: andre@0: return 238; andre@0: case SEC_OID_ANSIX962_EC_C2ONB239V5: andre@0: return 237; andre@0: case SEC_OID_ANSIX962_EC_PRIME239V1: andre@0: case SEC_OID_ANSIX962_EC_PRIME239V2: andre@0: case SEC_OID_ANSIX962_EC_PRIME239V3: andre@0: return 239; andre@0: andre@0: case SEC_OID_SECG_EC_SECP256K1: andre@0: case SEC_OID_ANSIX962_EC_PRIME256V1: andre@0: return 256; andre@0: andre@0: case SEC_OID_ANSIX962_EC_C2PNB272W1: andre@0: return 257; andre@0: andre@0: case SEC_OID_SECG_EC_SECT283K1: andre@0: return 281; andre@0: case SEC_OID_SECG_EC_SECT283R1: andre@0: return 282; andre@0: andre@0: case SEC_OID_ANSIX962_EC_C2PNB304W1: andre@0: return 289; andre@0: andre@0: case SEC_OID_ANSIX962_EC_C2TNB359V1: andre@0: return 353; andre@0: andre@0: case SEC_OID_ANSIX962_EC_C2PNB368W1: andre@0: return 353; andre@0: andre@0: case SEC_OID_SECG_EC_SECP384R1: andre@0: return 384; andre@0: andre@0: case SEC_OID_SECG_EC_SECT409K1: andre@0: return 407; andre@0: case SEC_OID_SECG_EC_SECT409R1: andre@0: return 409; andre@0: andre@0: case SEC_OID_ANSIX962_EC_C2TNB431R1: andre@0: return 418; andre@0: andre@0: case SEC_OID_SECG_EC_SECP521R1: andre@0: return 521; andre@0: andre@0: case SEC_OID_SECG_EC_SECT571K1: andre@0: case SEC_OID_SECG_EC_SECT571R1: andre@0: return 570; andre@0: andre@0: default: andre@0: PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE); andre@0: return 0; andre@0: } andre@0: } andre@0: andre@0: /* returns key strength in bytes (not bits) */ andre@0: unsigned andre@0: SECKEY_PublicKeyStrength(const SECKEYPublicKey *pubk) andre@0: { andre@0: unsigned char b0; andre@0: unsigned size; andre@0: andre@0: /* interpret modulus length as key strength */ andre@0: if (!pubk) andre@0: goto loser; andre@0: switch (pubk->keyType) { andre@0: case rsaKey: andre@0: if (!pubk->u.rsa.modulus.data) break; andre@0: b0 = pubk->u.rsa.modulus.data[0]; andre@0: return b0 ? pubk->u.rsa.modulus.len : pubk->u.rsa.modulus.len - 1; andre@0: case dsaKey: andre@0: if (!pubk->u.dsa.publicValue.data) break; andre@0: b0 = pubk->u.dsa.publicValue.data[0]; andre@0: return b0 ? pubk->u.dsa.publicValue.len : andre@0: pubk->u.dsa.publicValue.len - 1; andre@0: case dhKey: andre@0: if (!pubk->u.dh.publicValue.data) break; andre@0: b0 = pubk->u.dh.publicValue.data[0]; andre@0: return b0 ? pubk->u.dh.publicValue.len : andre@0: pubk->u.dh.publicValue.len - 1; andre@0: case ecKey: andre@0: /* Get the key size in bits and adjust */ andre@0: size = SECKEY_ECParamsToKeySize(&pubk->u.ec.DEREncodedParams); andre@0: return (size + 7)/8; andre@0: default: andre@0: break; andre@0: } andre@0: loser: andre@0: PORT_SetError(SEC_ERROR_INVALID_KEY); andre@0: return 0; andre@0: } andre@0: andre@0: /* returns key strength in bits */ andre@0: unsigned andre@0: SECKEY_PublicKeyStrengthInBits(const SECKEYPublicKey *pubk) andre@0: { andre@0: unsigned size; andre@0: switch (pubk->keyType) { andre@0: case rsaKey: andre@0: case dsaKey: andre@0: case dhKey: andre@0: return SECKEY_PublicKeyStrength(pubk) * 8; /* 1 byte = 8 bits */ andre@0: case ecKey: andre@0: size = SECKEY_ECParamsToKeySize(&pubk->u.ec.DEREncodedParams); andre@0: return size; andre@0: default: andre@0: break; andre@0: } andre@0: PORT_SetError(SEC_ERROR_INVALID_KEY); andre@0: return 0; andre@0: } andre@0: andre@0: /* returns signature length in bytes (not bits) */ andre@0: unsigned andre@0: SECKEY_SignatureLen(const SECKEYPublicKey *pubk) andre@0: { andre@0: unsigned char b0; andre@0: unsigned size; andre@0: andre@0: switch (pubk->keyType) { andre@0: case rsaKey: andre@0: b0 = pubk->u.rsa.modulus.data[0]; andre@0: return b0 ? pubk->u.rsa.modulus.len : pubk->u.rsa.modulus.len - 1; andre@0: case dsaKey: andre@0: return pubk->u.dsa.params.subPrime.len * 2; andre@0: case ecKey: andre@0: /* Get the base point order length in bits and adjust */ andre@0: size = SECKEY_ECParamsToBasePointOrderLen( andre@0: &pubk->u.ec.DEREncodedParams); andre@0: return ((size + 7)/8) * 2; andre@0: default: andre@0: break; andre@0: } andre@0: PORT_SetError(SEC_ERROR_INVALID_KEY); andre@0: return 0; andre@0: } andre@0: andre@0: SECKEYPrivateKey * andre@0: SECKEY_CopyPrivateKey(const SECKEYPrivateKey *privk) andre@0: { andre@0: SECKEYPrivateKey *copyk; andre@0: PLArenaPool *arena; andre@0: andre@0: if (!privk || !privk->pkcs11Slot) { andre@0: PORT_SetError(SEC_ERROR_INVALID_ARGS); andre@0: return NULL; andre@0: } andre@0: andre@0: arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); andre@0: if (arena == NULL) { andre@0: return NULL; andre@0: } andre@0: andre@0: copyk = (SECKEYPrivateKey *) PORT_ArenaZAlloc (arena, sizeof (SECKEYPrivateKey)); andre@0: if (copyk) { andre@0: copyk->arena = arena; andre@0: copyk->keyType = privk->keyType; andre@0: andre@0: /* copy the PKCS #11 parameters */ andre@0: copyk->pkcs11Slot = PK11_ReferenceSlot(privk->pkcs11Slot); andre@0: /* if the key we're referencing was a temparary key we have just andre@0: * created, that we want to go away when we're through, we need andre@0: * to make a copy of it */ andre@0: if (privk->pkcs11IsTemp) { andre@0: copyk->pkcs11ID = andre@0: PK11_CopyKey(privk->pkcs11Slot,privk->pkcs11ID); andre@0: if (copyk->pkcs11ID == CK_INVALID_HANDLE) goto fail; andre@0: } else { andre@0: copyk->pkcs11ID = privk->pkcs11ID; andre@0: } andre@0: copyk->pkcs11IsTemp = privk->pkcs11IsTemp; andre@0: copyk->wincx = privk->wincx; andre@0: copyk->staticflags = privk->staticflags; andre@0: return copyk; andre@0: } else { andre@0: PORT_SetError (SEC_ERROR_NO_MEMORY); andre@0: } andre@0: andre@0: fail: andre@0: PORT_FreeArena (arena, PR_FALSE); andre@0: return NULL; andre@0: } andre@0: andre@0: SECKEYPublicKey * andre@0: SECKEY_CopyPublicKey(const SECKEYPublicKey *pubk) andre@0: { andre@0: SECKEYPublicKey *copyk; andre@0: PLArenaPool *arena; andre@0: SECStatus rv = SECSuccess; andre@0: andre@0: arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); andre@0: if (arena == NULL) { andre@0: PORT_SetError (SEC_ERROR_NO_MEMORY); andre@0: return NULL; andre@0: } andre@0: andre@0: copyk = (SECKEYPublicKey *) PORT_ArenaZAlloc (arena, sizeof (SECKEYPublicKey)); andre@0: if (!copyk) { andre@0: PORT_FreeArena (arena, PR_FALSE); andre@0: PORT_SetError (SEC_ERROR_NO_MEMORY); andre@0: return NULL; andre@0: } andre@0: andre@0: copyk->arena = arena; andre@0: copyk->keyType = pubk->keyType; andre@0: if (pubk->pkcs11Slot && andre@0: PK11_IsPermObject(pubk->pkcs11Slot,pubk->pkcs11ID)) { andre@0: copyk->pkcs11Slot = PK11_ReferenceSlot(pubk->pkcs11Slot); andre@0: copyk->pkcs11ID = pubk->pkcs11ID; andre@0: } else { andre@0: copyk->pkcs11Slot = NULL; /* go get own reference */ andre@0: copyk->pkcs11ID = CK_INVALID_HANDLE; andre@0: } andre@0: switch (pubk->keyType) { andre@0: case rsaKey: andre@0: rv = SECITEM_CopyItem(arena, ©k->u.rsa.modulus, andre@0: &pubk->u.rsa.modulus); andre@0: if (rv == SECSuccess) { andre@0: rv = SECITEM_CopyItem (arena, ©k->u.rsa.publicExponent, andre@0: &pubk->u.rsa.publicExponent); andre@0: if (rv == SECSuccess) andre@0: return copyk; andre@0: } andre@0: break; andre@0: case dsaKey: andre@0: rv = SECITEM_CopyItem(arena, ©k->u.dsa.publicValue, andre@0: &pubk->u.dsa.publicValue); andre@0: if (rv != SECSuccess) break; andre@0: rv = SECITEM_CopyItem(arena, ©k->u.dsa.params.prime, andre@0: &pubk->u.dsa.params.prime); andre@0: if (rv != SECSuccess) break; andre@0: rv = SECITEM_CopyItem(arena, ©k->u.dsa.params.subPrime, andre@0: &pubk->u.dsa.params.subPrime); andre@0: if (rv != SECSuccess) break; andre@0: rv = SECITEM_CopyItem(arena, ©k->u.dsa.params.base, andre@0: &pubk->u.dsa.params.base); andre@0: break; andre@0: case dhKey: andre@0: rv = SECITEM_CopyItem(arena,©k->u.dh.prime,&pubk->u.dh.prime); andre@0: if (rv != SECSuccess) break; andre@0: rv = SECITEM_CopyItem(arena,©k->u.dh.base,&pubk->u.dh.base); andre@0: if (rv != SECSuccess) break; andre@0: rv = SECITEM_CopyItem(arena, ©k->u.dh.publicValue, andre@0: &pubk->u.dh.publicValue); andre@0: break; andre@0: case ecKey: andre@0: copyk->u.ec.size = pubk->u.ec.size; andre@0: rv = SECITEM_CopyItem(arena,©k->u.ec.DEREncodedParams, andre@0: &pubk->u.ec.DEREncodedParams); andre@0: if (rv != SECSuccess) break; andre@0: rv = SECITEM_CopyItem(arena,©k->u.ec.publicValue, andre@0: &pubk->u.ec.publicValue); andre@0: break; andre@0: case nullKey: andre@0: return copyk; andre@0: default: andre@0: PORT_SetError(SEC_ERROR_INVALID_KEY); andre@0: rv = SECFailure; andre@0: break; andre@0: } andre@0: if (rv == SECSuccess) andre@0: return copyk; andre@0: andre@0: SECKEY_DestroyPublicKey (copyk); andre@0: return NULL; andre@0: } andre@0: andre@0: andre@0: SECKEYPublicKey * andre@0: SECKEY_ConvertToPublicKey(SECKEYPrivateKey *privk) andre@0: { andre@0: SECKEYPublicKey *pubk; andre@0: PLArenaPool *arena; andre@0: CERTCertificate *cert; andre@0: SECStatus rv; andre@0: andre@0: /* andre@0: * First try to look up the cert. andre@0: */ andre@0: cert = PK11_GetCertFromPrivateKey(privk); andre@0: if (cert) { andre@0: pubk = CERT_ExtractPublicKey(cert); andre@0: CERT_DestroyCertificate(cert); andre@0: return pubk; andre@0: } andre@0: andre@0: /* couldn't find the cert, build pub key by hand */ andre@0: arena = PORT_NewArena (DER_DEFAULT_CHUNKSIZE); andre@0: if (arena == NULL) { andre@0: PORT_SetError (SEC_ERROR_NO_MEMORY); andre@0: return NULL; andre@0: } andre@0: pubk = (SECKEYPublicKey *)PORT_ArenaZAlloc(arena, andre@0: sizeof (SECKEYPublicKey)); andre@0: if (pubk == NULL) { andre@0: PORT_FreeArena(arena,PR_FALSE); andre@0: return NULL; andre@0: } andre@0: pubk->keyType = privk->keyType; andre@0: pubk->pkcs11Slot = NULL; andre@0: pubk->pkcs11ID = CK_INVALID_HANDLE; andre@0: pubk->arena = arena; andre@0: andre@0: switch(privk->keyType) { andre@0: case nullKey: andre@0: case dhKey: andre@0: case dsaKey: andre@0: /* Nothing to query, if the cert isn't there, we're done -- no way andre@0: * to get the public key */ andre@0: break; andre@0: case rsaKey: andre@0: rv = PK11_ReadAttribute(privk->pkcs11Slot,privk->pkcs11ID, andre@0: CKA_MODULUS,arena,&pubk->u.rsa.modulus); andre@0: if (rv != SECSuccess) break; andre@0: rv = PK11_ReadAttribute(privk->pkcs11Slot,privk->pkcs11ID, andre@0: CKA_PUBLIC_EXPONENT,arena,&pubk->u.rsa.publicExponent); andre@0: if (rv != SECSuccess) break; andre@0: return pubk; andre@0: break; andre@0: default: andre@0: break; andre@0: } andre@0: andre@0: PORT_FreeArena (arena, PR_FALSE); andre@0: return NULL; andre@0: } andre@0: andre@0: static CERTSubjectPublicKeyInfo * andre@0: seckey_CreateSubjectPublicKeyInfo_helper(SECKEYPublicKey *pubk) andre@0: { andre@0: CERTSubjectPublicKeyInfo *spki; andre@0: PLArenaPool *arena; andre@0: SECItem params = { siBuffer, NULL, 0 }; andre@0: andre@0: arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); andre@0: if (arena == NULL) { andre@0: PORT_SetError(SEC_ERROR_NO_MEMORY); andre@0: return NULL; andre@0: } andre@0: andre@0: spki = (CERTSubjectPublicKeyInfo *) PORT_ArenaZAlloc(arena, sizeof (*spki)); andre@0: if (spki != NULL) { andre@0: SECStatus rv; andre@0: SECItem *rv_item; andre@0: andre@0: spki->arena = arena; andre@0: switch(pubk->keyType) { andre@0: case rsaKey: andre@0: rv = SECOID_SetAlgorithmID(arena, &spki->algorithm, andre@0: SEC_OID_PKCS1_RSA_ENCRYPTION, 0); andre@0: if (rv == SECSuccess) { andre@0: /* andre@0: * DER encode the public key into the subjectPublicKeyInfo. andre@0: */ andre@0: prepare_rsa_pub_key_for_asn1(pubk); andre@0: rv_item = SEC_ASN1EncodeItem(arena, &spki->subjectPublicKey, andre@0: pubk, SECKEY_RSAPublicKeyTemplate); andre@0: if (rv_item != NULL) { andre@0: /* andre@0: * The stored value is supposed to be a BIT_STRING, andre@0: * so convert the length. andre@0: */ andre@0: spki->subjectPublicKey.len <<= 3; andre@0: /* andre@0: * We got a good one; return it. andre@0: */ andre@0: return spki; andre@0: } andre@0: } andre@0: break; andre@0: case dsaKey: andre@0: /* DER encode the params. */ andre@0: prepare_pqg_params_for_asn1(&pubk->u.dsa.params); andre@0: rv_item = SEC_ASN1EncodeItem(arena, ¶ms, &pubk->u.dsa.params, andre@0: SECKEY_PQGParamsTemplate); andre@0: if (rv_item != NULL) { andre@0: rv = SECOID_SetAlgorithmID(arena, &spki->algorithm, andre@0: SEC_OID_ANSIX9_DSA_SIGNATURE, andre@0: ¶ms); andre@0: if (rv == SECSuccess) { andre@0: /* andre@0: * DER encode the public key into the subjectPublicKeyInfo. andre@0: */ andre@0: prepare_dsa_pub_key_for_asn1(pubk); andre@0: rv_item = SEC_ASN1EncodeItem(arena, &spki->subjectPublicKey, andre@0: pubk, andre@0: SECKEY_DSAPublicKeyTemplate); andre@0: if (rv_item != NULL) { andre@0: /* andre@0: * The stored value is supposed to be a BIT_STRING, andre@0: * so convert the length. andre@0: */ andre@0: spki->subjectPublicKey.len <<= 3; andre@0: /* andre@0: * We got a good one; return it. andre@0: */ andre@0: return spki; andre@0: } andre@0: } andre@0: } andre@0: SECITEM_FreeItem(¶ms, PR_FALSE); andre@0: break; andre@0: case ecKey: andre@0: rv = SECITEM_CopyItem(arena, ¶ms, andre@0: &pubk->u.ec.DEREncodedParams); andre@0: if (rv != SECSuccess) break; andre@0: andre@0: rv = SECOID_SetAlgorithmID(arena, &spki->algorithm, andre@0: SEC_OID_ANSIX962_EC_PUBLIC_KEY, andre@0: ¶ms); andre@0: if (rv != SECSuccess) break; andre@0: andre@0: rv = SECITEM_CopyItem(arena, &spki->subjectPublicKey, andre@0: &pubk->u.ec.publicValue); andre@0: andre@0: if (rv == SECSuccess) { andre@0: /* andre@0: * The stored value is supposed to be a BIT_STRING, andre@0: * so convert the length. andre@0: */ andre@0: spki->subjectPublicKey.len <<= 3; andre@0: /* andre@0: * We got a good one; return it. andre@0: */ andre@0: return spki; andre@0: } andre@0: break; andre@0: case dhKey: /* later... */ andre@0: andre@0: break; andre@0: default: andre@0: break; andre@0: } andre@0: } else { andre@0: PORT_SetError(SEC_ERROR_NO_MEMORY); andre@0: } andre@0: andre@0: PORT_FreeArena(arena, PR_FALSE); andre@0: return NULL; andre@0: } andre@0: andre@0: CERTSubjectPublicKeyInfo * andre@0: SECKEY_CreateSubjectPublicKeyInfo(const SECKEYPublicKey *pubk) andre@0: { andre@0: CERTSubjectPublicKeyInfo *spki; andre@0: SECKEYPublicKey *tempKey; andre@0: andre@0: if (!pubk) { andre@0: PORT_SetError(SEC_ERROR_INVALID_ARGS); andre@0: return NULL; andre@0: } andre@0: andre@0: tempKey = SECKEY_CopyPublicKey(pubk); andre@0: if (!tempKey) { andre@0: return NULL; andre@0: } andre@0: spki = seckey_CreateSubjectPublicKeyInfo_helper(tempKey); andre@0: SECKEY_DestroyPublicKey(tempKey); andre@0: return spki; andre@0: } andre@0: andre@0: void andre@0: SECKEY_DestroySubjectPublicKeyInfo(CERTSubjectPublicKeyInfo *spki) andre@0: { andre@0: if (spki && spki->arena) { andre@0: PORT_FreeArena(spki->arena, PR_FALSE); andre@0: } andre@0: } andre@0: andre@0: SECItem * andre@0: SECKEY_EncodeDERSubjectPublicKeyInfo(const SECKEYPublicKey *pubk) andre@0: { andre@0: CERTSubjectPublicKeyInfo *spki=NULL; andre@0: SECItem *spkiDER=NULL; andre@0: andre@0: /* get the subjectpublickeyinfo */ andre@0: spki = SECKEY_CreateSubjectPublicKeyInfo(pubk); andre@0: if( spki == NULL ) { andre@0: goto finish; andre@0: } andre@0: andre@0: /* DER-encode the subjectpublickeyinfo */ andre@0: spkiDER = SEC_ASN1EncodeItem(NULL /*arena*/, NULL/*dest*/, spki, andre@0: CERT_SubjectPublicKeyInfoTemplate); andre@0: andre@0: SECKEY_DestroySubjectPublicKeyInfo(spki); andre@0: andre@0: finish: andre@0: return spkiDER; andre@0: } andre@0: andre@0: andre@0: CERTSubjectPublicKeyInfo * andre@0: SECKEY_DecodeDERSubjectPublicKeyInfo(const SECItem *spkider) andre@0: { andre@0: PLArenaPool *arena; andre@0: CERTSubjectPublicKeyInfo *spki; andre@0: SECStatus rv; andre@0: SECItem newSpkider; andre@0: andre@0: arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); andre@0: if (arena == NULL) { andre@0: PORT_SetError(SEC_ERROR_NO_MEMORY); andre@0: return NULL; andre@0: } andre@0: andre@0: spki = (CERTSubjectPublicKeyInfo *) andre@0: PORT_ArenaZAlloc(arena, sizeof (CERTSubjectPublicKeyInfo)); andre@0: if (spki != NULL) { andre@0: spki->arena = arena; andre@0: andre@0: /* copy the DER into the arena, since Quick DER returns data that points andre@0: into the DER input, which may get freed by the caller */ andre@0: rv = SECITEM_CopyItem(arena, &newSpkider, spkider); andre@0: if ( rv == SECSuccess ) { andre@0: rv = SEC_QuickDERDecodeItem(arena,spki, andre@0: CERT_SubjectPublicKeyInfoTemplate, &newSpkider); andre@0: } andre@0: if (rv == SECSuccess) andre@0: return spki; andre@0: } else { andre@0: PORT_SetError(SEC_ERROR_NO_MEMORY); andre@0: } andre@0: andre@0: PORT_FreeArena(arena, PR_FALSE); andre@0: return NULL; andre@0: } andre@0: andre@0: /* andre@0: * Decode a base64 ascii encoded DER encoded subject public key info. andre@0: */ andre@0: CERTSubjectPublicKeyInfo * andre@0: SECKEY_ConvertAndDecodeSubjectPublicKeyInfo(const char *spkistr) andre@0: { andre@0: CERTSubjectPublicKeyInfo *spki; andre@0: SECStatus rv; andre@0: SECItem der; andre@0: andre@0: rv = ATOB_ConvertAsciiToItem(&der, spkistr); andre@0: if (rv != SECSuccess) andre@0: return NULL; andre@0: andre@0: spki = SECKEY_DecodeDERSubjectPublicKeyInfo(&der); andre@0: andre@0: PORT_Free(der.data); andre@0: return spki; andre@0: } andre@0: andre@0: /* andre@0: * Decode a base64 ascii encoded DER encoded public key and challenge andre@0: * Verify digital signature and make sure challenge matches andre@0: */ andre@0: CERTSubjectPublicKeyInfo * andre@0: SECKEY_ConvertAndDecodePublicKeyAndChallenge(char *pkacstr, char *challenge, andre@0: void *wincx) andre@0: { andre@0: CERTSubjectPublicKeyInfo *spki = NULL; andre@0: CERTPublicKeyAndChallenge pkac; andre@0: SECStatus rv; andre@0: SECItem signedItem; andre@0: PLArenaPool *arena = NULL; andre@0: CERTSignedData sd; andre@0: SECItem sig; andre@0: SECKEYPublicKey *pubKey = NULL; andre@0: unsigned int len; andre@0: andre@0: signedItem.data = NULL; andre@0: andre@0: /* convert the base64 encoded data to binary */ andre@0: rv = ATOB_ConvertAsciiToItem(&signedItem, pkacstr); andre@0: if (rv != SECSuccess) { andre@0: goto loser; andre@0: } andre@0: andre@0: /* create an arena */ andre@0: arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); andre@0: if (arena == NULL) { andre@0: goto loser; andre@0: } andre@0: andre@0: /* decode the outer wrapping of signed data */ andre@0: PORT_Memset(&sd, 0, sizeof(CERTSignedData)); andre@0: rv = SEC_QuickDERDecodeItem(arena, &sd, CERT_SignedDataTemplate, &signedItem ); andre@0: if ( rv ) { andre@0: goto loser; andre@0: } andre@0: andre@0: /* decode the public key and challenge wrapper */ andre@0: PORT_Memset(&pkac, 0, sizeof(CERTPublicKeyAndChallenge)); andre@0: rv = SEC_QuickDERDecodeItem(arena, &pkac, CERT_PublicKeyAndChallengeTemplate, andre@0: &sd.data); andre@0: if ( rv ) { andre@0: goto loser; andre@0: } andre@0: andre@0: /* decode the subject public key info */ andre@0: spki = SECKEY_DecodeDERSubjectPublicKeyInfo(&pkac.spki); andre@0: if ( spki == NULL ) { andre@0: goto loser; andre@0: } andre@0: andre@0: /* get the public key */ andre@0: pubKey = seckey_ExtractPublicKey(spki); andre@0: if ( pubKey == NULL ) { andre@0: goto loser; andre@0: } andre@0: andre@0: /* check the signature */ andre@0: sig = sd.signature; andre@0: DER_ConvertBitString(&sig); andre@0: rv = VFY_VerifyDataWithAlgorithmID(sd.data.data, sd.data.len, pubKey, &sig, andre@0: &(sd.signatureAlgorithm), NULL, wincx); andre@0: if ( rv != SECSuccess ) { andre@0: goto loser; andre@0: } andre@0: andre@0: /* check the challenge */ andre@0: if ( challenge ) { andre@0: len = PORT_Strlen(challenge); andre@0: /* length is right */ andre@0: if ( len != pkac.challenge.len ) { andre@0: goto loser; andre@0: } andre@0: /* actual data is right */ andre@0: if ( PORT_Memcmp(challenge, pkac.challenge.data, len) != 0 ) { andre@0: goto loser; andre@0: } andre@0: } andre@0: goto done; andre@0: andre@0: loser: andre@0: /* make sure that we return null if we got an error */ andre@0: if ( spki ) { andre@0: SECKEY_DestroySubjectPublicKeyInfo(spki); andre@0: } andre@0: spki = NULL; andre@0: andre@0: done: andre@0: if ( signedItem.data ) { andre@0: PORT_Free(signedItem.data); andre@0: } andre@0: if ( arena ) { andre@0: PORT_FreeArena(arena, PR_FALSE); andre@0: } andre@0: if ( pubKey ) { andre@0: SECKEY_DestroyPublicKey(pubKey); andre@0: } andre@0: andre@0: return spki; andre@0: } andre@0: andre@0: void andre@0: SECKEY_DestroyPrivateKeyInfo(SECKEYPrivateKeyInfo *pvk, andre@0: PRBool freeit) andre@0: { andre@0: PLArenaPool *poolp; andre@0: andre@0: if(pvk != NULL) { andre@0: if(pvk->arena) { andre@0: poolp = pvk->arena; andre@0: /* zero structure since PORT_FreeArena does not support andre@0: * this yet. andre@0: */ andre@0: PORT_Memset(pvk->privateKey.data, 0, pvk->privateKey.len); andre@0: PORT_Memset((char *)pvk, 0, sizeof(*pvk)); andre@0: if(freeit == PR_TRUE) { andre@0: PORT_FreeArena(poolp, PR_TRUE); andre@0: } else { andre@0: pvk->arena = poolp; andre@0: } andre@0: } else { andre@0: SECITEM_ZfreeItem(&pvk->version, PR_FALSE); andre@0: SECITEM_ZfreeItem(&pvk->privateKey, PR_FALSE); andre@0: SECOID_DestroyAlgorithmID(&pvk->algorithm, PR_FALSE); andre@0: PORT_Memset((char *)pvk, 0, sizeof(*pvk)); andre@0: if(freeit == PR_TRUE) { andre@0: PORT_Free(pvk); andre@0: } andre@0: } andre@0: } andre@0: } andre@0: andre@0: void andre@0: SECKEY_DestroyEncryptedPrivateKeyInfo(SECKEYEncryptedPrivateKeyInfo *epki, andre@0: PRBool freeit) andre@0: { andre@0: PLArenaPool *poolp; andre@0: andre@0: if(epki != NULL) { andre@0: if(epki->arena) { andre@0: poolp = epki->arena; andre@0: /* zero structure since PORT_FreeArena does not support andre@0: * this yet. andre@0: */ andre@0: PORT_Memset(epki->encryptedData.data, 0, epki->encryptedData.len); andre@0: PORT_Memset((char *)epki, 0, sizeof(*epki)); andre@0: if(freeit == PR_TRUE) { andre@0: PORT_FreeArena(poolp, PR_TRUE); andre@0: } else { andre@0: epki->arena = poolp; andre@0: } andre@0: } else { andre@0: SECITEM_ZfreeItem(&epki->encryptedData, PR_FALSE); andre@0: SECOID_DestroyAlgorithmID(&epki->algorithm, PR_FALSE); andre@0: PORT_Memset((char *)epki, 0, sizeof(*epki)); andre@0: if(freeit == PR_TRUE) { andre@0: PORT_Free(epki); andre@0: } andre@0: } andre@0: } andre@0: } andre@0: andre@0: SECStatus andre@0: SECKEY_CopyPrivateKeyInfo(PLArenaPool *poolp, andre@0: SECKEYPrivateKeyInfo *to, andre@0: const SECKEYPrivateKeyInfo *from) andre@0: { andre@0: SECStatus rv = SECFailure; andre@0: andre@0: if((to == NULL) || (from == NULL)) { andre@0: return SECFailure; andre@0: } andre@0: andre@0: rv = SECOID_CopyAlgorithmID(poolp, &to->algorithm, &from->algorithm); andre@0: if(rv != SECSuccess) { andre@0: return SECFailure; andre@0: } andre@0: rv = SECITEM_CopyItem(poolp, &to->privateKey, &from->privateKey); andre@0: if(rv != SECSuccess) { andre@0: return SECFailure; andre@0: } andre@0: rv = SECITEM_CopyItem(poolp, &to->version, &from->version); andre@0: andre@0: return rv; andre@0: } andre@0: andre@0: SECStatus andre@0: SECKEY_CopyEncryptedPrivateKeyInfo(PLArenaPool *poolp, andre@0: SECKEYEncryptedPrivateKeyInfo *to, andre@0: const SECKEYEncryptedPrivateKeyInfo *from) andre@0: { andre@0: SECStatus rv = SECFailure; andre@0: andre@0: if((to == NULL) || (from == NULL)) { andre@0: return SECFailure; andre@0: } andre@0: andre@0: rv = SECOID_CopyAlgorithmID(poolp, &to->algorithm, &from->algorithm); andre@0: if(rv != SECSuccess) { andre@0: return SECFailure; andre@0: } andre@0: rv = SECITEM_CopyItem(poolp, &to->encryptedData, &from->encryptedData); andre@0: andre@0: return rv; andre@0: } andre@0: andre@0: KeyType andre@0: SECKEY_GetPrivateKeyType(const SECKEYPrivateKey *privKey) andre@0: { andre@0: return privKey->keyType; andre@0: } andre@0: andre@0: KeyType andre@0: SECKEY_GetPublicKeyType(const SECKEYPublicKey *pubKey) andre@0: { andre@0: return pubKey->keyType; andre@0: } andre@0: andre@0: SECKEYPublicKey* andre@0: SECKEY_ImportDERPublicKey(const SECItem *derKey, CK_KEY_TYPE type) andre@0: { andre@0: SECKEYPublicKey *pubk = NULL; andre@0: SECStatus rv = SECFailure; andre@0: SECItem newDerKey; andre@0: PLArenaPool *arena = NULL; andre@0: andre@0: if (!derKey) { andre@0: return NULL; andre@0: } andre@0: andre@0: arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); andre@0: if (arena == NULL) { andre@0: PORT_SetError(SEC_ERROR_NO_MEMORY); andre@0: goto finish; andre@0: } andre@0: andre@0: pubk = PORT_ArenaZNew(arena, SECKEYPublicKey); andre@0: if (pubk == NULL) { andre@0: goto finish; andre@0: } andre@0: pubk->arena = arena; andre@0: andre@0: rv = SECITEM_CopyItem(pubk->arena, &newDerKey, derKey); andre@0: if (SECSuccess != rv) { andre@0: goto finish; andre@0: } andre@0: andre@0: pubk->pkcs11Slot = NULL; andre@0: pubk->pkcs11ID = CK_INVALID_HANDLE; andre@0: andre@0: switch( type ) { andre@0: case CKK_RSA: andre@0: prepare_rsa_pub_key_for_asn1(pubk); andre@0: rv = SEC_QuickDERDecodeItem(pubk->arena, pubk, SECKEY_RSAPublicKeyTemplate, &newDerKey); andre@0: pubk->keyType = rsaKey; andre@0: break; andre@0: case CKK_DSA: andre@0: prepare_dsa_pub_key_for_asn1(pubk); andre@0: rv = SEC_QuickDERDecodeItem(pubk->arena, pubk, SECKEY_DSAPublicKeyTemplate, &newDerKey); andre@0: pubk->keyType = dsaKey; andre@0: break; andre@0: case CKK_DH: andre@0: prepare_dh_pub_key_for_asn1(pubk); andre@0: rv = SEC_QuickDERDecodeItem(pubk->arena, pubk, SECKEY_DHPublicKeyTemplate, &newDerKey); andre@0: pubk->keyType = dhKey; andre@0: break; andre@0: default: andre@0: rv = SECFailure; andre@0: break; andre@0: } andre@0: andre@0: finish: andre@0: if (rv != SECSuccess) { andre@0: if (arena != NULL) { andre@0: PORT_FreeArena(arena, PR_FALSE); andre@0: } andre@0: pubk = NULL; andre@0: } andre@0: return pubk; andre@0: } andre@0: andre@0: SECKEYPrivateKeyList* andre@0: SECKEY_NewPrivateKeyList(void) andre@0: { andre@0: PLArenaPool *arena = NULL; andre@0: SECKEYPrivateKeyList *ret = NULL; andre@0: andre@0: arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); andre@0: if ( arena == NULL ) { andre@0: goto loser; andre@0: } andre@0: andre@0: ret = (SECKEYPrivateKeyList *)PORT_ArenaZAlloc(arena, andre@0: sizeof(SECKEYPrivateKeyList)); andre@0: if ( ret == NULL ) { andre@0: goto loser; andre@0: } andre@0: andre@0: ret->arena = arena; andre@0: andre@0: PR_INIT_CLIST(&ret->list); andre@0: andre@0: return(ret); andre@0: andre@0: loser: andre@0: if ( arena != NULL ) { andre@0: PORT_FreeArena(arena, PR_FALSE); andre@0: } andre@0: andre@0: return(NULL); andre@0: } andre@0: andre@0: void andre@0: SECKEY_DestroyPrivateKeyList(SECKEYPrivateKeyList *keys) andre@0: { andre@0: while( !PR_CLIST_IS_EMPTY(&keys->list) ) { andre@0: SECKEY_RemovePrivateKeyListNode( andre@0: (SECKEYPrivateKeyListNode*)(PR_LIST_HEAD(&keys->list)) ); andre@0: } andre@0: andre@0: PORT_FreeArena(keys->arena, PR_FALSE); andre@0: andre@0: return; andre@0: } andre@0: andre@0: andre@0: void andre@0: SECKEY_RemovePrivateKeyListNode(SECKEYPrivateKeyListNode *node) andre@0: { andre@0: PR_ASSERT(node->key); andre@0: SECKEY_DestroyPrivateKey(node->key); andre@0: node->key = NULL; andre@0: PR_REMOVE_LINK(&node->links); andre@0: return; andre@0: andre@0: } andre@0: andre@0: SECStatus andre@0: SECKEY_AddPrivateKeyToListTail( SECKEYPrivateKeyList *list, andre@0: SECKEYPrivateKey *key) andre@0: { andre@0: SECKEYPrivateKeyListNode *node; andre@0: andre@0: node = (SECKEYPrivateKeyListNode *)PORT_ArenaZAlloc(list->arena, andre@0: sizeof(SECKEYPrivateKeyListNode)); andre@0: if ( node == NULL ) { andre@0: goto loser; andre@0: } andre@0: andre@0: PR_INSERT_BEFORE(&node->links, &list->list); andre@0: node->key = key; andre@0: return(SECSuccess); andre@0: andre@0: loser: andre@0: return(SECFailure); andre@0: } andre@0: andre@0: andre@0: SECKEYPublicKeyList* andre@0: SECKEY_NewPublicKeyList(void) andre@0: { andre@0: PLArenaPool *arena = NULL; andre@0: SECKEYPublicKeyList *ret = NULL; andre@0: andre@0: arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); andre@0: if ( arena == NULL ) { andre@0: goto loser; andre@0: } andre@0: andre@0: ret = (SECKEYPublicKeyList *)PORT_ArenaZAlloc(arena, andre@0: sizeof(SECKEYPublicKeyList)); andre@0: if ( ret == NULL ) { andre@0: goto loser; andre@0: } andre@0: andre@0: ret->arena = arena; andre@0: andre@0: PR_INIT_CLIST(&ret->list); andre@0: andre@0: return(ret); andre@0: andre@0: loser: andre@0: if ( arena != NULL ) { andre@0: PORT_FreeArena(arena, PR_FALSE); andre@0: } andre@0: andre@0: return(NULL); andre@0: } andre@0: andre@0: void andre@0: SECKEY_DestroyPublicKeyList(SECKEYPublicKeyList *keys) andre@0: { andre@0: while( !PR_CLIST_IS_EMPTY(&keys->list) ) { andre@0: SECKEY_RemovePublicKeyListNode( andre@0: (SECKEYPublicKeyListNode*)(PR_LIST_HEAD(&keys->list)) ); andre@0: } andre@0: andre@0: PORT_FreeArena(keys->arena, PR_FALSE); andre@0: andre@0: return; andre@0: } andre@0: andre@0: andre@0: void andre@0: SECKEY_RemovePublicKeyListNode(SECKEYPublicKeyListNode *node) andre@0: { andre@0: PR_ASSERT(node->key); andre@0: SECKEY_DestroyPublicKey(node->key); andre@0: node->key = NULL; andre@0: PR_REMOVE_LINK(&node->links); andre@0: return; andre@0: andre@0: } andre@0: andre@0: SECStatus andre@0: SECKEY_AddPublicKeyToListTail( SECKEYPublicKeyList *list, andre@0: SECKEYPublicKey *key) andre@0: { andre@0: SECKEYPublicKeyListNode *node; andre@0: andre@0: node = (SECKEYPublicKeyListNode *)PORT_ArenaZAlloc(list->arena, andre@0: sizeof(SECKEYPublicKeyListNode)); andre@0: if ( node == NULL ) { andre@0: goto loser; andre@0: } andre@0: andre@0: PR_INSERT_BEFORE(&node->links, &list->list); andre@0: node->key = key; andre@0: return(SECSuccess); andre@0: andre@0: loser: andre@0: return(SECFailure); andre@0: } andre@0: andre@0: #define SECKEY_CacheAttribute(key, attribute) \ andre@0: if (CK_TRUE == PK11_HasAttributeSet(key->pkcs11Slot, key->pkcs11ID, attribute, PR_FALSE)) { \ andre@0: key->staticflags |= SECKEY_##attribute; \ andre@0: } else { \ andre@0: key->staticflags &= (~SECKEY_##attribute); \ andre@0: } andre@0: andre@0: SECStatus andre@0: SECKEY_CacheStaticFlags(SECKEYPrivateKey* key) andre@0: { andre@0: SECStatus rv = SECFailure; andre@0: if (key && key->pkcs11Slot && key->pkcs11ID) { andre@0: key->staticflags |= SECKEY_Attributes_Cached; andre@0: SECKEY_CacheAttribute(key, CKA_PRIVATE); andre@0: SECKEY_CacheAttribute(key, CKA_ALWAYS_AUTHENTICATE); andre@0: rv = SECSuccess; andre@0: } andre@0: return rv; andre@0: }