Source code

Revision control

Copy as Markdown

Other Tools

/* 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/. */
/*
* 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;
CK_MECHANISM_TYPE padType;
int blockSize;
int iv;
} pk11MechanismData;
static pk11MechanismData pk11_default = { CKM_GENERIC_SECRET_KEY_GEN, CKK_GENERIC_SECRET,
CKM_FAKE_RANDOM, 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_CAMELLIA_ECB,
CKM_SEED_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,
CK_MECHANISM_TYPE padType,
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].padType = padType;
newt[entry].iv = ivLen;
newt[entry].blockSize = blockSize;
pk11_MechanismTable = newt;
pk11_MechTableSize = tableSize;
pk11_MechEntrySize = size;
if (old)
PORT_Free(old);
}
/*
* Get the mechanism needed for the given key type
*/
CK_MECHANISM_TYPE
PK11_GetKeyMechanism(CK_KEY_TYPE type)
{
switch (type) {
case CKK_SEED:
return CKM_SEED_CBC;
case CKK_CAMELLIA:
return CKM_CAMELLIA_CBC;
case CKK_NSS_CHACHA20:
return CKM_NSS_CHACHA20_POLY1305;
case CKK_CHACHA20:
return CKM_CHACHA20_POLY1305;
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_EC_EDWARDS:
return CKM_EDDSA;
case CKK_HKDF:
return CKM_HKDF_DERIVE;
case CKK_GENERIC_SECRET:
default:
return CKM_SHA_1_HMAC;
}
}
/*
* Get the key type needed for the given mechanism
*/
CK_KEY_TYPE
PK11_GetKeyType(CK_MECHANISM_TYPE type, unsigned long len)
{
switch (type) {
case CKM_SEED_ECB:
case CKM_SEED_CBC:
case CKM_SEED_MAC:
case CKM_SEED_MAC_GENERAL:
case CKM_SEED_CBC_PAD:
case CKM_SEED_KEY_GEN:
return CKK_SEED;
case CKM_CAMELLIA_ECB:
case CKM_CAMELLIA_CBC:
case CKM_CAMELLIA_MAC:
case CKM_CAMELLIA_MAC_GENERAL:
case CKM_CAMELLIA_CBC_PAD:
case CKM_CAMELLIA_KEY_GEN:
return CKK_CAMELLIA;
case CKM_NSS_CHACHA20_POLY1305:
case CKM_NSS_CHACHA20_KEY_GEN:
case CKM_NSS_CHACHA20_CTR:
return CKK_NSS_CHACHA20;
case CKM_CHACHA20_POLY1305:
case CKM_CHACHA20_KEY_GEN:
case CKM_CHACHA20:
return CKK_CHACHA20;
case CKM_AES_ECB:
case CKM_AES_CBC:
case CKM_AES_CCM:
case CKM_AES_CTR:
case CKM_AES_CTS:
case CKM_AES_GCM:
case CKM_AES_MAC:
case CKM_AES_MAC_GENERAL:
case CKM_AES_CMAC:
case CKM_AES_CMAC_GENERAL:
case CKM_AES_CBC_PAD:
case CKM_AES_KEY_GEN:
case CKM_NSS_AES_KEY_WRAP:
case CKM_NSS_AES_KEY_WRAP_PAD:
case CKM_AES_KEY_WRAP:
case CKM_AES_KEY_WRAP_KWP:
case CKM_AES_XCBC_MAC:
case CKM_AES_XCBC_MAC_96:
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_SHA224_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_EC_EDWARDS_KEY_PAIR_GEN:
case CKM_EDDSA:
return CKK_EC_EDWARDS;
case CKM_HKDF_KEY_GEN:
case CKM_HKDF_DERIVE:
case CKM_HKDF_DATA:
return CKK_HKDF;
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_NSS_TLS_MASTER_KEY_DERIVE_SHA256:
case CKM_TLS_MASTER_KEY_DERIVE_DH:
case CKM_NSS_TLS_MASTER_KEY_DERIVE_DH_SHA256:
case CKM_TLS_KEY_AND_MAC_DERIVE:
case CKM_NSS_TLS_KEY_AND_MAC_DERIVE_SHA256:
case CKM_NSS_TLS_EXTENDED_MASTER_KEY_DERIVE:
case CKM_NSS_TLS_EXTENDED_MASTER_KEY_DERIVE_DH:
case CKM_SHA_1_HMAC:
case CKM_SHA_1_HMAC_GENERAL:
case CKM_SHA224_HMAC:
case CKM_SHA224_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_NSS_TLS_PRF_GENERAL_SHA256:
return CKK_GENERIC_SECRET;
case CKM_NSS_KYBER_KEY_PAIR_GEN:
return CKK_NSS_KYBER;
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_SEED_ECB:
case CKM_SEED_CBC:
case CKM_SEED_MAC:
case CKM_SEED_MAC_GENERAL:
case CKM_SEED_CBC_PAD:
case CKM_SEED_KEY_GEN:
return CKM_SEED_KEY_GEN;
case CKM_CAMELLIA_ECB:
case CKM_CAMELLIA_CBC:
case CKM_CAMELLIA_MAC:
case CKM_CAMELLIA_MAC_GENERAL:
case CKM_CAMELLIA_CBC_PAD:
case CKM_CAMELLIA_KEY_GEN:
return CKM_CAMELLIA_KEY_GEN;
case CKM_NSS_CHACHA20_POLY1305:
case CKM_NSS_CHACHA20_CTR:
return CKM_NSS_CHACHA20_KEY_GEN;
case CKM_CHACHA20_POLY1305:
case CKM_CHACHA20:
return CKM_CHACHA20_KEY_GEN;
case CKM_AES_ECB:
case CKM_AES_CBC:
case CKM_AES_CCM:
case CKM_AES_CTR:
case CKM_AES_CTS:
case CKM_AES_GCM:
case CKM_AES_MAC:
case CKM_AES_MAC_GENERAL:
case CKM_AES_CMAC:
case CKM_AES_CMAC_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_SHA224_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_EDDSA:
return CKM_EC_EDWARDS_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:
case CKM_NSS_TLS_KEY_AND_MAC_DERIVE_SHA256:
case CKM_NSS_TLS_EXTENDED_MASTER_KEY_DERIVE:
case CKM_NSS_TLS_EXTENDED_MASTER_KEY_DERIVE_DH:
return CKM_SSL3_PRE_MASTER_KEY_GEN;
case CKM_SHA_1_HMAC:
case CKM_SHA_1_HMAC_GENERAL:
case CKM_SHA224_HMAC:
case CKM_SHA224_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_NSS_TLS_PRF_GENERAL_SHA256:
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_NSS_PBE_SHA1_HMAC_KEY_GEN:
case CKM_NSS_PBE_MD5_HMAC_KEY_GEN:
case CKM_NSS_PBE_MD2_HMAC_KEY_GEN:
case CKM_NSS_PKCS12_PBE_SHA224_HMAC_KEY_GEN:
case CKM_NSS_PKCS12_PBE_SHA256_HMAC_KEY_GEN:
case CKM_NSS_PKCS12_PBE_SHA384_HMAC_KEY_GEN:
case CKM_NSS_PKCS12_PBE_SHA512_HMAC_KEY_GEN:
case CKM_NSS_PBE_SHA1_DES_CBC:
case CKM_NSS_PBE_SHA1_40_BIT_RC2_CBC:
case CKM_NSS_PBE_SHA1_128_BIT_RC2_CBC:
case CKM_NSS_PBE_SHA1_40_BIT_RC4:
case CKM_NSS_PBE_SHA1_128_BIT_RC4:
case CKM_NSS_PBE_SHA1_TRIPLE_DES_CBC:
case CKM_NSS_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:
case CKM_PKCS5_PBKD2:
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_NSS_PBE_SHA1_DES_CBC:
case CKM_NSS_PBE_SHA1_40_BIT_RC2_CBC:
case CKM_NSS_PBE_SHA1_128_BIT_RC2_CBC:
case CKM_NSS_PBE_SHA1_TRIPLE_DES_CBC:
case CKM_NSS_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_SEED_ECB:
case CKM_SEED_CBC:
case CKM_SEED_CBC_PAD:
case CKM_CAMELLIA_ECB:
case CKM_CAMELLIA_CBC:
case CKM_CAMELLIA_CBC_PAD:
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_NSS_PBE_SHA1_40_BIT_RC4:
case CKM_NSS_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 */
case CKM_NSS_CHACHA20_POLY1305:
case CKM_NSS_CHACHA20_CTR:
case CKM_CHACHA20_POLY1305:
case CKM_CHACHA20:
return 64;
default:
return pk11_lookup(type)->blockSize;
}
}
/*
* get the iv length
*/
int
PK11_GetIVLength(CK_MECHANISM_TYPE type)
{
switch (type) {
case CKM_SEED_ECB:
case CKM_CAMELLIA_ECB:
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_NSS_PBE_SHA1_DES_CBC:
case CKM_NSS_PBE_SHA1_40_BIT_RC2_CBC:
case CKM_NSS_PBE_SHA1_128_BIT_RC2_CBC:
case CKM_NSS_PBE_SHA1_TRIPLE_DES_CBC:
case CKM_NSS_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_GCM:
case CKM_NSS_CHACHA20_POLY1305:
case CKM_CHACHA20_POLY1305:
return 12;
case CKM_SEED_CBC:
case CKM_SEED_CBC_PAD:
case CKM_CAMELLIA_CBC:
case CKM_CAMELLIA_CBC_PAD:
case CKM_AES_CBC:
case CKM_AES_CBC_PAD:
case CKM_NSS_CHACHA20_CTR:
case CKM_CHACHA20:
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_NSS_PBE_SHA1_40_BIT_RC4:
case CKM_NSS_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_ParamFromIVWithLen(CK_MECHANISM_TYPE type, SECItem *iv, int keyLen)
{
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_SEED_ECB:
case CKM_CAMELLIA_ECB:
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 = keyLen ? keyLen * 8 : 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 = keyLen ? keyLen * 8 : 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_SEED_CBC:
case CKM_CAMELLIA_CBC:
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_CAMELLIA_CBC_PAD:
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;
}
/* 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)
{
return pk11_ParamFromIVWithLen(type, iv, 0);
}
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_SEED_ECB:
case CKM_CAMELLIA_ECB:
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_SEED_CBC:
case CKM_CAMELLIA_CBC:
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_CAMELLIA_CBC_PAD:
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:
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;
PLArenaPool *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_NSS_PBE_SHA1_DES_CBC:
case CKM_NSS_PBE_SHA1_TRIPLE_DES_CBC:
case CKM_NSS_PBE_SHA1_FAULTY_3DES_CBC:
case CKM_NSS_PBE_SHA1_40_BIT_RC2_CBC:
case CKM_NSS_PBE_SHA1_128_BIT_RC2_CBC:
case CKM_NSS_PBE_SHA1_40_BIT_RC4:
case CKM_NSS_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:
case CKM_PKCS5_PBKD2:
rv = pbe_PK11AlgidToParam(algid, mech);
if (rv != SECSuccess) {
goto loser;
}
break;
case CKM_RC4:
case CKM_SEED_ECB:
case CKM_CAMELLIA_ECB:
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_SEED_CBC:
case CKM_CAMELLIA_CBC:
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_SEED_CBC_PAD:
case CKM_CAMELLIA_CBC_PAD:
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_ASN1_GET(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 parameter block from the passed in MECHANISM and the
* key. Use Netscape's S/MIME Rules for the New param block.
*/
SECItem *
pk11_GenerateNewParamWithKeyLen(CK_MECHANISM_TYPE type, int keyLen)
{
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;
mech->data = NULL;
mech->len = 0;
switch (type) {
case CKM_RC4:
case CKM_SEED_ECB:
case CKM_CAMELLIA_ECB:
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;
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 = keyLen ? keyLen * 8 : 128;
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 = keyLen ? keyLen * 8 : 128;
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) {
break;
}
case CKM_SEED_CBC:
case CKM_CAMELLIA_CBC:
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;
}
SECItem *
PK11_GenerateNewParam(CK_MECHANISM_TYPE type, PK11SymKey *key)
{
int keyLen = key ? PK11_GetKeyLength(key) : 0;
return pk11_GenerateNewParamWithKeyLen(type, keyLen);
}
#define RC5_V10 0x10
/* turn a PKCS #11 parameter into a DER Encoded Algorithm ID */
SECStatus
PK11_ParamToAlgid(SECOidTag algTag, SECItem *param,
PLArenaPool *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;
switch (type) {
case CKM_RC4:
case CKM_SEED_ECB:
case CKM_CAMELLIA_ECB:
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_NSS_PBE_SHA1_DES_CBC:
case CKM_NSS_PBE_SHA1_TRIPLE_DES_CBC:
case CKM_NSS_PBE_SHA1_FAULTY_3DES_CBC:
case CKM_NSS_PBE_SHA1_40_BIT_RC2_CBC:
case CKM_NSS_PBE_SHA1_128_BIT_RC2_CBC:
case CKM_NSS_PBE_SHA1_40_BIT_RC4:
case CKM_NSS_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_SEED_CBC:
case CKM_CAMELLIA_CBC:
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_ASN1_GET(SEC_OctetStringTemplate));
if (newParams == NULL)
break;
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_SEED_CBC:
return CKM_SEED_CBC_PAD;
case CKM_CAMELLIA_CBC:
return CKM_CAMELLIA_CBC_PAD;
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;
}
/* pkcs5 v2 cannot be supported by this interface.
* use PK11_GetPBECryptoMechanism instead.
*/
if ((pPBEMechanism->mechanism == CKM_INVALID_MECHANISM) ||
(pPBEMechanism->mechanism == CKM_PKCS5_PBKD2)) {
return CKR_MECHANISM_INVALID;
}
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, &param, pbe_pwd, faulty3DES, NULL);
PK11_FreeSlot(intSlot);
if (symKey == NULL) {
return CKR_DEVICE_ERROR; /* sigh */
}
PK11_FreeSymKey(symKey);