/* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is the Netscape security libraries. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1994-2000 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Dr Stephen Henson * Dr Vipul Gupta , Sun Microsystems Laboratories * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ /* * This file maps various PKCS #11 Mechanisms to related mechanisms, key * types, and ASN.1 encodings. */ #include "seccomon.h" #include "secmod.h" #include "secmodi.h" #include "pkcs11t.h" #include "pk11func.h" #include "secitem.h" #include "secder.h" #include "secasn1.h" #include "secoid.h" #include "secerr.h" /************************************************************* * local static and global data *************************************************************/ /* * Tables used for Extended mechanism mapping (currently not used) */ typedef struct { CK_MECHANISM_TYPE keyGen; CK_KEY_TYPE keyType; CK_MECHANISM_TYPE type; int blockSize; int iv; } pk11MechanismData; static pk11MechanismData pk11_default = { CKM_GENERIC_SECRET_KEY_GEN, CKK_GENERIC_SECRET, CKM_FAKE_RANDOM, 8, 8 }; static pk11MechanismData *pk11_MechanismTable = NULL; static int pk11_MechTableSize = 0; static int pk11_MechEntrySize = 0; /* * list of mechanisms we're willing to wrap secret keys with. * This list is ordered by preference. */ CK_MECHANISM_TYPE wrapMechanismList[] = { CKM_DES3_ECB, CKM_CAST5_ECB, CKM_AES_ECB, CKM_CAST5_ECB, CKM_DES_ECB, CKM_KEY_WRAP_LYNKS, CKM_IDEA_ECB, CKM_CAST3_ECB, CKM_CAST_ECB, CKM_RC5_ECB, CKM_RC2_ECB, CKM_CDMF_ECB, CKM_SKIPJACK_WRAP, }; int wrapMechanismCount = sizeof(wrapMechanismList)/sizeof(wrapMechanismList[0]); /********************************************************************* * Mechanism Mapping functions *********************************************************************/ /* * lookup an entry in the mechanism table. If none found, return the * default structure. */ static pk11MechanismData * pk11_lookup(CK_MECHANISM_TYPE type) { int i; for (i=0; i < pk11_MechEntrySize; i++) { if (pk11_MechanismTable[i].type == type) { return (&pk11_MechanismTable[i]); } } return &pk11_default; } /* * find the best key wrap mechanism for this slot. */ CK_MECHANISM_TYPE PK11_GetBestWrapMechanism(PK11SlotInfo *slot) { int i; for (i=0; i < wrapMechanismCount; i++) { if (PK11_DoesMechanism(slot,wrapMechanismList[i])) { return wrapMechanismList[i]; } } return CKM_INVALID_MECHANISM; } /* * NOTE: This is not thread safe. Called at init time, and when loading * a new Entry. It is reasonably safe as long as it is not re-entered * (readers will always see a consistant table) * * This routine is called to add entries to the mechanism table, once there, * they can not be removed. */ void PK11_AddMechanismEntry(CK_MECHANISM_TYPE type, CK_KEY_TYPE key, CK_MECHANISM_TYPE keyGen, int ivLen, int blockSize) { int tableSize = pk11_MechTableSize; int size = pk11_MechEntrySize; int entry = size++; pk11MechanismData *old = pk11_MechanismTable; pk11MechanismData *newt = pk11_MechanismTable; if (size > tableSize) { int oldTableSize = tableSize; tableSize += 10; newt = PORT_NewArray(pk11MechanismData, tableSize); if (newt == NULL) return; if (old) PORT_Memcpy(newt, old, oldTableSize*sizeof(*newt)); } else old = NULL; newt[entry].type = type; newt[entry].keyType = key; newt[entry].keyGen = keyGen; newt[entry].iv = ivLen; newt[entry].blockSize = blockSize; pk11_MechanismTable = newt; pk11_MechTableSize = tableSize; pk11_MechEntrySize = size; if (old) PORT_Free(old); } /* * Get the key type needed for the given mechanism */ CK_MECHANISM_TYPE PK11_GetKeyMechanism(CK_KEY_TYPE type) { switch (type) { case CKK_AES: return CKM_AES_CBC; case CKK_DES: return CKM_DES_CBC; case CKK_DES3: return CKM_DES3_KEY_GEN; case CKK_DES2: return CKM_DES2_KEY_GEN; case CKK_CDMF: return CKM_CDMF_CBC; case CKK_RC2: return CKM_RC2_CBC; case CKK_RC4: return CKM_RC4; case CKK_RC5: return CKM_RC5_CBC; case CKK_SKIPJACK: return CKM_SKIPJACK_CBC64; case CKK_BATON: return CKM_BATON_CBC128; case CKK_JUNIPER: return CKM_JUNIPER_CBC128; case CKK_IDEA: return CKM_IDEA_CBC; case CKK_CAST: return CKM_CAST_CBC; case CKK_CAST3: return CKM_CAST3_CBC; case CKK_CAST5: return CKM_CAST5_CBC; case CKK_RSA: return CKM_RSA_PKCS; case CKK_DSA: return CKM_DSA; case CKK_DH: return CKM_DH_PKCS_DERIVE; case CKK_KEA: return CKM_KEA_KEY_DERIVE; case CKK_EC: /* CKK_ECDSA is deprecated */ return CKM_ECDSA; case CKK_GENERIC_SECRET: default: return CKM_SHA_1_HMAC; } } /* * Get the key type needed for the given mechanism */ CK_MECHANISM_TYPE PK11_GetKeyType(CK_MECHANISM_TYPE type,unsigned long len) { switch (type) { case CKM_AES_ECB: case CKM_AES_CBC: case CKM_AES_MAC: case CKM_AES_MAC_GENERAL: case CKM_AES_CBC_PAD: case CKM_AES_KEY_GEN: case CKM_NETSCAPE_AES_KEY_WRAP: case CKM_NETSCAPE_AES_KEY_WRAP_PAD: return CKK_AES; case CKM_DES_ECB: case CKM_DES_CBC: case CKM_DES_MAC: case CKM_DES_MAC_GENERAL: case CKM_DES_CBC_PAD: case CKM_DES_KEY_GEN: case CKM_KEY_WRAP_LYNKS: case CKM_PBE_MD2_DES_CBC: case CKM_PBE_MD5_DES_CBC: return CKK_DES; case CKM_DES3_ECB: case CKM_DES3_CBC: case CKM_DES3_MAC: case CKM_DES3_MAC_GENERAL: case CKM_DES3_CBC_PAD: return (len == 16) ? CKK_DES2 : CKK_DES3; case CKM_DES2_KEY_GEN: case CKM_PBE_SHA1_DES2_EDE_CBC: return CKK_DES2; case CKM_PBE_SHA1_DES3_EDE_CBC: case CKM_DES3_KEY_GEN: return CKK_DES3; case CKM_CDMF_ECB: case CKM_CDMF_CBC: case CKM_CDMF_MAC: case CKM_CDMF_MAC_GENERAL: case CKM_CDMF_CBC_PAD: case CKM_CDMF_KEY_GEN: return CKK_CDMF; case CKM_RC2_ECB: case CKM_RC2_CBC: case CKM_RC2_MAC: case CKM_RC2_MAC_GENERAL: case CKM_RC2_CBC_PAD: case CKM_RC2_KEY_GEN: case CKM_PBE_SHA1_RC2_128_CBC: case CKM_PBE_SHA1_RC2_40_CBC: return CKK_RC2; case CKM_RC4: case CKM_RC4_KEY_GEN: return CKK_RC4; case CKM_RC5_ECB: case CKM_RC5_CBC: case CKM_RC5_MAC: case CKM_RC5_MAC_GENERAL: case CKM_RC5_CBC_PAD: case CKM_RC5_KEY_GEN: return CKK_RC5; case CKM_SKIPJACK_CBC64: case CKM_SKIPJACK_ECB64: case CKM_SKIPJACK_OFB64: case CKM_SKIPJACK_CFB64: case CKM_SKIPJACK_CFB32: case CKM_SKIPJACK_CFB16: case CKM_SKIPJACK_CFB8: case CKM_SKIPJACK_KEY_GEN: case CKM_SKIPJACK_WRAP: case CKM_SKIPJACK_PRIVATE_WRAP: return CKK_SKIPJACK; case CKM_BATON_ECB128: case CKM_BATON_ECB96: case CKM_BATON_CBC128: case CKM_BATON_COUNTER: case CKM_BATON_SHUFFLE: case CKM_BATON_WRAP: case CKM_BATON_KEY_GEN: return CKK_BATON; case CKM_JUNIPER_ECB128: case CKM_JUNIPER_CBC128: case CKM_JUNIPER_COUNTER: case CKM_JUNIPER_SHUFFLE: case CKM_JUNIPER_WRAP: case CKM_JUNIPER_KEY_GEN: return CKK_JUNIPER; case CKM_IDEA_CBC: case CKM_IDEA_ECB: case CKM_IDEA_MAC: case CKM_IDEA_MAC_GENERAL: case CKM_IDEA_CBC_PAD: case CKM_IDEA_KEY_GEN: return CKK_IDEA; case CKM_CAST_ECB: case CKM_CAST_CBC: case CKM_CAST_MAC: case CKM_CAST_MAC_GENERAL: case CKM_CAST_CBC_PAD: case CKM_CAST_KEY_GEN: case CKM_PBE_MD5_CAST_CBC: return CKK_CAST; case CKM_CAST3_ECB: case CKM_CAST3_CBC: case CKM_CAST3_MAC: case CKM_CAST3_MAC_GENERAL: case CKM_CAST3_CBC_PAD: case CKM_CAST3_KEY_GEN: case CKM_PBE_MD5_CAST3_CBC: return CKK_CAST3; case CKM_CAST5_ECB: case CKM_CAST5_CBC: case CKM_CAST5_MAC: case CKM_CAST5_MAC_GENERAL: case CKM_CAST5_CBC_PAD: case CKM_CAST5_KEY_GEN: case CKM_PBE_MD5_CAST5_CBC: return CKK_CAST5; case CKM_RSA_PKCS: case CKM_RSA_9796: case CKM_RSA_X_509: case CKM_MD2_RSA_PKCS: case CKM_MD5_RSA_PKCS: case CKM_SHA1_RSA_PKCS: case CKM_SHA256_RSA_PKCS: case CKM_SHA384_RSA_PKCS: case CKM_SHA512_RSA_PKCS: case CKM_KEY_WRAP_SET_OAEP: case CKM_RSA_PKCS_KEY_PAIR_GEN: case CKM_RSA_X9_31_KEY_PAIR_GEN: return CKK_RSA; case CKM_DSA: case CKM_DSA_SHA1: case CKM_DSA_KEY_PAIR_GEN: return CKK_DSA; case CKM_DH_PKCS_DERIVE: case CKM_DH_PKCS_KEY_PAIR_GEN: return CKK_DH; case CKM_KEA_KEY_DERIVE: case CKM_KEA_KEY_PAIR_GEN: return CKK_KEA; case CKM_ECDSA: case CKM_ECDSA_SHA1: case CKM_EC_KEY_PAIR_GEN: /* aka CKM_ECDSA_KEY_PAIR_GEN */ case CKM_ECDH1_DERIVE: return CKK_EC; /* CKK_ECDSA is deprecated */ case CKM_SSL3_PRE_MASTER_KEY_GEN: case CKM_GENERIC_SECRET_KEY_GEN: case CKM_SSL3_MASTER_KEY_DERIVE: case CKM_SSL3_MASTER_KEY_DERIVE_DH: case CKM_SSL3_KEY_AND_MAC_DERIVE: case CKM_SSL3_SHA1_MAC: case CKM_SSL3_MD5_MAC: case CKM_TLS_MASTER_KEY_DERIVE: case CKM_TLS_MASTER_KEY_DERIVE_DH: case CKM_TLS_KEY_AND_MAC_DERIVE: case CKM_SHA_1_HMAC: case CKM_SHA_1_HMAC_GENERAL: case CKM_SHA256_HMAC: case CKM_SHA256_HMAC_GENERAL: case CKM_SHA384_HMAC: case CKM_SHA384_HMAC_GENERAL: case CKM_SHA512_HMAC: case CKM_SHA512_HMAC_GENERAL: case CKM_MD2_HMAC: case CKM_MD2_HMAC_GENERAL: case CKM_MD5_HMAC: case CKM_MD5_HMAC_GENERAL: case CKM_TLS_PRF_GENERAL: return CKK_GENERIC_SECRET; default: return pk11_lookup(type)->keyType; } } /* * Get the Key Gen Mechanism needed for the given * crypto mechanism */ CK_MECHANISM_TYPE PK11_GetKeyGen(CK_MECHANISM_TYPE type) { return PK11_GetKeyGenWithSize(type, 0); } CK_MECHANISM_TYPE PK11_GetKeyGenWithSize(CK_MECHANISM_TYPE type, int size) { switch (type) { case CKM_AES_ECB: case CKM_AES_CBC: case CKM_AES_MAC: case CKM_AES_MAC_GENERAL: case CKM_AES_CBC_PAD: case CKM_AES_KEY_GEN: return CKM_AES_KEY_GEN; case CKM_DES_ECB: case CKM_DES_CBC: case CKM_DES_MAC: case CKM_DES_MAC_GENERAL: case CKM_KEY_WRAP_LYNKS: case CKM_DES_CBC_PAD: case CKM_DES_KEY_GEN: return CKM_DES_KEY_GEN; case CKM_DES3_ECB: case CKM_DES3_CBC: case CKM_DES3_MAC: case CKM_DES3_MAC_GENERAL: case CKM_DES3_CBC_PAD: return (size == 16) ? CKM_DES2_KEY_GEN : CKM_DES3_KEY_GEN; case CKM_DES3_KEY_GEN: return CKM_DES3_KEY_GEN; case CKM_DES2_KEY_GEN: return CKM_DES2_KEY_GEN; case CKM_CDMF_ECB: case CKM_CDMF_CBC: case CKM_CDMF_MAC: case CKM_CDMF_MAC_GENERAL: case CKM_CDMF_CBC_PAD: case CKM_CDMF_KEY_GEN: return CKM_CDMF_KEY_GEN; case CKM_RC2_ECB: case CKM_RC2_CBC: case CKM_RC2_MAC: case CKM_RC2_MAC_GENERAL: case CKM_RC2_CBC_PAD: case CKM_RC2_KEY_GEN: return CKM_RC2_KEY_GEN; case CKM_RC4: case CKM_RC4_KEY_GEN: return CKM_RC4_KEY_GEN; case CKM_RC5_ECB: case CKM_RC5_CBC: case CKM_RC5_MAC: case CKM_RC5_MAC_GENERAL: case CKM_RC5_CBC_PAD: case CKM_RC5_KEY_GEN: return CKM_RC5_KEY_GEN; case CKM_SKIPJACK_CBC64: case CKM_SKIPJACK_ECB64: case CKM_SKIPJACK_OFB64: case CKM_SKIPJACK_CFB64: case CKM_SKIPJACK_CFB32: case CKM_SKIPJACK_CFB16: case CKM_SKIPJACK_CFB8: case CKM_SKIPJACK_WRAP: case CKM_SKIPJACK_KEY_GEN: return CKM_SKIPJACK_KEY_GEN; case CKM_BATON_ECB128: case CKM_BATON_ECB96: case CKM_BATON_CBC128: case CKM_BATON_COUNTER: case CKM_BATON_SHUFFLE: case CKM_BATON_WRAP: case CKM_BATON_KEY_GEN: return CKM_BATON_KEY_GEN; case CKM_JUNIPER_ECB128: case CKM_JUNIPER_CBC128: case CKM_JUNIPER_COUNTER: case CKM_JUNIPER_SHUFFLE: case CKM_JUNIPER_WRAP: case CKM_JUNIPER_KEY_GEN: return CKM_JUNIPER_KEY_GEN; case CKM_IDEA_CBC: case CKM_IDEA_ECB: case CKM_IDEA_MAC: case CKM_IDEA_MAC_GENERAL: case CKM_IDEA_CBC_PAD: case CKM_IDEA_KEY_GEN: return CKM_IDEA_KEY_GEN; case CKM_CAST_ECB: case CKM_CAST_CBC: case CKM_CAST_MAC: case CKM_CAST_MAC_GENERAL: case CKM_CAST_CBC_PAD: case CKM_CAST_KEY_GEN: return CKM_CAST_KEY_GEN; case CKM_CAST3_ECB: case CKM_CAST3_CBC: case CKM_CAST3_MAC: case CKM_CAST3_MAC_GENERAL: case CKM_CAST3_CBC_PAD: case CKM_CAST3_KEY_GEN: return CKM_CAST3_KEY_GEN; case CKM_CAST5_ECB: case CKM_CAST5_CBC: case CKM_CAST5_MAC: case CKM_CAST5_MAC_GENERAL: case CKM_CAST5_CBC_PAD: case CKM_CAST5_KEY_GEN: return CKM_CAST5_KEY_GEN; case CKM_RSA_PKCS: case CKM_RSA_9796: case CKM_RSA_X_509: case CKM_MD2_RSA_PKCS: case CKM_MD5_RSA_PKCS: case CKM_SHA1_RSA_PKCS: case CKM_SHA256_RSA_PKCS: case CKM_SHA384_RSA_PKCS: case CKM_SHA512_RSA_PKCS: case CKM_KEY_WRAP_SET_OAEP: case CKM_RSA_PKCS_KEY_PAIR_GEN: return CKM_RSA_PKCS_KEY_PAIR_GEN; case CKM_RSA_X9_31_KEY_PAIR_GEN: return CKM_RSA_X9_31_KEY_PAIR_GEN; case CKM_DSA: case CKM_DSA_SHA1: case CKM_DSA_KEY_PAIR_GEN: return CKM_DSA_KEY_PAIR_GEN; case CKM_DH_PKCS_DERIVE: case CKM_DH_PKCS_KEY_PAIR_GEN: return CKM_DH_PKCS_KEY_PAIR_GEN; case CKM_KEA_KEY_DERIVE: case CKM_KEA_KEY_PAIR_GEN: return CKM_KEA_KEY_PAIR_GEN; case CKM_ECDSA: case CKM_ECDSA_SHA1: case CKM_EC_KEY_PAIR_GEN: /* aka CKM_ECDSA_KEY_PAIR_GEN */ case CKM_ECDH1_DERIVE: return CKM_EC_KEY_PAIR_GEN; case CKM_SSL3_PRE_MASTER_KEY_GEN: case CKM_SSL3_MASTER_KEY_DERIVE: case CKM_SSL3_KEY_AND_MAC_DERIVE: case CKM_SSL3_SHA1_MAC: case CKM_SSL3_MD5_MAC: case CKM_TLS_MASTER_KEY_DERIVE: case CKM_TLS_KEY_AND_MAC_DERIVE: return CKM_SSL3_PRE_MASTER_KEY_GEN; case CKM_SHA_1_HMAC: case CKM_SHA_1_HMAC_GENERAL: case CKM_SHA256_HMAC: case CKM_SHA256_HMAC_GENERAL: case CKM_SHA384_HMAC: case CKM_SHA384_HMAC_GENERAL: case CKM_SHA512_HMAC: case CKM_SHA512_HMAC_GENERAL: case CKM_MD2_HMAC: case CKM_MD2_HMAC_GENERAL: case CKM_MD5_HMAC: case CKM_MD5_HMAC_GENERAL: case CKM_TLS_PRF_GENERAL: case CKM_GENERIC_SECRET_KEY_GEN: return CKM_GENERIC_SECRET_KEY_GEN; case CKM_PBE_MD2_DES_CBC: case CKM_PBE_MD5_DES_CBC: case CKM_PBA_SHA1_WITH_SHA1_HMAC: case CKM_NETSCAPE_PBE_SHA1_HMAC_KEY_GEN: case CKM_NETSCAPE_PBE_MD5_HMAC_KEY_GEN: case CKM_NETSCAPE_PBE_MD2_HMAC_KEY_GEN: case CKM_NETSCAPE_PBE_SHA1_DES_CBC: case CKM_NETSCAPE_PBE_SHA1_40_BIT_RC2_CBC: case CKM_NETSCAPE_PBE_SHA1_128_BIT_RC2_CBC: case CKM_NETSCAPE_PBE_SHA1_40_BIT_RC4: case CKM_NETSCAPE_PBE_SHA1_128_BIT_RC4: case CKM_NETSCAPE_PBE_SHA1_TRIPLE_DES_CBC: case CKM_NETSCAPE_PBE_SHA1_FAULTY_3DES_CBC: case CKM_PBE_SHA1_RC2_40_CBC: case CKM_PBE_SHA1_RC2_128_CBC: case CKM_PBE_SHA1_RC4_40: case CKM_PBE_SHA1_RC4_128: case CKM_PBE_SHA1_DES3_EDE_CBC: case CKM_PBE_SHA1_DES2_EDE_CBC: return type; default: return pk11_lookup(type)->keyGen; } } /* * get the mechanism block size */ int PK11_GetBlockSize(CK_MECHANISM_TYPE type,SECItem *params) { CK_RC5_PARAMS *rc5_params; CK_RC5_CBC_PARAMS *rc5_cbc_params; switch (type) { case CKM_RC5_ECB: if ((params) && (params->data)) { rc5_params = (CK_RC5_PARAMS *) params->data; return (rc5_params->ulWordsize)*2; } return 8; case CKM_RC5_CBC: case CKM_RC5_CBC_PAD: if ((params) && (params->data)) { rc5_cbc_params = (CK_RC5_CBC_PARAMS *) params->data; return (rc5_cbc_params->ulWordsize)*2; } return 8; case CKM_DES_ECB: case CKM_DES3_ECB: case CKM_RC2_ECB: case CKM_IDEA_ECB: case CKM_CAST_ECB: case CKM_CAST3_ECB: case CKM_CAST5_ECB: case CKM_RC2_CBC: case CKM_SKIPJACK_CBC64: case CKM_SKIPJACK_ECB64: case CKM_SKIPJACK_OFB64: case CKM_SKIPJACK_CFB64: case CKM_DES_CBC: case CKM_DES3_CBC: case CKM_IDEA_CBC: case CKM_CAST_CBC: case CKM_CAST3_CBC: case CKM_CAST5_CBC: case CKM_DES_CBC_PAD: case CKM_DES3_CBC_PAD: case CKM_RC2_CBC_PAD: case CKM_IDEA_CBC_PAD: case CKM_CAST_CBC_PAD: case CKM_CAST3_CBC_PAD: case CKM_CAST5_CBC_PAD: case CKM_PBE_MD2_DES_CBC: case CKM_PBE_MD5_DES_CBC: case CKM_NETSCAPE_PBE_SHA1_DES_CBC: case CKM_NETSCAPE_PBE_SHA1_40_BIT_RC2_CBC: case CKM_NETSCAPE_PBE_SHA1_128_BIT_RC2_CBC: case CKM_NETSCAPE_PBE_SHA1_TRIPLE_DES_CBC: case CKM_NETSCAPE_PBE_SHA1_FAULTY_3DES_CBC: case CKM_PBE_SHA1_RC2_40_CBC: case CKM_PBE_SHA1_RC2_128_CBC: case CKM_PBE_SHA1_DES3_EDE_CBC: case CKM_PBE_SHA1_DES2_EDE_CBC: return 8; case CKM_SKIPJACK_CFB32: case CKM_SKIPJACK_CFB16: case CKM_SKIPJACK_CFB8: return 4; case CKM_AES_ECB: case CKM_AES_CBC: case CKM_AES_CBC_PAD: case CKM_BATON_ECB128: case CKM_BATON_CBC128: case CKM_BATON_COUNTER: case CKM_BATON_SHUFFLE: case CKM_JUNIPER_ECB128: case CKM_JUNIPER_CBC128: case CKM_JUNIPER_COUNTER: case CKM_JUNIPER_SHUFFLE: return 16; case CKM_BATON_ECB96: return 12; case CKM_RC4: case CKM_NETSCAPE_PBE_SHA1_40_BIT_RC4: case CKM_NETSCAPE_PBE_SHA1_128_BIT_RC4: case CKM_PBE_SHA1_RC4_40: case CKM_PBE_SHA1_RC4_128: return 0; case CKM_RSA_PKCS: case CKM_RSA_9796: case CKM_RSA_X_509: /*actually it's the modulus length of the key!*/ return -1; /* failure */ default: return pk11_lookup(type)->blockSize; } } /* * get the iv length */ int PK11_GetIVLength(CK_MECHANISM_TYPE type) { switch (type) { case CKM_AES_ECB: case CKM_DES_ECB: case CKM_DES3_ECB: case CKM_RC2_ECB: case CKM_IDEA_ECB: case CKM_SKIPJACK_WRAP: case CKM_BATON_WRAP: case CKM_RC5_ECB: case CKM_CAST_ECB: case CKM_CAST3_ECB: case CKM_CAST5_ECB: return 0; case CKM_RC2_CBC: case CKM_DES_CBC: case CKM_DES3_CBC: case CKM_IDEA_CBC: case CKM_PBE_MD2_DES_CBC: case CKM_PBE_MD5_DES_CBC: case CKM_NETSCAPE_PBE_SHA1_DES_CBC: case CKM_NETSCAPE_PBE_SHA1_40_BIT_RC2_CBC: case CKM_NETSCAPE_PBE_SHA1_128_BIT_RC2_CBC: case CKM_NETSCAPE_PBE_SHA1_TRIPLE_DES_CBC: case CKM_NETSCAPE_PBE_SHA1_FAULTY_3DES_CBC: case CKM_PBE_SHA1_RC2_40_CBC: case CKM_PBE_SHA1_RC2_128_CBC: case CKM_PBE_SHA1_DES3_EDE_CBC: case CKM_PBE_SHA1_DES2_EDE_CBC: case CKM_RC5_CBC: case CKM_CAST_CBC: case CKM_CAST3_CBC: case CKM_CAST5_CBC: case CKM_RC2_CBC_PAD: case CKM_DES_CBC_PAD: case CKM_DES3_CBC_PAD: case CKM_IDEA_CBC_PAD: case CKM_RC5_CBC_PAD: case CKM_CAST_CBC_PAD: case CKM_CAST3_CBC_PAD: case CKM_CAST5_CBC_PAD: return 8; case CKM_AES_CBC: case CKM_AES_CBC_PAD: return 16; case CKM_SKIPJACK_CBC64: case CKM_SKIPJACK_ECB64: case CKM_SKIPJACK_OFB64: case CKM_SKIPJACK_CFB64: case CKM_SKIPJACK_CFB32: case CKM_SKIPJACK_CFB16: case CKM_SKIPJACK_CFB8: case CKM_BATON_ECB128: case CKM_BATON_ECB96: case CKM_BATON_CBC128: case CKM_BATON_COUNTER: case CKM_BATON_SHUFFLE: case CKM_JUNIPER_ECB128: case CKM_JUNIPER_CBC128: case CKM_JUNIPER_COUNTER: case CKM_JUNIPER_SHUFFLE: return 24; case CKM_RC4: case CKM_RSA_PKCS: case CKM_RSA_9796: case CKM_RSA_X_509: case CKM_NETSCAPE_PBE_SHA1_40_BIT_RC4: case CKM_NETSCAPE_PBE_SHA1_128_BIT_RC4: case CKM_PBE_SHA1_RC4_40: case CKM_PBE_SHA1_RC4_128: return 0; default: return pk11_lookup(type)->iv; } } /* These next two utilities are here to help facilitate future * Dynamic Encrypt/Decrypt symetric key mechanisms, and to allow functions * like SSL and S-MIME to automatically add them. */ SECItem * PK11_ParamFromIV(CK_MECHANISM_TYPE type,SECItem *iv) { CK_RC2_CBC_PARAMS *rc2_params = NULL; CK_RC2_PARAMS *rc2_ecb_params = NULL; CK_RC5_PARAMS *rc5_params = NULL; CK_RC5_CBC_PARAMS *rc5_cbc_params = NULL; SECItem *param; param = (SECItem *)PORT_Alloc(sizeof(SECItem)); if (param == NULL) return NULL; param->data = NULL; param->len = 0; param->type = 0; switch (type) { case CKM_AES_ECB: case CKM_DES_ECB: case CKM_DES3_ECB: case CKM_RSA_PKCS: case CKM_RSA_X_509: case CKM_RSA_9796: case CKM_IDEA_ECB: case CKM_CDMF_ECB: case CKM_CAST_ECB: case CKM_CAST3_ECB: case CKM_CAST5_ECB: case CKM_RC4: break; case CKM_RC2_ECB: rc2_ecb_params = (CK_RC2_PARAMS *)PORT_Alloc(sizeof(CK_RC2_PARAMS)); if (rc2_ecb_params == NULL) break; /* Maybe we should pass the key size in too to get this value? */ *rc2_ecb_params = 128; param->data = (unsigned char *) rc2_ecb_params; param->len = sizeof(CK_RC2_PARAMS); break; case CKM_RC2_CBC: case CKM_RC2_CBC_PAD: rc2_params = (CK_RC2_CBC_PARAMS *)PORT_Alloc(sizeof(CK_RC2_CBC_PARAMS)); if (rc2_params == NULL) break; /* Maybe we should pass the key size in too to get this value? */ rc2_params->ulEffectiveBits = 128; if (iv && iv->data) PORT_Memcpy(rc2_params->iv,iv->data,sizeof(rc2_params->iv)); param->data = (unsigned char *) rc2_params; param->len = sizeof(CK_RC2_CBC_PARAMS); break; case CKM_RC5_CBC: case CKM_RC5_CBC_PAD: rc5_cbc_params = (CK_RC5_CBC_PARAMS *) PORT_Alloc(sizeof(CK_RC5_CBC_PARAMS) + ((iv) ? iv->len : 0)); if (rc5_cbc_params == NULL) break; if (iv && iv->data && iv->len) { rc5_cbc_params->pIv = ((CK_BYTE_PTR) rc5_cbc_params) + sizeof(CK_RC5_CBC_PARAMS); PORT_Memcpy(rc5_cbc_params->pIv,iv->data,iv->len); rc5_cbc_params->ulIvLen = iv->len; rc5_cbc_params->ulWordsize = iv->len/2; } else { rc5_cbc_params->ulWordsize = 4; rc5_cbc_params->pIv = NULL; rc5_cbc_params->ulIvLen = 0; } rc5_cbc_params->ulRounds = 16; param->data = (unsigned char *) rc5_cbc_params; param->len = sizeof(CK_RC5_CBC_PARAMS); break; case CKM_RC5_ECB: rc5_params = (CK_RC5_PARAMS *)PORT_Alloc(sizeof(CK_RC5_PARAMS)); if (rc5_params == NULL) break; if (iv && iv->data && iv->len) { rc5_params->ulWordsize = iv->len/2; } else { rc5_params->ulWordsize = 4; } rc5_params->ulRounds = 16; param->data = (unsigned char *) rc5_params; param->len = sizeof(CK_RC5_PARAMS); break; case CKM_AES_CBC: case CKM_DES_CBC: case CKM_DES3_CBC: case CKM_IDEA_CBC: case CKM_CDMF_CBC: case CKM_CAST_CBC: case CKM_CAST3_CBC: case CKM_CAST5_CBC: case CKM_AES_CBC_PAD: case CKM_DES_CBC_PAD: case CKM_DES3_CBC_PAD: case CKM_IDEA_CBC_PAD: case CKM_CDMF_CBC_PAD: case CKM_CAST_CBC_PAD: case CKM_CAST3_CBC_PAD: case CKM_CAST5_CBC_PAD: case CKM_SKIPJACK_CBC64: case CKM_SKIPJACK_ECB64: case CKM_SKIPJACK_OFB64: case CKM_SKIPJACK_CFB64: case CKM_SKIPJACK_CFB32: case CKM_SKIPJACK_CFB16: case CKM_SKIPJACK_CFB8: case CKM_BATON_ECB128: case CKM_BATON_ECB96: case CKM_BATON_CBC128: case CKM_BATON_COUNTER: case CKM_BATON_SHUFFLE: case CKM_JUNIPER_ECB128: case CKM_JUNIPER_CBC128: case CKM_JUNIPER_COUNTER: case CKM_JUNIPER_SHUFFLE: if ((iv == NULL) || (iv->data == NULL)) break; param->data = (unsigned char*)PORT_Alloc(iv->len); if (param->data != NULL) { PORT_Memcpy(param->data,iv->data,iv->len); param->len = iv->len; } break; /* unknown mechanism, pass IV in if it's there */ default: if (pk11_lookup(type)->iv == 0) { break; } if ((iv == NULL) || (iv->data == NULL)) { break; } param->data = (unsigned char*)PORT_Alloc(iv->len); if (param->data != NULL) { PORT_Memcpy(param->data,iv->data,iv->len); param->len = iv->len; } break; } return param; } unsigned char * PK11_IVFromParam(CK_MECHANISM_TYPE type,SECItem *param,int *len) { CK_RC2_CBC_PARAMS *rc2_params; CK_RC5_CBC_PARAMS *rc5_cbc_params; *len = 0; switch (type) { case CKM_AES_ECB: case CKM_DES_ECB: case CKM_DES3_ECB: case CKM_RSA_PKCS: case CKM_RSA_X_509: case CKM_RSA_9796: case CKM_IDEA_ECB: case CKM_CDMF_ECB: case CKM_CAST_ECB: case CKM_CAST3_ECB: case CKM_CAST5_ECB: case CKM_RC4: return NULL; case CKM_RC2_ECB: return NULL; case CKM_RC2_CBC: case CKM_RC2_CBC_PAD: rc2_params = (CK_RC2_CBC_PARAMS *)param->data; *len = sizeof(rc2_params->iv); return &rc2_params->iv[0]; case CKM_RC5_CBC: case CKM_RC5_CBC_PAD: rc5_cbc_params = (CK_RC5_CBC_PARAMS *) param->data; *len = rc5_cbc_params->ulIvLen; return rc5_cbc_params->pIv; case CKM_AES_CBC: case CKM_DES_CBC: case CKM_DES3_CBC: case CKM_IDEA_CBC: case CKM_CDMF_CBC: case CKM_CAST_CBC: case CKM_CAST3_CBC: case CKM_CAST5_CBC: case CKM_DES_CBC_PAD: case CKM_DES3_CBC_PAD: case CKM_IDEA_CBC_PAD: case CKM_CDMF_CBC_PAD: case CKM_CAST_CBC_PAD: case CKM_CAST3_CBC_PAD: case CKM_CAST5_CBC_PAD: case CKM_SKIPJACK_CBC64: case CKM_SKIPJACK_ECB64: case CKM_SKIPJACK_OFB64: case CKM_SKIPJACK_CFB64: case CKM_SKIPJACK_CFB32: case CKM_SKIPJACK_CFB16: case CKM_SKIPJACK_CFB8: case CKM_BATON_ECB128: case CKM_BATON_ECB96: case CKM_BATON_CBC128: case CKM_BATON_COUNTER: case CKM_BATON_SHUFFLE: case CKM_JUNIPER_ECB128: case CKM_JUNIPER_CBC128: case CKM_JUNIPER_COUNTER: case CKM_JUNIPER_SHUFFLE: break; /* unknown mechanism, pass IV in if it's there */ default: break; } if (param->data) { *len = param->len; } return param->data; } typedef struct sec_rc5cbcParameterStr { SECItem version; SECItem rounds; SECItem blockSizeInBits; SECItem iv; } sec_rc5cbcParameter; static const SEC_ASN1Template sec_rc5ecb_parameter_template[] = { { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(sec_rc5cbcParameter) }, { SEC_ASN1_INTEGER, offsetof(sec_rc5cbcParameter,version) }, { SEC_ASN1_INTEGER, offsetof(sec_rc5cbcParameter,rounds) }, { SEC_ASN1_INTEGER, offsetof(sec_rc5cbcParameter,blockSizeInBits) }, { 0 } }; static const SEC_ASN1Template sec_rc5cbc_parameter_template[] = { { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(sec_rc5cbcParameter) }, { SEC_ASN1_INTEGER, offsetof(sec_rc5cbcParameter,version) }, { SEC_ASN1_INTEGER, offsetof(sec_rc5cbcParameter,rounds) }, { SEC_ASN1_INTEGER, offsetof(sec_rc5cbcParameter,blockSizeInBits) }, { SEC_ASN1_OCTET_STRING, offsetof(sec_rc5cbcParameter,iv) }, { 0 } }; typedef struct sec_rc2cbcParameterStr { SECItem rc2ParameterVersion; SECItem iv; } sec_rc2cbcParameter; static const SEC_ASN1Template sec_rc2cbc_parameter_template[] = { { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(sec_rc2cbcParameter) }, { SEC_ASN1_INTEGER, offsetof(sec_rc2cbcParameter,rc2ParameterVersion) }, { SEC_ASN1_OCTET_STRING, offsetof(sec_rc2cbcParameter,iv) }, { 0 } }; static const SEC_ASN1Template sec_rc2ecb_parameter_template[] = { { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(sec_rc2cbcParameter) }, { SEC_ASN1_INTEGER, offsetof(sec_rc2cbcParameter,rc2ParameterVersion) }, { 0 } }; /* S/MIME picked id values to represent differnt keysizes */ /* I do have a formula, but it ain't pretty, and it only works because you * can always match three points to a parabola:) */ static unsigned char rc2_map(SECItem *version) { long x; x = DER_GetInteger(version); switch (x) { case 58: return 128; case 120: return 64; case 160: return 40; } return 128; } static unsigned long rc2_unmap(unsigned long x) { switch (x) { case 128: return 58; case 64: return 120; case 40: return 160; } return 58; } /* Generate a mechaism param from a type, and iv. */ SECItem * PK11_ParamFromAlgid(SECAlgorithmID *algid) { CK_RC2_CBC_PARAMS * rc2_cbc_params = NULL; CK_RC2_PARAMS * rc2_ecb_params = NULL; CK_RC5_CBC_PARAMS * rc5_cbc_params = NULL; CK_RC5_PARAMS * rc5_ecb_params = NULL; PRArenaPool * arena = NULL; SECItem * mech = NULL; SECOidTag algtag; SECStatus rv; CK_MECHANISM_TYPE type; /* initialize these to prevent UMRs in the ASN1 decoder. */ SECItem iv = {siBuffer, NULL, 0}; sec_rc2cbcParameter rc2 = { {siBuffer, NULL, 0}, {siBuffer, NULL, 0} }; sec_rc5cbcParameter rc5 = { {siBuffer, NULL, 0}, {siBuffer, NULL, 0}, {siBuffer, NULL, 0}, {siBuffer, NULL, 0} }; algtag = SECOID_GetAlgorithmTag(algid); type = PK11_AlgtagToMechanism(algtag); mech = PORT_New(SECItem); if (mech == NULL) { return NULL; } mech->type = siBuffer; mech->data = NULL; mech->len = 0; arena = PORT_NewArena(1024); if (!arena) { goto loser; } /* handle the complicated cases */ switch (type) { case CKM_RC2_ECB: rv = SEC_ASN1DecodeItem(arena, &rc2 ,sec_rc2ecb_parameter_template, &(algid->parameters)); if (rv != SECSuccess) { goto loser; } rc2_ecb_params = PORT_New(CK_RC2_PARAMS); if (rc2_ecb_params == NULL) { goto loser; } *rc2_ecb_params = rc2_map(&rc2.rc2ParameterVersion); mech->data = (unsigned char *) rc2_ecb_params; mech->len = sizeof *rc2_ecb_params; break; case CKM_RC2_CBC: case CKM_RC2_CBC_PAD: rv = SEC_ASN1DecodeItem(arena, &rc2 ,sec_rc2cbc_parameter_template, &(algid->parameters)); if (rv != SECSuccess) { goto loser; } rc2_cbc_params = PORT_New(CK_RC2_CBC_PARAMS); if (rc2_cbc_params == NULL) { goto loser; } mech->data = (unsigned char *) rc2_cbc_params; mech->len = sizeof *rc2_cbc_params; rc2_cbc_params->ulEffectiveBits = rc2_map(&rc2.rc2ParameterVersion); if (rc2.iv.len != sizeof rc2_cbc_params->iv) { PORT_SetError(SEC_ERROR_INPUT_LEN); goto loser; } PORT_Memcpy(rc2_cbc_params->iv, rc2.iv.data, rc2.iv.len); break; case CKM_RC5_ECB: rv = SEC_ASN1DecodeItem(arena, &rc5 ,sec_rc5ecb_parameter_template, &(algid->parameters)); if (rv != SECSuccess) { goto loser; } rc5_ecb_params = PORT_New(CK_RC5_PARAMS); if (rc5_ecb_params == NULL) { goto loser; } rc5_ecb_params->ulRounds = DER_GetInteger(&rc5.rounds); rc5_ecb_params->ulWordsize = DER_GetInteger(&rc5.blockSizeInBits)/8; mech->data = (unsigned char *) rc5_ecb_params; mech->len = sizeof *rc5_ecb_params; break; case CKM_RC5_CBC: case CKM_RC5_CBC_PAD: rv = SEC_ASN1DecodeItem(arena, &rc5 ,sec_rc5cbc_parameter_template, &(algid->parameters)); if (rv != SECSuccess) { goto loser; } rc5_cbc_params = (CK_RC5_CBC_PARAMS *) PORT_Alloc(sizeof(CK_RC5_CBC_PARAMS) + rc5.iv.len); if (rc5_cbc_params == NULL) { goto loser; } mech->data = (unsigned char *) rc5_cbc_params; mech->len = sizeof *rc5_cbc_params; rc5_cbc_params->ulRounds = DER_GetInteger(&rc5.rounds); rc5_cbc_params->ulWordsize = DER_GetInteger(&rc5.blockSizeInBits)/8; rc5_cbc_params->pIv = ((CK_BYTE_PTR)rc5_cbc_params) + sizeof(CK_RC5_CBC_PARAMS); rc5_cbc_params->ulIvLen = rc5.iv.len; PORT_Memcpy(rc5_cbc_params->pIv, rc5.iv.data, rc5.iv.len); break; case CKM_PBE_MD2_DES_CBC: case CKM_PBE_MD5_DES_CBC: case CKM_NETSCAPE_PBE_SHA1_DES_CBC: case CKM_NETSCAPE_PBE_SHA1_TRIPLE_DES_CBC: case CKM_NETSCAPE_PBE_SHA1_FAULTY_3DES_CBC: case CKM_NETSCAPE_PBE_SHA1_40_BIT_RC2_CBC: case CKM_NETSCAPE_PBE_SHA1_128_BIT_RC2_CBC: case CKM_NETSCAPE_PBE_SHA1_40_BIT_RC4: case CKM_NETSCAPE_PBE_SHA1_128_BIT_RC4: case CKM_PBE_SHA1_DES2_EDE_CBC: case CKM_PBE_SHA1_DES3_EDE_CBC: case CKM_PBE_SHA1_RC2_40_CBC: case CKM_PBE_SHA1_RC2_128_CBC: case CKM_PBE_SHA1_RC4_40: case CKM_PBE_SHA1_RC4_128: rv = pbe_PK11AlgidToParam(algid,mech); if (rv != SECSuccess) { goto loser; } break; case CKM_RC4: case CKM_AES_ECB: case CKM_DES_ECB: case CKM_DES3_ECB: case CKM_IDEA_ECB: case CKM_CDMF_ECB: case CKM_CAST_ECB: case CKM_CAST3_ECB: case CKM_CAST5_ECB: break; default: if (pk11_lookup(type)->iv == 0) { break; } /* FALL THROUGH */ case CKM_AES_CBC: case CKM_DES_CBC: case CKM_DES3_CBC: case CKM_IDEA_CBC: case CKM_CDMF_CBC: case CKM_CAST_CBC: case CKM_CAST3_CBC: case CKM_CAST5_CBC: case CKM_AES_CBC_PAD: case CKM_DES_CBC_PAD: case CKM_DES3_CBC_PAD: case CKM_IDEA_CBC_PAD: case CKM_CDMF_CBC_PAD: case CKM_CAST_CBC_PAD: case CKM_CAST3_CBC_PAD: case CKM_CAST5_CBC_PAD: case CKM_SKIPJACK_CBC64: case CKM_SKIPJACK_ECB64: case CKM_SKIPJACK_OFB64: case CKM_SKIPJACK_CFB64: case CKM_SKIPJACK_CFB32: case CKM_SKIPJACK_CFB16: case CKM_SKIPJACK_CFB8: case CKM_BATON_ECB128: case CKM_BATON_ECB96: case CKM_BATON_CBC128: case CKM_BATON_COUNTER: case CKM_BATON_SHUFFLE: case CKM_JUNIPER_ECB128: case CKM_JUNIPER_CBC128: case CKM_JUNIPER_COUNTER: case CKM_JUNIPER_SHUFFLE: /* simple cases are simply octet string encoded IVs */ rv = SEC_ASN1DecodeItem(arena, &iv, SEC_OctetStringTemplate, &(algid->parameters)); if (rv != SECSuccess || iv.data == NULL) { goto loser; } /* XXX Should be some IV length sanity check here. */ mech->data = (unsigned char*)PORT_Alloc(iv.len); if (mech->data == NULL) { goto loser; } PORT_Memcpy(mech->data, iv.data, iv.len); mech->len = iv.len; break; } PORT_FreeArena(arena, PR_FALSE); return mech; loser: if (arena) PORT_FreeArena(arena, PR_FALSE); SECITEM_FreeItem(mech,PR_TRUE); return NULL; } /* * Generate an IV for the given mechanism */ static SECStatus pk11_GenIV(CK_MECHANISM_TYPE type, SECItem *iv) { int iv_size = PK11_GetIVLength(type); SECStatus rv; iv->len = iv_size; if (iv_size == 0) { iv->data = NULL; return SECSuccess; } iv->data = (unsigned char *) PORT_Alloc(iv_size); if (iv->data == NULL) { iv->len = 0; return SECFailure; } rv = PK11_GenerateRandom(iv->data,iv->len); if (rv != SECSuccess) { PORT_Free(iv->data); iv->data = NULL; iv->len = 0; return SECFailure; } return SECSuccess; } /* * create a new paramter block from the passed in MECHANISM and the * key. Use Netscape's S/MIME Rules for the New param block. */ SECItem * PK11_GenerateNewParam(CK_MECHANISM_TYPE type, PK11SymKey *key) { CK_RC2_CBC_PARAMS *rc2_params; CK_RC2_PARAMS *rc2_ecb_params; SECItem *mech; SECItem iv; SECStatus rv; mech = (SECItem *) PORT_Alloc(sizeof(SECItem)); if (mech == NULL) return NULL; rv = SECSuccess; mech->type = siBuffer; switch (type) { case CKM_RC4: case CKM_AES_ECB: case CKM_DES_ECB: case CKM_DES3_ECB: case CKM_IDEA_ECB: case CKM_CDMF_ECB: case CKM_CAST_ECB: case CKM_CAST3_ECB: case CKM_CAST5_ECB: mech->data = NULL; mech->len = 0; break; case CKM_RC2_ECB: rc2_ecb_params = (CK_RC2_PARAMS *)PORT_Alloc(sizeof(CK_RC2_PARAMS)); if (rc2_ecb_params == NULL) { rv = SECFailure; break; } /* NOTE PK11_GetKeyLength can return -1 if the key isn't and RC2, RC5, * or RC4 key. Of course that wouldn't happen here doing RC2:).*/ *rc2_ecb_params = PK11_GetKeyLength(key)*8; mech->data = (unsigned char *) rc2_ecb_params; mech->len = sizeof(CK_RC2_PARAMS); break; case CKM_RC2_CBC: case CKM_RC2_CBC_PAD: rv = pk11_GenIV(type,&iv); if (rv != SECSuccess) { break; } rc2_params = (CK_RC2_CBC_PARAMS *)PORT_Alloc(sizeof(CK_RC2_CBC_PARAMS)); if (rc2_params == NULL) { PORT_Free(iv.data); rv = SECFailure; break; } /* NOTE PK11_GetKeyLength can return -1 if the key isn't and RC2, RC5, * or RC4 key. Of course that wouldn't happen here doing RC2:).*/ rc2_params->ulEffectiveBits = PK11_GetKeyLength(key)*8; if (iv.data) PORT_Memcpy(rc2_params->iv,iv.data,sizeof(rc2_params->iv)); mech->data = (unsigned char *) rc2_params; mech->len = sizeof(CK_RC2_CBC_PARAMS); PORT_Free(iv.data); break; case CKM_RC5_ECB: PORT_Free(mech); return PK11_ParamFromIV(type,NULL); case CKM_RC5_CBC: case CKM_RC5_CBC_PAD: rv = pk11_GenIV(type,&iv); if (rv != SECSuccess) { break; } PORT_Free(mech); return PK11_ParamFromIV(type,&iv); default: if (pk11_lookup(type)->iv == 0) { mech->data = NULL; mech->len = 0; break; } case CKM_AES_CBC: case CKM_DES_CBC: case CKM_DES3_CBC: case CKM_IDEA_CBC: case CKM_CDMF_CBC: case CKM_CAST_CBC: case CKM_CAST3_CBC: case CKM_CAST5_CBC: case CKM_DES_CBC_PAD: case CKM_DES3_CBC_PAD: case CKM_IDEA_CBC_PAD: case CKM_CDMF_CBC_PAD: case CKM_CAST_CBC_PAD: case CKM_CAST3_CBC_PAD: case CKM_CAST5_CBC_PAD: case CKM_SKIPJACK_CBC64: case CKM_SKIPJACK_ECB64: case CKM_SKIPJACK_OFB64: case CKM_SKIPJACK_CFB64: case CKM_SKIPJACK_CFB32: case CKM_SKIPJACK_CFB16: case CKM_SKIPJACK_CFB8: case CKM_BATON_ECB128: case CKM_BATON_ECB96: case CKM_BATON_CBC128: case CKM_BATON_COUNTER: case CKM_BATON_SHUFFLE: case CKM_JUNIPER_ECB128: case CKM_JUNIPER_CBC128: case CKM_JUNIPER_COUNTER: case CKM_JUNIPER_SHUFFLE: rv = pk11_GenIV(type,&iv); if (rv != SECSuccess) { break; } mech->data = (unsigned char*)PORT_Alloc(iv.len); if (mech->data == NULL) { PORT_Free(iv.data); rv = SECFailure; break; } PORT_Memcpy(mech->data,iv.data,iv.len); mech->len = iv.len; PORT_Free(iv.data); break; } if (rv != SECSuccess) { SECITEM_FreeItem(mech,PR_TRUE); return NULL; } return mech; } #define RC5_V10 0x10 /* turn a PKCS #11 parameter into a DER Encoded Algorithm ID */ SECStatus PK11_ParamToAlgid(SECOidTag algTag, SECItem *param, PRArenaPool *arena, SECAlgorithmID *algid) { CK_RC2_CBC_PARAMS *rc2_params; sec_rc2cbcParameter rc2; CK_RC5_CBC_PARAMS *rc5_params; sec_rc5cbcParameter rc5; CK_MECHANISM_TYPE type = PK11_AlgtagToMechanism(algTag); SECItem *newParams = NULL; SECStatus rv = SECFailure; unsigned long rc2version; rv = SECSuccess; switch (type) { case CKM_RC4: case CKM_AES_ECB: case CKM_DES_ECB: case CKM_DES3_ECB: case CKM_IDEA_ECB: case CKM_CDMF_ECB: case CKM_CAST_ECB: case CKM_CAST3_ECB: case CKM_CAST5_ECB: newParams = NULL; rv = SECSuccess; break; case CKM_RC2_ECB: break; case CKM_RC2_CBC: case CKM_RC2_CBC_PAD: rc2_params = (CK_RC2_CBC_PARAMS *)param->data; rc2version = rc2_unmap(rc2_params->ulEffectiveBits); if (SEC_ASN1EncodeUnsignedInteger (NULL, &(rc2.rc2ParameterVersion), rc2version) == NULL) break; rc2.iv.data = rc2_params->iv; rc2.iv.len = sizeof(rc2_params->iv); newParams = SEC_ASN1EncodeItem (NULL, NULL, &rc2, sec_rc2cbc_parameter_template); PORT_Free(rc2.rc2ParameterVersion.data); if (newParams == NULL) break; rv = SECSuccess; break; case CKM_RC5_ECB: /* well not really... */ break; case CKM_RC5_CBC: case CKM_RC5_CBC_PAD: rc5_params = (CK_RC5_CBC_PARAMS *)param->data; if (SEC_ASN1EncodeUnsignedInteger (NULL, &rc5.version, RC5_V10) == NULL) break; if (SEC_ASN1EncodeUnsignedInteger (NULL, &rc5.blockSizeInBits, rc5_params->ulWordsize*8) == NULL) { PORT_Free(rc5.version.data); break; } if (SEC_ASN1EncodeUnsignedInteger (NULL, &rc5.rounds, rc5_params->ulWordsize*8) == NULL) { PORT_Free(rc5.blockSizeInBits.data); PORT_Free(rc5.version.data); break; } rc5.iv.data = rc5_params->pIv; rc5.iv.len = rc5_params->ulIvLen; newParams = SEC_ASN1EncodeItem (NULL, NULL, &rc5, sec_rc5cbc_parameter_template); PORT_Free(rc5.version.data); PORT_Free(rc5.blockSizeInBits.data); PORT_Free(rc5.rounds.data); if (newParams == NULL) break; rv = SECSuccess; break; case CKM_PBE_MD2_DES_CBC: case CKM_PBE_MD5_DES_CBC: case CKM_NETSCAPE_PBE_SHA1_DES_CBC: case CKM_NETSCAPE_PBE_SHA1_TRIPLE_DES_CBC: case CKM_NETSCAPE_PBE_SHA1_FAULTY_3DES_CBC: case CKM_NETSCAPE_PBE_SHA1_40_BIT_RC2_CBC: case CKM_NETSCAPE_PBE_SHA1_128_BIT_RC2_CBC: case CKM_NETSCAPE_PBE_SHA1_40_BIT_RC4: case CKM_NETSCAPE_PBE_SHA1_128_BIT_RC4: case CKM_PBE_SHA1_DES3_EDE_CBC: case CKM_PBE_SHA1_DES2_EDE_CBC: case CKM_PBE_SHA1_RC2_40_CBC: case CKM_PBE_SHA1_RC2_128_CBC: case CKM_PBE_SHA1_RC4_40: case CKM_PBE_SHA1_RC4_128: return PBE_PK11ParamToAlgid(algTag, param, arena, algid); default: if (pk11_lookup(type)->iv == 0) { rv = SECSuccess; newParams = NULL; break; } case CKM_AES_CBC: case CKM_DES_CBC: case CKM_DES3_CBC: case CKM_IDEA_CBC: case CKM_CDMF_CBC: case CKM_CAST_CBC: case CKM_CAST3_CBC: case CKM_CAST5_CBC: case CKM_DES_CBC_PAD: case CKM_DES3_CBC_PAD: case CKM_IDEA_CBC_PAD: case CKM_CDMF_CBC_PAD: case CKM_CAST_CBC_PAD: case CKM_CAST3_CBC_PAD: case CKM_CAST5_CBC_PAD: case CKM_SKIPJACK_CBC64: case CKM_SKIPJACK_ECB64: case CKM_SKIPJACK_OFB64: case CKM_SKIPJACK_CFB64: case CKM_SKIPJACK_CFB32: case CKM_SKIPJACK_CFB16: case CKM_SKIPJACK_CFB8: case CKM_BATON_ECB128: case CKM_BATON_ECB96: case CKM_BATON_CBC128: case CKM_BATON_COUNTER: case CKM_BATON_SHUFFLE: case CKM_JUNIPER_ECB128: case CKM_JUNIPER_CBC128: case CKM_JUNIPER_COUNTER: case CKM_JUNIPER_SHUFFLE: newParams = SEC_ASN1EncodeItem(NULL,NULL,param, SEC_OctetStringTemplate); rv = SECSuccess; break; } if (rv != SECSuccess) { if (newParams) SECITEM_FreeItem(newParams,PR_TRUE); return rv; } rv = SECOID_SetAlgorithmID(arena, algid, algTag, newParams); SECITEM_FreeItem(newParams,PR_TRUE); return rv; } /* turn an OID algorithm tag into a PKCS #11 mechanism. This allows us to * map OID's directly into the PKCS #11 mechanism we want to call. We find * this mapping in our standard OID table */ CK_MECHANISM_TYPE PK11_AlgtagToMechanism(SECOidTag algTag) { SECOidData *oid = SECOID_FindOIDByTag(algTag); if (oid) return (CK_MECHANISM_TYPE) oid->mechanism; return CKM_INVALID_MECHANISM; } /* turn a mechanism into an oid. */ SECOidTag PK11_MechanismToAlgtag(CK_MECHANISM_TYPE type) { SECOidData *oid = SECOID_FindOIDByMechanism((unsigned long)type); if (oid) return oid->offset; return SEC_OID_UNKNOWN; } /* Determine appropriate blocking mechanism, used when wrapping private keys * which require PKCS padding. If the mechanism does not map to a padding * mechanism, we simply return the mechanism. */ CK_MECHANISM_TYPE PK11_GetPadMechanism(CK_MECHANISM_TYPE type) { switch(type) { case CKM_AES_CBC: return CKM_AES_CBC_PAD; case CKM_DES_CBC: return CKM_DES_CBC_PAD; case CKM_DES3_CBC: return CKM_DES3_CBC_PAD; case CKM_RC2_CBC: return CKM_RC2_CBC_PAD; case CKM_CDMF_CBC: return CKM_CDMF_CBC_PAD; case CKM_CAST_CBC: return CKM_CAST_CBC_PAD; case CKM_CAST3_CBC: return CKM_CAST3_CBC_PAD; case CKM_CAST5_CBC: return CKM_CAST5_CBC_PAD; case CKM_RC5_CBC: return CKM_RC5_CBC_PAD; case CKM_IDEA_CBC: return CKM_IDEA_CBC_PAD; default: break; } return type; } static PRBool pk11_isAllZero(unsigned char *data,int len) { while (len--) { if (*data++) { return PR_FALSE; } } return PR_TRUE; } CK_RV PK11_MapPBEMechanismToCryptoMechanism(CK_MECHANISM_PTR pPBEMechanism, CK_MECHANISM_PTR pCryptoMechanism, SECItem *pbe_pwd, PRBool faulty3DES) { int iv_len = 0; CK_PBE_PARAMS_PTR pPBEparams; CK_RC2_CBC_PARAMS_PTR rc2_params; CK_ULONG rc2_key_len; if((pPBEMechanism == CK_NULL_PTR) || (pCryptoMechanism == CK_NULL_PTR)) { return CKR_HOST_MEMORY; } pPBEparams = (CK_PBE_PARAMS_PTR)pPBEMechanism->pParameter; iv_len = PK11_GetIVLength(pPBEMechanism->mechanism); if (iv_len) { if (pk11_isAllZero(pPBEparams->pInitVector,iv_len)) { SECItem param; PK11SymKey *symKey; PK11SlotInfo *intSlot = PK11_GetInternalSlot(); if (intSlot == NULL) { return CKR_DEVICE_ERROR; } param.data = pPBEMechanism->pParameter; param.len = pPBEMechanism->ulParameterLen; symKey = PK11_RawPBEKeyGen(intSlot, pPBEMechanism->mechanism, ¶m, pbe_pwd, faulty3DES, NULL); PK11_FreeSlot(intSlot); if (symKey== NULL) { return CKR_DEVICE_ERROR; /* sigh */ } PK11_FreeSymKey(symKey); } } switch(pPBEMechanism->mechanism) { case CKM_PBE_MD2_DES_CBC: case CKM_PBE_MD5_DES_CBC: case CKM_NETSCAPE_PBE_SHA1_DES_CBC: pCryptoMechanism->mechanism = CKM_DES_CBC; goto have_crypto_mechanism; case CKM_NETSCAPE_PBE_SHA1_TRIPLE_DES_CBC: case CKM_NETSCAPE_PBE_SHA1_FAULTY_3DES_CBC: case CKM_PBE_SHA1_DES3_EDE_CBC: case CKM_PBE_SHA1_DES2_EDE_CBC: pCryptoMechanism->mechanism = CKM_DES3_CBC; have_crypto_mechanism: pCryptoMechanism->pParameter = PORT_Alloc(iv_len); pCryptoMechanism->ulParameterLen = (CK_ULONG)iv_len; if(pCryptoMechanism->pParameter == NULL) { return CKR_HOST_MEMORY; } PORT_Memcpy((unsigned char *)(pCryptoMechanism->pParameter), (unsigned char *)(pPBEparams->pInitVector), iv_len); break; case CKM_NETSCAPE_PBE_SHA1_40_BIT_RC4: case CKM_NETSCAPE_PBE_SHA1_128_BIT_RC4: case CKM_PBE_SHA1_RC4_40: case CKM_PBE_SHA1_RC4_128: pCryptoMechanism->mechanism = CKM_RC4; pCryptoMechanism->ulParameterLen = 0; pCryptoMechanism->pParameter = CK_NULL_PTR; break; case CKM_NETSCAPE_PBE_SHA1_40_BIT_RC2_CBC: case CKM_PBE_SHA1_RC2_40_CBC: rc2_key_len = 40; goto have_key_len; case CKM_NETSCAPE_PBE_SHA1_128_BIT_RC2_CBC: rc2_key_len = 128; have_key_len: pCryptoMechanism->mechanism = CKM_RC2_CBC; pCryptoMechanism->ulParameterLen = (CK_ULONG) sizeof(CK_RC2_CBC_PARAMS); pCryptoMechanism->pParameter = (CK_RC2_CBC_PARAMS_PTR) PORT_ZAlloc(sizeof(CK_RC2_CBC_PARAMS)); if(pCryptoMechanism->pParameter == NULL) { return CKR_HOST_MEMORY; } rc2_params = (CK_RC2_CBC_PARAMS_PTR)pCryptoMechanism->pParameter; PORT_Memcpy((unsigned char *)rc2_params->iv, (unsigned char *)pPBEparams->pInitVector, iv_len); rc2_params->ulEffectiveBits = rc2_key_len; break; default: return CKR_MECHANISM_INVALID; } return CKR_OK; } /* Make a Key type to an appropriate signing/verification mechanism */ CK_MECHANISM_TYPE PK11_MapSignKeyType(KeyType keyType) { switch (keyType) { case rsaKey: return CKM_RSA_PKCS; case fortezzaKey: case dsaKey: return CKM_DSA; case ecKey: return CKM_ECDSA; case dhKey: default: break; } return CKM_INVALID_MECHANISM; } CK_MECHANISM_TYPE pk11_mapWrapKeyType(KeyType keyType) { switch (keyType) { case rsaKey: return CKM_RSA_PKCS; /* Add fortezza?? */ default: break; } return CKM_INVALID_MECHANISM; } SECOidTag PK11_FortezzaMapSig(SECOidTag algTag) { switch (algTag) { case SEC_OID_MISSI_KEA_DSS: case SEC_OID_MISSI_DSS: case SEC_OID_MISSI_DSS_OLD: case SEC_OID_MISSI_KEA_DSS_OLD: case SEC_OID_BOGUS_DSA_SIGNATURE_WITH_SHA1_DIGEST: return SEC_OID_ANSIX9_DSA_SIGNATURE; default: break; } return algTag; }