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: #include "lowkeyi.h" michael@0: #include "secoid.h" michael@0: #include "secitem.h" michael@0: #include "secder.h" michael@0: #include "secasn1.h" michael@0: #include "secerr.h" michael@0: michael@0: SEC_ASN1_MKSUB(SEC_AnyTemplate) michael@0: SEC_ASN1_MKSUB(SEC_BitStringTemplate) michael@0: SEC_ASN1_MKSUB(SEC_ObjectIDTemplate) michael@0: SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate) michael@0: michael@0: static const SEC_ASN1Template nsslowkey_AttributeTemplate[] = { michael@0: { SEC_ASN1_SEQUENCE, michael@0: 0, NULL, sizeof(NSSLOWKEYAttribute) }, michael@0: { SEC_ASN1_OBJECT_ID, offsetof(NSSLOWKEYAttribute, attrType) }, michael@0: { SEC_ASN1_SET_OF | SEC_ASN1_XTRN, offsetof(NSSLOWKEYAttribute, attrValue), michael@0: SEC_ASN1_SUB(SEC_AnyTemplate) }, michael@0: { 0 } michael@0: }; michael@0: michael@0: static const SEC_ASN1Template nsslowkey_SetOfAttributeTemplate[] = { michael@0: { SEC_ASN1_SET_OF, 0, nsslowkey_AttributeTemplate }, michael@0: }; michael@0: /* ASN1 Templates for new decoder/encoder */ michael@0: const SEC_ASN1Template lg_nsslowkey_PrivateKeyInfoTemplate[] = { michael@0: { SEC_ASN1_SEQUENCE, michael@0: 0, NULL, sizeof(NSSLOWKEYPrivateKeyInfo) }, michael@0: { SEC_ASN1_INTEGER, michael@0: offsetof(NSSLOWKEYPrivateKeyInfo,version) }, michael@0: { SEC_ASN1_INLINE | SEC_ASN1_XTRN, michael@0: offsetof(NSSLOWKEYPrivateKeyInfo,algorithm), michael@0: SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) }, michael@0: { SEC_ASN1_OCTET_STRING, michael@0: offsetof(NSSLOWKEYPrivateKeyInfo,privateKey) }, michael@0: { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0, michael@0: offsetof(NSSLOWKEYPrivateKeyInfo, attributes), michael@0: nsslowkey_SetOfAttributeTemplate }, michael@0: { 0 } michael@0: }; michael@0: michael@0: const SEC_ASN1Template lg_nsslowkey_PQGParamsTemplate[] = { michael@0: { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(PQGParams) }, michael@0: { SEC_ASN1_INTEGER, offsetof(PQGParams,prime) }, michael@0: { SEC_ASN1_INTEGER, offsetof(PQGParams,subPrime) }, michael@0: { SEC_ASN1_INTEGER, offsetof(PQGParams,base) }, michael@0: { 0, } michael@0: }; michael@0: michael@0: const SEC_ASN1Template lg_nsslowkey_RSAPrivateKeyTemplate[] = { michael@0: { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(NSSLOWKEYPrivateKey) }, michael@0: { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey,u.rsa.version) }, michael@0: { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey,u.rsa.modulus) }, michael@0: { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey,u.rsa.publicExponent) }, michael@0: { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey,u.rsa.privateExponent) }, michael@0: { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey,u.rsa.prime1) }, michael@0: { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey,u.rsa.prime2) }, michael@0: { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey,u.rsa.exponent1) }, michael@0: { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey,u.rsa.exponent2) }, michael@0: { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey,u.rsa.coefficient) }, michael@0: { 0 } michael@0: }; michael@0: michael@0: /* michael@0: * Allows u.rsa.modulus to be zero length for secret keys with an empty michael@0: * CKA_ID incorrectly generated in NSS 3.13.3 or earlier. Only used for michael@0: * decoding. See bug 715073. michael@0: */ michael@0: const SEC_ASN1Template lg_nsslowkey_RSAPrivateKeyTemplate2[] = { michael@0: { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(NSSLOWKEYPrivateKey) }, michael@0: { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey,u.rsa.version) }, michael@0: { SEC_ASN1_ANY, offsetof(NSSLOWKEYPrivateKey,u.rsa.modulus) }, michael@0: { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey,u.rsa.publicExponent) }, michael@0: { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey,u.rsa.privateExponent) }, michael@0: { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey,u.rsa.prime1) }, michael@0: { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey,u.rsa.prime2) }, michael@0: { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey,u.rsa.exponent1) }, michael@0: { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey,u.rsa.exponent2) }, michael@0: { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey,u.rsa.coefficient) }, michael@0: { 0 } michael@0: }; michael@0: michael@0: const SEC_ASN1Template lg_nsslowkey_DSAPrivateKeyTemplate[] = { michael@0: { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(NSSLOWKEYPrivateKey) }, michael@0: { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey,u.dsa.publicValue) }, michael@0: { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey,u.dsa.privateValue) }, michael@0: { 0, } michael@0: }; michael@0: michael@0: const SEC_ASN1Template lg_nsslowkey_DHPrivateKeyTemplate[] = { michael@0: { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(NSSLOWKEYPrivateKey) }, michael@0: { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey,u.dh.publicValue) }, michael@0: { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey,u.dh.privateValue) }, michael@0: { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey,u.dh.base) }, michael@0: { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey,u.dh.prime) }, michael@0: { 0, } michael@0: }; michael@0: michael@0: #ifndef NSS_DISABLE_ECC michael@0: michael@0: /* XXX This is just a placeholder for later when we support michael@0: * generic curves and need full-blown support for parsing EC michael@0: * parameters. For now, we only support named curves in which michael@0: * EC params are simply encoded as an object ID and we don't michael@0: * use lg_nsslowkey_ECParamsTemplate. michael@0: */ michael@0: const SEC_ASN1Template lg_nsslowkey_ECParamsTemplate[] = { michael@0: { SEC_ASN1_CHOICE, offsetof(ECParams,type), NULL, sizeof(ECParams) }, michael@0: { SEC_ASN1_OBJECT_ID, offsetof(ECParams,curveOID), NULL, ec_params_named }, michael@0: { 0, } michael@0: }; michael@0: michael@0: michael@0: /* NOTE: The SECG specification allows the private key structure michael@0: * to contain curve parameters but recommends that they be stored michael@0: * in the PrivateKeyAlgorithmIdentifier field of the PrivateKeyInfo michael@0: * instead. michael@0: */ michael@0: const SEC_ASN1Template lg_nsslowkey_ECPrivateKeyTemplate[] = { michael@0: { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(NSSLOWKEYPrivateKey) }, michael@0: { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey,u.ec.version) }, michael@0: { SEC_ASN1_OCTET_STRING, michael@0: offsetof(NSSLOWKEYPrivateKey,u.ec.privateValue) }, michael@0: /* XXX The following template works for now since we only michael@0: * support named curves for which the parameters are michael@0: * encoded as an object ID. When we support generic curves, michael@0: * we'll need to define lg_nsslowkey_ECParamsTemplate michael@0: */ michael@0: #if 1 michael@0: { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | michael@0: SEC_ASN1_EXPLICIT | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 0, michael@0: offsetof(NSSLOWKEYPrivateKey,u.ec.ecParams.curveOID), michael@0: SEC_ASN1_SUB(SEC_ObjectIDTemplate) }, michael@0: #else michael@0: { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | michael@0: SEC_ASN1_EXPLICIT | SEC_ASN1_CONTEXT_SPECIFIC | 0, michael@0: offsetof(NSSLOWKEYPrivateKey,u.ec.ecParams), michael@0: lg_nsslowkey_ECParamsTemplate }, michael@0: #endif michael@0: { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | michael@0: SEC_ASN1_EXPLICIT | SEC_ASN1_CONTEXT_SPECIFIC | michael@0: SEC_ASN1_XTRN | 1, michael@0: offsetof(NSSLOWKEYPrivateKey,u.ec.publicValue), michael@0: SEC_ASN1_SUB(SEC_BitStringTemplate) }, michael@0: { 0, } michael@0: }; michael@0: michael@0: michael@0: /* michael@0: * smaller version of EC_FillParams. In this code, we only need michael@0: * oid and DER data. michael@0: */ michael@0: SECStatus michael@0: LGEC_FillParams(PLArenaPool *arena, const SECItem *encodedParams, michael@0: ECParams *params) michael@0: { michael@0: SECOidTag tag; michael@0: SECItem oid = { siBuffer, NULL, 0}; michael@0: michael@0: #if EC_DEBUG michael@0: int i; michael@0: michael@0: printf("Encoded params in EC_DecodeParams: "); michael@0: for (i = 0; i < encodedParams->len; i++) { michael@0: printf("%02x:", encodedParams->data[i]); michael@0: } michael@0: printf("\n"); michael@0: #endif michael@0: michael@0: oid.len = encodedParams->len - 2; michael@0: oid.data = encodedParams->data + 2; michael@0: if ((encodedParams->data[0] != SEC_ASN1_OBJECT_ID) || michael@0: ((tag = SECOID_FindOIDTag(&oid)) == SEC_OID_UNKNOWN)) { michael@0: PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE); michael@0: return SECFailure; michael@0: } michael@0: michael@0: params->arena = arena; michael@0: michael@0: /* For named curves, fill out curveOID */ michael@0: params->curveOID.len = oid.len; michael@0: params->curveOID.data = (unsigned char *) PORT_ArenaAlloc(arena, oid.len); michael@0: if (params->curveOID.data == NULL) { michael@0: return SECFailure; michael@0: } michael@0: memcpy(params->curveOID.data, oid.data, oid.len); michael@0: michael@0: return SECSuccess; michael@0: } michael@0: michael@0: /* Copy all of the fields from srcParams into dstParams michael@0: */ michael@0: SECStatus michael@0: LGEC_CopyParams(PLArenaPool *arena, ECParams *dstParams, michael@0: const ECParams *srcParams) michael@0: { michael@0: SECStatus rv = SECFailure; michael@0: michael@0: dstParams->arena = arena; michael@0: rv = SECITEM_CopyItem(arena, &dstParams->DEREncoding, michael@0: &srcParams->DEREncoding); michael@0: if (rv != SECSuccess) { michael@0: goto loser; michael@0: } michael@0: rv =SECITEM_CopyItem(arena, &dstParams->curveOID, michael@0: &srcParams->curveOID); michael@0: if (rv != SECSuccess) { michael@0: goto loser; michael@0: } michael@0: michael@0: return SECSuccess; michael@0: michael@0: loser: michael@0: return SECFailure; michael@0: } michael@0: #endif /* NSS_DISABLE_ECC */ 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: void michael@0: lg_prepare_low_rsa_priv_key_for_asn1(NSSLOWKEYPrivateKey *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: void michael@0: lg_prepare_low_pqg_params_for_asn1(PQGParams *params) michael@0: { michael@0: params->prime.type = siUnsignedInteger; michael@0: params->subPrime.type = siUnsignedInteger; michael@0: params->base.type = siUnsignedInteger; michael@0: } michael@0: michael@0: void michael@0: lg_prepare_low_dsa_priv_key_for_asn1(NSSLOWKEYPrivateKey *key) michael@0: { michael@0: key->u.dsa.publicValue.type = siUnsignedInteger; 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: void michael@0: lg_prepare_low_dh_priv_key_for_asn1(NSSLOWKEYPrivateKey *key) michael@0: { michael@0: key->u.dh.prime.type = siUnsignedInteger; michael@0: key->u.dh.base.type = siUnsignedInteger; michael@0: key->u.dh.publicValue.type = siUnsignedInteger; michael@0: key->u.dh.privateValue.type = siUnsignedInteger; michael@0: } michael@0: michael@0: #ifndef NSS_DISABLE_ECC michael@0: void michael@0: lg_prepare_low_ecparams_for_asn1(ECParams *params) michael@0: { michael@0: params->DEREncoding.type = siUnsignedInteger; michael@0: params->curveOID.type = siUnsignedInteger; michael@0: } michael@0: michael@0: void michael@0: lg_prepare_low_ec_priv_key_for_asn1(NSSLOWKEYPrivateKey *key) michael@0: { michael@0: key->u.ec.version.type = siUnsignedInteger; michael@0: key->u.ec.ecParams.DEREncoding.type = siUnsignedInteger; michael@0: key->u.ec.ecParams.curveOID.type = siUnsignedInteger; michael@0: key->u.ec.privateValue.type = siUnsignedInteger; michael@0: key->u.ec.publicValue.type = siUnsignedInteger; michael@0: } michael@0: #endif /* NSS_DISABLE_ECC */ michael@0: michael@0: void michael@0: lg_nsslowkey_DestroyPrivateKey(NSSLOWKEYPrivateKey *privk) michael@0: { michael@0: if (privk && privk->arena) { michael@0: PORT_FreeArena(privk->arena, PR_TRUE); michael@0: } michael@0: } michael@0: michael@0: void michael@0: lg_nsslowkey_DestroyPublicKey(NSSLOWKEYPublicKey *pubk) michael@0: { michael@0: if (pubk && pubk->arena) { michael@0: PORT_FreeArena(pubk->arena, PR_FALSE); michael@0: } michael@0: } michael@0: michael@0: NSSLOWKEYPublicKey * michael@0: lg_nsslowkey_ConvertToPublicKey(NSSLOWKEYPrivateKey *privk) michael@0: { michael@0: NSSLOWKEYPublicKey *pubk; michael@0: PLArenaPool *arena; michael@0: michael@0: michael@0: arena = PORT_NewArena (DER_DEFAULT_CHUNKSIZE); michael@0: if (arena == NULL) { michael@0: PORT_SetError (SEC_ERROR_NO_MEMORY); michael@0: return NULL; michael@0: } michael@0: michael@0: switch(privk->keyType) { michael@0: case NSSLOWKEYRSAKey: michael@0: case NSSLOWKEYNullKey: michael@0: pubk = (NSSLOWKEYPublicKey *)PORT_ArenaZAlloc(arena, michael@0: sizeof (NSSLOWKEYPublicKey)); michael@0: if (pubk != NULL) { michael@0: SECStatus rv; michael@0: michael@0: pubk->arena = arena; michael@0: pubk->keyType = privk->keyType; michael@0: if (privk->keyType == NSSLOWKEYNullKey) return pubk; michael@0: rv = SECITEM_CopyItem(arena, &pubk->u.rsa.modulus, michael@0: &privk->u.rsa.modulus); michael@0: if (rv == SECSuccess) { michael@0: rv = SECITEM_CopyItem (arena, &pubk->u.rsa.publicExponent, michael@0: &privk->u.rsa.publicExponent); michael@0: if (rv == SECSuccess) michael@0: return pubk; michael@0: } michael@0: } else { michael@0: PORT_SetError (SEC_ERROR_NO_MEMORY); michael@0: } michael@0: break; michael@0: case NSSLOWKEYDSAKey: michael@0: pubk = (NSSLOWKEYPublicKey *)PORT_ArenaZAlloc(arena, michael@0: sizeof(NSSLOWKEYPublicKey)); michael@0: if (pubk != NULL) { michael@0: SECStatus rv; michael@0: michael@0: pubk->arena = arena; michael@0: pubk->keyType = privk->keyType; michael@0: rv = SECITEM_CopyItem(arena, &pubk->u.dsa.publicValue, michael@0: &privk->u.dsa.publicValue); michael@0: if (rv != SECSuccess) break; michael@0: rv = SECITEM_CopyItem(arena, &pubk->u.dsa.params.prime, michael@0: &privk->u.dsa.params.prime); michael@0: if (rv != SECSuccess) break; michael@0: rv = SECITEM_CopyItem(arena, &pubk->u.dsa.params.subPrime, michael@0: &privk->u.dsa.params.subPrime); michael@0: if (rv != SECSuccess) break; michael@0: rv = SECITEM_CopyItem(arena, &pubk->u.dsa.params.base, michael@0: &privk->u.dsa.params.base); michael@0: if (rv == SECSuccess) return pubk; michael@0: } michael@0: break; michael@0: case NSSLOWKEYDHKey: michael@0: pubk = (NSSLOWKEYPublicKey *)PORT_ArenaZAlloc(arena, michael@0: sizeof(NSSLOWKEYPublicKey)); michael@0: if (pubk != NULL) { michael@0: SECStatus rv; michael@0: michael@0: pubk->arena = arena; michael@0: pubk->keyType = privk->keyType; michael@0: rv = SECITEM_CopyItem(arena, &pubk->u.dh.publicValue, michael@0: &privk->u.dh.publicValue); michael@0: if (rv != SECSuccess) break; michael@0: rv = SECITEM_CopyItem(arena, &pubk->u.dh.prime, michael@0: &privk->u.dh.prime); michael@0: if (rv != SECSuccess) break; michael@0: rv = SECITEM_CopyItem(arena, &pubk->u.dh.base, michael@0: &privk->u.dh.base); michael@0: if (rv == SECSuccess) return pubk; michael@0: } michael@0: break; michael@0: #ifndef NSS_DISABLE_ECC michael@0: case NSSLOWKEYECKey: michael@0: pubk = (NSSLOWKEYPublicKey *)PORT_ArenaZAlloc(arena, michael@0: sizeof(NSSLOWKEYPublicKey)); michael@0: if (pubk != NULL) { michael@0: SECStatus rv; michael@0: michael@0: pubk->arena = arena; michael@0: pubk->keyType = privk->keyType; michael@0: rv = SECITEM_CopyItem(arena, &pubk->u.ec.publicValue, michael@0: &privk->u.ec.publicValue); michael@0: if (rv != SECSuccess) break; michael@0: pubk->u.ec.ecParams.arena = arena; michael@0: /* Copy the rest of the params */ michael@0: rv = LGEC_CopyParams(arena, &(pubk->u.ec.ecParams), michael@0: &(privk->u.ec.ecParams)); michael@0: if (rv == SECSuccess) return pubk; michael@0: } michael@0: break; michael@0: #endif /* NSS_DISABLE_ECC */ michael@0: /* No Fortezza in Low Key implementations (Fortezza keys aren't michael@0: * stored in our data base */ michael@0: default: michael@0: break; michael@0: } michael@0: michael@0: PORT_FreeArena (arena, PR_FALSE); michael@0: return NULL; michael@0: } michael@0: