| /* This Source Code Form is subject to the terms of the Mozilla Public |
| * License, v. 2.0. If a copy of the MPL was not distributed with this |
| * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
| #include "lowkeyi.h" |
| #include "secoid.h" |
| #include "secitem.h" |
| #include "secder.h" |
| #include "base64.h" |
| #include "secasn1.h" |
| #include "secerr.h" |
| #include "softoken.h" |
| |
| SEC_ASN1_MKSUB(SEC_AnyTemplate) |
| SEC_ASN1_MKSUB(SEC_BitStringTemplate) |
| SEC_ASN1_MKSUB(SEC_ObjectIDTemplate) |
| SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate) |
| |
| const SEC_ASN1Template nsslowkey_AttributeTemplate[] = { |
| { SEC_ASN1_SEQUENCE, |
| 0, NULL, sizeof(NSSLOWKEYAttribute) }, |
| { SEC_ASN1_OBJECT_ID, offsetof(NSSLOWKEYAttribute, attrType) }, |
| { SEC_ASN1_SET_OF | SEC_ASN1_XTRN, |
| offsetof(NSSLOWKEYAttribute, attrValue), |
| SEC_ASN1_SUB(SEC_AnyTemplate) }, |
| { 0 } |
| }; |
| |
| const SEC_ASN1Template nsslowkey_SetOfAttributeTemplate[] = { |
| { SEC_ASN1_SET_OF, 0, nsslowkey_AttributeTemplate }, |
| }; |
| /* ASN1 Templates for new decoder/encoder */ |
| const SEC_ASN1Template nsslowkey_PrivateKeyInfoTemplate[] = { |
| { SEC_ASN1_SEQUENCE, |
| 0, NULL, sizeof(NSSLOWKEYPrivateKeyInfo) }, |
| { SEC_ASN1_INTEGER, |
| offsetof(NSSLOWKEYPrivateKeyInfo, version) }, |
| { SEC_ASN1_INLINE | SEC_ASN1_XTRN, |
| offsetof(NSSLOWKEYPrivateKeyInfo, algorithm), |
| SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) }, |
| { SEC_ASN1_OCTET_STRING, |
| offsetof(NSSLOWKEYPrivateKeyInfo, privateKey) }, |
| { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0, |
| offsetof(NSSLOWKEYPrivateKeyInfo, attributes), |
| nsslowkey_SetOfAttributeTemplate }, |
| { 0 } |
| }; |
| |
| const SEC_ASN1Template nsslowkey_SubjectPublicKeyInfoTemplate[] = { |
| { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(NSSLOWKEYSubjectPublicKeyInfo) }, |
| { SEC_ASN1_INLINE | SEC_ASN1_XTRN, |
| offsetof(NSSLOWKEYSubjectPublicKeyInfo, algorithm), |
| SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) }, |
| { SEC_ASN1_BIT_STRING, |
| offsetof(NSSLOWKEYSubjectPublicKeyInfo, subjectPublicKey) }, |
| { 0 } |
| }; |
| |
| const SEC_ASN1Template nsslowkey_RSAPublicKeyTemplate[] = { |
| { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(NSSLOWKEYPublicKey) }, |
| { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPublicKey, u.rsa.modulus) }, |
| { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPublicKey, u.rsa.publicExponent) }, |
| { 0 } |
| }; |
| |
| const SEC_ASN1Template nsslowkey_PQGParamsTemplate[] = { |
| { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(PQGParams) }, |
| { SEC_ASN1_INTEGER, offsetof(PQGParams, prime) }, |
| { SEC_ASN1_INTEGER, offsetof(PQGParams, subPrime) }, |
| { SEC_ASN1_INTEGER, offsetof(PQGParams, base) }, |
| { 0 } |
| }; |
| |
| const SEC_ASN1Template nsslowkey_RSAPrivateKeyTemplate[] = { |
| { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(NSSLOWKEYPrivateKey) }, |
| { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey, u.rsa.version) }, |
| { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey, u.rsa.modulus) }, |
| { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey, u.rsa.publicExponent) }, |
| { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey, u.rsa.privateExponent) }, |
| { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey, u.rsa.prime1) }, |
| { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey, u.rsa.prime2) }, |
| { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey, u.rsa.exponent1) }, |
| { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey, u.rsa.exponent2) }, |
| { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey, u.rsa.coefficient) }, |
| { 0 } |
| }; |
| |
| const SEC_ASN1Template nsslowkey_DSAPrivateKeyTemplate[] = { |
| { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(NSSLOWKEYPrivateKey) }, |
| { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey, u.dsa.publicValue) }, |
| { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey, u.dsa.privateValue) }, |
| { 0 } |
| }; |
| |
| const SEC_ASN1Template nsslowkey_DSAPrivateKeyExportTemplate[] = { |
| { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey, u.dsa.privateValue) }, |
| }; |
| |
| const SEC_ASN1Template nsslowkey_DHPrivateKeyTemplate[] = { |
| { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(NSSLOWKEYPrivateKey) }, |
| { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey, u.dh.publicValue) }, |
| { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey, u.dh.privateValue) }, |
| { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey, u.dh.base) }, |
| { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey, u.dh.prime) }, |
| { 0 } |
| }; |
| |
| /* NOTE: The SECG specification allows the private key structure |
| * to contain curve parameters but recommends that they be stored |
| * in the PrivateKeyAlgorithmIdentifier field of the PrivateKeyInfo |
| * instead. |
| */ |
| const SEC_ASN1Template nsslowkey_ECPrivateKeyTemplate[] = { |
| { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(NSSLOWKEYPrivateKey) }, |
| { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey, u.ec.version) }, |
| { SEC_ASN1_OCTET_STRING, |
| offsetof(NSSLOWKEYPrivateKey, u.ec.privateValue) }, |
| /* We only support named curves for which the parameters are |
| * encoded as an object ID. |
| */ |
| { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | |
| SEC_ASN1_EXPLICIT | SEC_ASN1_CONTEXT_SPECIFIC | |
| SEC_ASN1_XTRN | 0, |
| offsetof(NSSLOWKEYPrivateKey, u.ec.ecParams.curveOID), |
| SEC_ASN1_SUB(SEC_ObjectIDTemplate) }, |
| { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | |
| SEC_ASN1_EXPLICIT | SEC_ASN1_CONTEXT_SPECIFIC | |
| SEC_ASN1_XTRN | 1, |
| offsetof(NSSLOWKEYPrivateKey, u.ec.publicValue), |
| SEC_ASN1_SUB(SEC_BitStringTemplate) }, |
| { 0 } |
| }; |
| /* |
| * See bugzilla bug 125359 |
| * Since NSS (via PKCS#11) wants to handle big integers as unsigned ints, |
| * all of the templates above that en/decode into integers must be converted |
| * from ASN.1's signed integer type. This is done by marking either the |
| * source or destination (encoding or decoding, respectively) type as |
| * siUnsignedInteger. |
| */ |
| |
| void |
| prepare_low_rsa_priv_key_for_asn1(NSSLOWKEYPrivateKey *key) |
| { |
| key->u.rsa.modulus.type = siUnsignedInteger; |
| key->u.rsa.publicExponent.type = siUnsignedInteger; |
| key->u.rsa.privateExponent.type = siUnsignedInteger; |
| key->u.rsa.prime1.type = siUnsignedInteger; |
| key->u.rsa.prime2.type = siUnsignedInteger; |
| key->u.rsa.exponent1.type = siUnsignedInteger; |
| key->u.rsa.exponent2.type = siUnsignedInteger; |
| key->u.rsa.coefficient.type = siUnsignedInteger; |
| } |
| |
| void |
| prepare_low_rsa_pub_key_for_asn1(NSSLOWKEYPublicKey *key) |
| { |
| key->u.rsa.modulus.type = siUnsignedInteger; |
| key->u.rsa.publicExponent.type = siUnsignedInteger; |
| } |
| |
| void |
| prepare_low_pqg_params_for_asn1(PQGParams *params) |
| { |
| params->prime.type = siUnsignedInteger; |
| params->subPrime.type = siUnsignedInteger; |
| params->base.type = siUnsignedInteger; |
| } |
| |
| void |
| prepare_low_dsa_priv_key_for_asn1(NSSLOWKEYPrivateKey *key) |
| { |
| key->u.dsa.publicValue.type = siUnsignedInteger; |
| key->u.dsa.privateValue.type = siUnsignedInteger; |
| key->u.dsa.params.prime.type = siUnsignedInteger; |
| key->u.dsa.params.subPrime.type = siUnsignedInteger; |
| key->u.dsa.params.base.type = siUnsignedInteger; |
| } |
| |
| void |
| prepare_low_dsa_priv_key_export_for_asn1(NSSLOWKEYPrivateKey *key) |
| { |
| key->u.dsa.privateValue.type = siUnsignedInteger; |
| } |
| |
| void |
| prepare_low_dh_priv_key_for_asn1(NSSLOWKEYPrivateKey *key) |
| { |
| key->u.dh.prime.type = siUnsignedInteger; |
| key->u.dh.base.type = siUnsignedInteger; |
| key->u.dh.publicValue.type = siUnsignedInteger; |
| key->u.dh.privateValue.type = siUnsignedInteger; |
| } |
| |
| void |
| prepare_low_ecparams_for_asn1(ECParams *params) |
| { |
| params->DEREncoding.type = siUnsignedInteger; |
| params->curveOID.type = siUnsignedInteger; |
| } |
| |
| void |
| prepare_low_ec_priv_key_for_asn1(NSSLOWKEYPrivateKey *key) |
| { |
| key->u.ec.version.type = siUnsignedInteger; |
| key->u.ec.ecParams.DEREncoding.type = siUnsignedInteger; |
| key->u.ec.ecParams.curveOID.type = siUnsignedInteger; |
| key->u.ec.privateValue.type = siUnsignedInteger; |
| key->u.ec.publicValue.type = siUnsignedInteger; |
| } |
| |
| void |
| nsslowkey_DestroyPrivateKey(NSSLOWKEYPrivateKey *privk) |
| { |
| if (privk && privk->arena) { |
| PORT_FreeArena(privk->arena, PR_TRUE); |
| } |
| } |
| |
| void |
| nsslowkey_DestroyPublicKey(NSSLOWKEYPublicKey *pubk) |
| { |
| if (pubk && pubk->arena) { |
| PORT_FreeArena(pubk->arena, PR_FALSE); |
| } |
| } |
| unsigned |
| nsslowkey_PublicModulusLen(NSSLOWKEYPublicKey *pubk) |
| { |
| unsigned char b0; |
| |
| /* interpret modulus length as key strength... in |
| * fortezza that's the public key length */ |
| |
| switch (pubk->keyType) { |
| case NSSLOWKEYRSAKey: |
| b0 = pubk->u.rsa.modulus.data[0]; |
| return b0 ? pubk->u.rsa.modulus.len : pubk->u.rsa.modulus.len - 1; |
| default: |
| break; |
| } |
| return 0; |
| } |
| |
| unsigned |
| nsslowkey_PrivateModulusLen(NSSLOWKEYPrivateKey *privk) |
| { |
| |
| unsigned char b0; |
| |
| switch (privk->keyType) { |
| case NSSLOWKEYRSAKey: |
| b0 = privk->u.rsa.modulus.data[0]; |
| return b0 ? privk->u.rsa.modulus.len : privk->u.rsa.modulus.len - 1; |
| default: |
| break; |
| } |
| return 0; |
| } |
| |
| NSSLOWKEYPublicKey * |
| nsslowkey_ConvertToPublicKey(NSSLOWKEYPrivateKey *privk) |
| { |
| NSSLOWKEYPublicKey *pubk; |
| PLArenaPool *arena; |
| |
| arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); |
| if (arena == NULL) { |
| PORT_SetError(SEC_ERROR_NO_MEMORY); |
| return NULL; |
| } |
| |
| switch (privk->keyType) { |
| case NSSLOWKEYRSAKey: |
| case NSSLOWKEYNullKey: |
| pubk = (NSSLOWKEYPublicKey *)PORT_ArenaZAlloc(arena, |
| sizeof(NSSLOWKEYPublicKey)); |
| if (pubk != NULL) { |
| SECStatus rv; |
| |
| pubk->arena = arena; |
| pubk->keyType = privk->keyType; |
| if (privk->keyType == NSSLOWKEYNullKey) |
| return pubk; |
| rv = SECITEM_CopyItem(arena, &pubk->u.rsa.modulus, |
| &privk->u.rsa.modulus); |
| if (rv == SECSuccess) { |
| rv = SECITEM_CopyItem(arena, &pubk->u.rsa.publicExponent, |
| &privk->u.rsa.publicExponent); |
| if (rv == SECSuccess) |
| return pubk; |
| } |
| } else { |
| PORT_SetError(SEC_ERROR_NO_MEMORY); |
| } |
| break; |
| case NSSLOWKEYDSAKey: |
| pubk = (NSSLOWKEYPublicKey *)PORT_ArenaZAlloc(arena, |
| sizeof(NSSLOWKEYPublicKey)); |
| if (pubk != NULL) { |
| SECStatus rv; |
| |
| pubk->arena = arena; |
| pubk->keyType = privk->keyType; |
| rv = SECITEM_CopyItem(arena, &pubk->u.dsa.publicValue, |
| &privk->u.dsa.publicValue); |
| if (rv != SECSuccess) |
| break; |
| rv = SECITEM_CopyItem(arena, &pubk->u.dsa.params.prime, |
| &privk->u.dsa.params.prime); |
| if (rv != SECSuccess) |
| break; |
| rv = SECITEM_CopyItem(arena, &pubk->u.dsa.params.subPrime, |
| &privk->u.dsa.params.subPrime); |
| if (rv != SECSuccess) |
| break; |
| rv = SECITEM_CopyItem(arena, &pubk->u.dsa.params.base, |
| &privk->u.dsa.params.base); |
| if (rv == SECSuccess) |
| return pubk; |
| } |
| break; |
| case NSSLOWKEYDHKey: |
| pubk = (NSSLOWKEYPublicKey *)PORT_ArenaZAlloc(arena, |
| sizeof(NSSLOWKEYPublicKey)); |
| if (pubk != NULL) { |
| SECStatus rv; |
| |
| pubk->arena = arena; |
| pubk->keyType = privk->keyType; |
| rv = SECITEM_CopyItem(arena, &pubk->u.dh.publicValue, |
| &privk->u.dh.publicValue); |
| if (rv != SECSuccess) |
| break; |
| rv = SECITEM_CopyItem(arena, &pubk->u.dh.prime, |
| &privk->u.dh.prime); |
| if (rv != SECSuccess) |
| break; |
| rv = SECITEM_CopyItem(arena, &pubk->u.dh.base, |
| &privk->u.dh.base); |
| if (rv == SECSuccess) |
| return pubk; |
| } |
| break; |
| case NSSLOWKEYECKey: |
| pubk = (NSSLOWKEYPublicKey *)PORT_ArenaZAlloc(arena, |
| sizeof(NSSLOWKEYPublicKey)); |
| if (pubk != NULL) { |
| SECStatus rv; |
| |
| pubk->arena = arena; |
| pubk->keyType = privk->keyType; |
| rv = SECITEM_CopyItem(arena, &pubk->u.ec.publicValue, |
| &privk->u.ec.publicValue); |
| if (rv != SECSuccess) |
| break; |
| pubk->u.ec.ecParams.arena = arena; |
| /* Copy the rest of the params */ |
| rv = EC_CopyParams(arena, &(pubk->u.ec.ecParams), |
| &(privk->u.ec.ecParams)); |
| if (rv == SECSuccess) |
| return pubk; |
| } |
| break; |
| /* No Fortezza in Low Key implementations (Fortezza keys aren't |
| * stored in our data base */ |
| default: |
| break; |
| } |
| |
| PORT_FreeArena(arena, PR_FALSE); |
| return NULL; |
| } |
| |
| NSSLOWKEYPrivateKey * |
| nsslowkey_CopyPrivateKey(NSSLOWKEYPrivateKey *privKey) |
| { |
| NSSLOWKEYPrivateKey *returnKey = NULL; |
| SECStatus rv = SECFailure; |
| PLArenaPool *poolp; |
| |
| if (!privKey) { |
| return NULL; |
| } |
| |
| poolp = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); |
| if (!poolp) { |
| return NULL; |
| } |
| |
| returnKey = (NSSLOWKEYPrivateKey *)PORT_ArenaZAlloc(poolp, sizeof(NSSLOWKEYPrivateKey)); |
| if (!returnKey) { |
| rv = SECFailure; |
| goto loser; |
| } |
| |
| returnKey->keyType = privKey->keyType; |
| returnKey->arena = poolp; |
| |
| switch (privKey->keyType) { |
| case NSSLOWKEYRSAKey: |
| rv = SECITEM_CopyItem(poolp, &(returnKey->u.rsa.modulus), |
| &(privKey->u.rsa.modulus)); |
| if (rv != SECSuccess) |
| break; |
| rv = SECITEM_CopyItem(poolp, &(returnKey->u.rsa.version), |
| &(privKey->u.rsa.version)); |
| if (rv != SECSuccess) |
| break; |
| rv = SECITEM_CopyItem(poolp, &(returnKey->u.rsa.publicExponent), |
| &(privKey->u.rsa.publicExponent)); |
| if (rv != SECSuccess) |
| break; |
| rv = SECITEM_CopyItem(poolp, &(returnKey->u.rsa.privateExponent), |
| &(privKey->u.rsa.privateExponent)); |
| if (rv != SECSuccess) |
| break; |
| rv = SECITEM_CopyItem(poolp, &(returnKey->u.rsa.prime1), |
| &(privKey->u.rsa.prime1)); |
| if (rv != SECSuccess) |
| break; |
| rv = SECITEM_CopyItem(poolp, &(returnKey->u.rsa.prime2), |
| &(privKey->u.rsa.prime2)); |
| if (rv != SECSuccess) |
| break; |
| rv = SECITEM_CopyItem(poolp, &(returnKey->u.rsa.exponent1), |
| &(privKey->u.rsa.exponent1)); |
| if (rv != SECSuccess) |
| break; |
| rv = SECITEM_CopyItem(poolp, &(returnKey->u.rsa.exponent2), |
| &(privKey->u.rsa.exponent2)); |
| if (rv != SECSuccess) |
| break; |
| rv = SECITEM_CopyItem(poolp, &(returnKey->u.rsa.coefficient), |
| &(privKey->u.rsa.coefficient)); |
| if (rv != SECSuccess) |
| break; |
| break; |
| case NSSLOWKEYDSAKey: |
| rv = SECITEM_CopyItem(poolp, &(returnKey->u.dsa.publicValue), |
| &(privKey->u.dsa.publicValue)); |
| if (rv != SECSuccess) |
| break; |
| rv = SECITEM_CopyItem(poolp, &(returnKey->u.dsa.privateValue), |
| &(privKey->u.dsa.privateValue)); |
| if (rv != SECSuccess) |
| break; |
| returnKey->u.dsa.params.arena = poolp; |
| rv = SECITEM_CopyItem(poolp, &(returnKey->u.dsa.params.prime), |
| &(privKey->u.dsa.params.prime)); |
| if (rv != SECSuccess) |
| break; |
| rv = SECITEM_CopyItem(poolp, &(returnKey->u.dsa.params.subPrime), |
| &(privKey->u.dsa.params.subPrime)); |
| if (rv != SECSuccess) |
| break; |
| rv = SECITEM_CopyItem(poolp, &(returnKey->u.dsa.params.base), |
| &(privKey->u.dsa.params.base)); |
| if (rv != SECSuccess) |
| break; |
| break; |
| case NSSLOWKEYDHKey: |
| rv = SECITEM_CopyItem(poolp, &(returnKey->u.dh.publicValue), |
| &(privKey->u.dh.publicValue)); |
| if (rv != SECSuccess) |
| break; |
| rv = SECITEM_CopyItem(poolp, &(returnKey->u.dh.privateValue), |
| &(privKey->u.dh.privateValue)); |
| if (rv != SECSuccess) |
| break; |
| returnKey->u.dsa.params.arena = poolp; |
| rv = SECITEM_CopyItem(poolp, &(returnKey->u.dh.prime), |
| &(privKey->u.dh.prime)); |
| if (rv != SECSuccess) |
| break; |
| rv = SECITEM_CopyItem(poolp, &(returnKey->u.dh.base), |
| &(privKey->u.dh.base)); |
| if (rv != SECSuccess) |
| break; |
| break; |
| case NSSLOWKEYECKey: |
| rv = SECITEM_CopyItem(poolp, &(returnKey->u.ec.version), |
| &(privKey->u.ec.version)); |
| if (rv != SECSuccess) |
| break; |
| rv = SECITEM_CopyItem(poolp, &(returnKey->u.ec.publicValue), |
| &(privKey->u.ec.publicValue)); |
| if (rv != SECSuccess) |
| break; |
| rv = SECITEM_CopyItem(poolp, &(returnKey->u.ec.privateValue), |
| &(privKey->u.ec.privateValue)); |
| if (rv != SECSuccess) |
| break; |
| returnKey->u.ec.ecParams.arena = poolp; |
| /* Copy the rest of the params */ |
| rv = EC_CopyParams(poolp, &(returnKey->u.ec.ecParams), |
| &(privKey->u.ec.ecParams)); |
| if (rv != SECSuccess) |
| break; |
| break; |
| default: |
| rv = SECFailure; |
| } |
| |
| loser: |
| |
| if (rv != SECSuccess) { |
| PORT_FreeArena(poolp, PR_TRUE); |
| returnKey = NULL; |
| } |
| |
| return returnKey; |
| } |