/* 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 implements PKCS 11 on top of our existing security modules * * For more information about PKCS 11 See PKCS 11 Token Inteface Standard. * This implementation has two slots: * slot 1 is our generic crypto support. It does not require login. * It supports Public Key ops, and all they bulk ciphers and hashes. * It can also support Private Key ops for imported Private keys. It does * not have any token storage. * slot 2 is our private key support. It requires a login before use. It * can store Private Keys and Certs as token objects. Currently only private * keys and their associated Certificates are saved on the token. * * In this implementation, session objects are only visible to the session * that created or generated them.
*/ #include"seccomon.h" #include"secitem.h" #include"pkcs11.h" #include"pkcs11i.h" #include"softoken.h" #include"lowkeyi.h" #include"blapi.h" #include"secder.h" #include"secport.h" #include"secrng.h" #include"prtypes.h" #include"nspr.h" #include"softkver.h" #include"secoid.h" #include"sftkdb.h" #include"utilpars.h" #include"ec.h" #include"secasn1.h" #include"secerr.h" #include"lgglue.h" #include"kem.h"
/* The next three strings must be exactly 32 characters long */ staticchar *manufacturerID = "Mozilla Foundation "; staticchar manufacturerID_space[33]; staticchar *libraryDescription = "NSS Internal Crypto Services "; staticchar libraryDescription_space[33];
/* * In FIPS mode, we disallow login attempts for 1 second after a login * failure so that there are at most 60 login attempts per minute.
*/ static PRIntervalTime loginWaitTime;
#define __PASTE(x, y) x##y
/* * we renamed all our internal functions, get the correct * definitions for them...
*/ #undef CK_PKCS11_FUNCTION_INFO #undef CK_NEED_ARG_LIST
/* need a special version of get info for version 2 which returns the version
* 2.4 version number */
CK_RV NSC_GetInfoV2(CK_INFO_PTR pInfo);
CK_RV NSC_GetMechanismInfoV2(CK_SLOT_ID slotID, CK_MECHANISM_TYPE type,
CK_MECHANISM_INFO_PTR pInfo);
/* * the following table includes a complete list of mechanism defined by * PKCS #11 version 2.01. Those Mechanisms not supported by this PKCS #11 * module are ifdef'ed out.
*/ #define CKF_EN_DE CKF_ENCRYPT | CKF_DECRYPT #define CKF_WR_UN CKF_WRAP | CKF_UNWRAP #define CKF_SN_VR CKF_SIGN | CKF_VERIFY #define CKF_SN_RE CKF_SIGN_RECOVER | CKF_VERIFY_RECOVER #define CKF_EN_DE_MSG CKF_ENCRYPT | CKF_DECRYPT | CKF_MESSAGE_ENCRYPT | CKF_MESSAGE_DECRYPT
/* * PKCS #11 Mechanism List. * * The first argument is the PKCS #11 Mechanism we support. * The second argument is Mechanism info structure. It includes: * The minimum key size, * in bits for RSA, DSA, DH, EC*, KEA, RC2 and RC4 * algs. * in bytes for RC5, AES, Camellia, and CAST* * ignored for DES*, IDEA and FORTEZZA based * The maximum key size, * in bits for RSA, DSA, DH, EC*, KEA, RC2 and RC4 * algs. * in bytes for RC5, AES, Camellia, and CAST* * ignored for DES*, IDEA and FORTEZZA based * Flags * What operations are supported by this mechanism. * The third argument is a bool which tells if this mechanism is * supported in the database token. *
*/
staticchar *
sftk_setStringName(constchar *inString, char *buffer, int buffer_length, PRBool nullTerminate)
{ int full_length, string_length;
full_length = nullTerminate ? buffer_length - 1 : buffer_length;
string_length = PORT_Strlen(inString); /* * shorten the string, respecting utf8 encoding * to do so, we work backward from the end * bytes looking from the end are either: * - ascii [0x00,0x7f] * - the [2-n]th byte of a multibyte sequence * [0x3F,0xBF], i.e, most significant 2 bits are '10' * - the first byte of a multibyte sequence [0xC0,0xFD], * i.e, most significant 2 bits are '11' * * When the string is too long, we lop off any trailing '10' bytes, * if any. When these are all eliminated we lop off * one additional byte. Thus if we lopped any '10' * we'll be lopping a '11' byte (the first byte of the multibyte sequence), * otherwise we're lopping off an ascii character. * * To test for '10' bytes, we first AND it with * 11000000 (0xc0) so that we get 10000000 (0x80) if and only if * the byte starts with 10. We test for equality.
*/ while (string_length > full_length) { /* need to shorten */ while (string_length > 0 &&
((inString[string_length - 1] & (char)0xc0) == (char)0x80)) { /* lop off '10' byte */
string_length--;
} /* * test string_length in case bad data is received * and string consisted of all '10' bytes, * avoiding any infinite loop
*/ if (string_length) { /* remove either '11' byte or an asci byte */
string_length--;
}
}
PORT_Memset(buffer, ' ', full_length); if (nullTerminate) {
buffer[full_length] = 0;
}
PORT_Memcpy(buffer, inString, string_length); return buffer;
} /* * Configuration utils
*/ static CK_RV
sftk_configure(constchar *man, constchar *libdes)
{
/* make sure the internationalization was done correctly... */ if (man) {
manufacturerID = sftk_setStringName(man, manufacturerID_space, sizeof(manufacturerID_space), PR_TRUE);
} if (libdes) {
libraryDescription = sftk_setStringName(libdes,
libraryDescription_space, sizeof(libraryDescription_space),
PR_TRUE);
}
/* Make sure a given attribute exists. If it doesn't, initialize it to * value and len
*/
CK_RV
sftk_defaultAttribute(SFTKObject *object, CK_ATTRIBUTE_TYPE type, constvoid *value, unsignedint len)
{ if (!sftk_hasAttribute(object, type)) { return sftk_AddAttributeType(object, type, value, len);
} return CKR_OK;
}
/* * check the consistancy and initialize a Data Object
*/ static CK_RV
sftk_handleDataObject(SFTKSession *session, SFTKObject *object)
{
CK_RV crv;
/* first reject private and token data objects */ if (sftk_isTrue(object, CKA_PRIVATE) || sftk_isTrue(object, CKA_TOKEN)) { return CKR_ATTRIBUTE_VALUE_INVALID;
}
/* now just verify the required date fields */
crv = sftk_defaultAttribute(object, CKA_APPLICATION, NULL, 0); if (crv != CKR_OK) return crv;
crv = sftk_defaultAttribute(object, CKA_VALUE, NULL, 0); if (crv != CKR_OK) return crv;
return CKR_OK;
}
/* * check the consistancy and initialize a Certificate Object
*/ static CK_RV
sftk_handleCertObject(SFTKSession *session, SFTKObject *object)
{
CK_CERTIFICATE_TYPE type;
SFTKAttribute *attribute;
CK_RV crv;
/* certificates must have a type */ if (!sftk_hasAttribute(object, CKA_CERTIFICATE_TYPE)) { return CKR_TEMPLATE_INCOMPLETE;
}
/* we can't store any certs private */ if (sftk_isTrue(object, CKA_PRIVATE)) { return CKR_ATTRIBUTE_VALUE_INVALID;
}
/* We only support X.509 Certs for now */
attribute = sftk_FindAttribute(object, CKA_CERTIFICATE_TYPE); if (attribute == NULL) return CKR_TEMPLATE_INCOMPLETE;
type = *(CK_CERTIFICATE_TYPE *)attribute->attrib.pValue;
sftk_FreeAttribute(attribute);
if (type != CKC_X_509) { return CKR_ATTRIBUTE_VALUE_INVALID;
}
/* X.509 Certificate */
/* make sure we have a cert */ if (!sftk_hasAttribute(object, CKA_VALUE)) { return CKR_TEMPLATE_INCOMPLETE;
}
/* in PKCS #11, Subject is a required field */ if (!sftk_hasAttribute(object, CKA_SUBJECT)) { return CKR_TEMPLATE_INCOMPLETE;
}
/* in PKCS #11, Issuer is a required field */ if (!sftk_hasAttribute(object, CKA_ISSUER)) { return CKR_TEMPLATE_INCOMPLETE;
}
/* in PKCS #11, Serial is a required field */ if (!sftk_hasAttribute(object, CKA_SERIAL_NUMBER)) { return CKR_TEMPLATE_INCOMPLETE;
}
/* add it to the object */
object->objectInfo = NULL;
object->infoFree = (SFTKFree)NULL;
/* now just verify the required date fields */
crv = sftk_defaultAttribute(object, CKA_ID, NULL, 0); if (crv != CKR_OK) { return crv;
}
/* * check the consistancy and initialize a Trust Object
*/ static CK_RV
sftk_handleTrustObject(SFTKSession *session, SFTKObject *object)
{ /* we can't store any certs private */ if (sftk_isTrue(object, CKA_PRIVATE)) { return CKR_ATTRIBUTE_VALUE_INVALID;
}
/* certificates must have a type */ if (!sftk_hasAttribute(object, CKA_ISSUER)) { return CKR_TEMPLATE_INCOMPLETE;
} if (!sftk_hasAttribute(object, CKA_SERIAL_NUMBER)) { return CKR_TEMPLATE_INCOMPLETE;
} if (!sftk_hasAttribute(object, CKA_CERT_SHA1_HASH)) { return CKR_TEMPLATE_INCOMPLETE;
} if (!sftk_hasAttribute(object, CKA_CERT_MD5_HASH)) { return CKR_TEMPLATE_INCOMPLETE;
}
/* * check the consistancy and initialize a Trust Object
*/ static CK_RV
sftk_handleSMimeObject(SFTKSession *session, SFTKObject *object)
{
/* we can't store any certs private */ if (sftk_isTrue(object, CKA_PRIVATE)) { return CKR_ATTRIBUTE_VALUE_INVALID;
}
/* certificates must have a type */ if (!sftk_hasAttribute(object, CKA_SUBJECT)) { return CKR_TEMPLATE_INCOMPLETE;
} if (!sftk_hasAttribute(object, CKA_NSS_EMAIL)) { return CKR_TEMPLATE_INCOMPLETE;
}
/* * check the consistancy and initialize a Trust Object
*/ static CK_RV
sftk_handleCrlObject(SFTKSession *session, SFTKObject *object)
{
/* we can't store any certs private */ if (sftk_isTrue(object, CKA_PRIVATE)) { return CKR_ATTRIBUTE_VALUE_INVALID;
}
/* certificates must have a type */ if (!sftk_hasAttribute(object, CKA_SUBJECT)) { return CKR_TEMPLATE_INCOMPLETE;
} if (!sftk_hasAttribute(object, CKA_VALUE)) { return CKR_TEMPLATE_INCOMPLETE;
}
switch (key_type) { case CKK_RSA: if (!sftk_hasAttribute(object, CKA_MODULUS)) {
missing_rsa_mod_component++;
} if (!sftk_hasAttribute(object, CKA_PUBLIC_EXPONENT)) {
missing_rsa_exp_component++;
} if (!sftk_hasAttribute(object, CKA_PRIVATE_EXPONENT)) {
missing_rsa_exp_component++;
} if (!sftk_hasAttribute(object, CKA_PRIME_1)) {
missing_rsa_mod_component++;
} if (!sftk_hasAttribute(object, CKA_PRIME_2)) {
missing_rsa_mod_component++;
} if (!sftk_hasAttribute(object, CKA_EXPONENT_1)) {
missing_rsa_crt_component++;
} if (!sftk_hasAttribute(object, CKA_EXPONENT_2)) {
missing_rsa_crt_component++;
} if (!sftk_hasAttribute(object, CKA_COEFFICIENT)) {
missing_rsa_crt_component++;
} if (missing_rsa_mod_component || missing_rsa_exp_component ||
missing_rsa_crt_component) { /* we are missing a component, see if we have enough to rebuild
* the rest */ int have_exp = 2 - missing_rsa_exp_component; int have_component = 5 -
(missing_rsa_exp_component + missing_rsa_mod_component);
if ((have_exp == 0) || (have_component < 3)) { /* nope, not enough to reconstruct the private key */ return CKR_TEMPLATE_INCOMPLETE;
}
fillPrivateKey = PR_TRUE;
} /*verify the parameters for consistency*/
rv = sftk_verifyRSAPrivateKey(object, fillPrivateKey); if (rv != SECSuccess) { return CKR_TEMPLATE_INCOMPLETE;
}
/* make sure Netscape DB attribute is set correctly */
crv = sftk_Attribute2SSecItem(NULL, &mod, object, CKA_MODULUS); if (crv != CKR_OK) return crv;
crv = sftk_forceAttribute(object, CKA_NSS_DB,
sftk_item_expand(&mod)); if (mod.data)
SECITEM_ZfreeItem(&mod, PR_FALSE); if (crv != CKR_OK) return crv;
sign = CK_TRUE;
derive = CK_FALSE; break; case CKK_DSA: if (!sftk_hasAttribute(object, CKA_SUBPRIME)) { return CKR_TEMPLATE_INCOMPLETE;
}
sign = CK_TRUE;
derive = CK_FALSE; /* fall through */ case CKK_DH: if (!sftk_hasAttribute(object, CKA_PRIME)) { return CKR_TEMPLATE_INCOMPLETE;
} if (!sftk_hasAttribute(object, CKA_BASE)) { return CKR_TEMPLATE_INCOMPLETE;
} if (!sftk_hasAttribute(object, CKA_VALUE)) { return CKR_TEMPLATE_INCOMPLETE;
} /* allow subprime to be set after the fact */
crv = sftk_defaultAttribute(object, CKA_SUBPRIME, NULL, 0); if (crv != CKR_OK) { return crv;
}
encrypt = CK_FALSE;
recover = CK_FALSE;
wrap = CK_FALSE; break; case CKK_EC: case CKK_EC_EDWARDS: case CKK_EC_MONTGOMERY: if (!sftk_hasAttribute(object, CKA_EC_PARAMS)) { return CKR_TEMPLATE_INCOMPLETE;
} if (!sftk_hasAttribute(object, CKA_VALUE)) { return CKR_TEMPLATE_INCOMPLETE;
} /* for ECDSA and EDDSA. Change if the structure of any of them is modified. */
derive = (key_type == CKK_EC_EDWARDS) ? CK_FALSE : CK_TRUE; /* CK_TRUE for ECDH */
sign = (key_type == CKK_EC_MONTGOMERY) ? CK_FALSE : CK_TRUE; /* for ECDSA and EDDSA */
encrypt = CK_FALSE;
recover = CK_FALSE;
wrap = CK_FALSE; break; case CKK_NSS_JPAKE_ROUND1: if (!sftk_hasAttribute(object, CKA_PRIME) ||
!sftk_hasAttribute(object, CKA_SUBPRIME) ||
!sftk_hasAttribute(object, CKA_BASE)) { return CKR_TEMPLATE_INCOMPLETE;
} /* fall through */ case CKK_NSS_JPAKE_ROUND2: /* CKA_NSS_JPAKE_SIGNERID and CKA_NSS_JPAKE_PEERID are checked in
the J-PAKE code. */
encrypt = sign = recover = wrap = CK_FALSE;
derive = CK_TRUE;
createObjectInfo = PR_FALSE; break; case CKK_NSS_KYBER: case CKK_NSS_ML_KEM: if (!sftk_hasAttribute(object, CKA_KEY_TYPE)) { return CKR_TEMPLATE_INCOMPLETE;
} if (!sftk_hasAttribute(object, CKA_VALUE)) { return CKR_TEMPLATE_INCOMPLETE;
}
encrypt = sign = recover = wrap = CK_FALSE; break; default: return CKR_ATTRIBUTE_VALUE_INVALID;
}
crv = sftk_defaultAttribute(object, CKA_SUBJECT, NULL, 0); if (crv != CKR_OK) return crv;
crv = sftk_defaultAttribute(object, CKA_SENSITIVE, &cktrue, sizeof(CK_BBOOL)); if (crv != CKR_OK) return crv;
crv = sftk_defaultAttribute(object, CKA_EXTRACTABLE, &cktrue, sizeof(CK_BBOOL)); if (crv != CKR_OK) return crv;
crv = sftk_defaultAttribute(object, CKA_DECRYPT, &encrypt, sizeof(CK_BBOOL)); if (crv != CKR_OK) return crv;
crv = sftk_defaultAttribute(object, CKA_SIGN, &sign, sizeof(CK_BBOOL)); if (crv != CKR_OK) return crv;
crv = sftk_defaultAttribute(object, CKA_SIGN_RECOVER, &recover, sizeof(CK_BBOOL)); if (crv != CKR_OK) return crv;
crv = sftk_defaultAttribute(object, CKA_UNWRAP, &wrap, sizeof(CK_BBOOL)); if (crv != CKR_OK) return crv;
crv = sftk_defaultAttribute(object, CKA_DERIVE, &derive, sizeof(CK_BBOOL)); if (crv != CKR_OK) return crv; /* the next two bits get modified only in the key gen and token cases */
crv = sftk_forceAttribute(object, CKA_ALWAYS_SENSITIVE,
&ckfalse, sizeof(CK_BBOOL)); if (crv != CKR_OK) return crv;
crv = sftk_forceAttribute(object, CKA_NEVER_EXTRACTABLE,
&ckfalse, sizeof(CK_BBOOL)); if (crv != CKR_OK) return crv;
/* should we check the non-token RSA private keys? */
if (!sftk_hasAttribute(object, CKA_VALUE)) { return CKR_TEMPLATE_INCOMPLETE;
} /* the next two bits get modified only in the key gen and token cases */
crv = sftk_forceAttribute(object, CKA_ALWAYS_SENSITIVE,
&ckfalse, sizeof(CK_BBOOL)); if (crv != CKR_OK) return crv;
crv = sftk_forceAttribute(object, CKA_NEVER_EXTRACTABLE,
&ckfalse, sizeof(CK_BBOOL)); if (crv != CKR_OK) return crv;
/* some types of keys have a value length */
crv = CKR_OK; switch (key_type) { /* force CKA_VALUE_LEN to be set */ case CKK_GENERIC_SECRET: case CKK_RC2: case CKK_RC4: #if NSS_SOFTOKEN_DOES_RC5 case CKK_RC5: #endif #ifdef NSS_SOFTOKEN_DOES_CAST case CKK_CAST: case CKK_CAST3: case CKK_CAST5: #endif #if NSS_SOFTOKEN_DOES_IDEA case CKK_IDEA: #endif
attribute = sftk_FindAttribute(object, CKA_VALUE); /* shouldn't happen */ if (attribute == NULL) return CKR_TEMPLATE_INCOMPLETE;
crv = sftk_forceAttribute(object, CKA_VALUE_LEN,
&attribute->attrib.ulValueLen, sizeof(CK_ULONG));
sftk_FreeAttribute(attribute); break; /* force the value to have the correct parity */ case CKK_DES: case CKK_DES2: case CKK_DES3: case CKK_CDMF:
attribute = sftk_FindAttribute(object, CKA_VALUE); /* shouldn't happen */ if (attribute == NULL) return CKR_TEMPLATE_INCOMPLETE;
requiredLen = sftk_MapKeySize(key_type); if (attribute->attrib.ulValueLen != requiredLen) {
sftk_FreeAttribute(attribute); return CKR_KEY_SIZE_RANGE;
}
sftk_FormatDESKey((unsignedchar *)attribute->attrib.pValue,
attribute->attrib.ulValueLen);
sftk_FreeAttribute(attribute); break; case CKK_AES:
attribute = sftk_FindAttribute(object, CKA_VALUE); /* shouldn't happen */ if (attribute == NULL) return CKR_TEMPLATE_INCOMPLETE; if (attribute->attrib.ulValueLen != 16 &&
attribute->attrib.ulValueLen != 24 &&
attribute->attrib.ulValueLen != 32) {
sftk_FreeAttribute(attribute); return CKR_KEY_SIZE_RANGE;
}
crv = sftk_forceAttribute(object, CKA_VALUE_LEN,
&attribute->attrib.ulValueLen, sizeof(CK_ULONG));
sftk_FreeAttribute(attribute); break; default: break;
}
return crv;
}
/* * check the consistancy and initialize a Secret Key Object
*/ static CK_RV
sftk_handleSecretKeyObject(SFTKSession *session, SFTKObject *object,
CK_KEY_TYPE key_type, PRBool isFIPS)
{
CK_RV crv;
/* First validate and set defaults */
crv = validateSecretKey(session, object, key_type, isFIPS); if (crv != CKR_OK) goto loser;
/* If the object is a TOKEN object, store in the database */ if (sftk_isTrue(object, CKA_TOKEN)) {
SFTKSlot *slot = session->slot;
SFTKDBHandle *keyHandle = sftk_getKeyDB(slot);
if (keyHandle == NULL) { return CKR_TOKEN_WRITE_PROTECTED;
}
/* * check the consistancy and initialize a Key Object
*/ static CK_RV
sftk_handleKeyObject(SFTKSession *session, SFTKObject *object)
{
SFTKAttribute *attribute;
CK_KEY_TYPE key_type;
CK_BBOOL ckfalse = CK_FALSE;
CK_RV crv;
/* verify the required fields */ if (!sftk_hasAttribute(object, CKA_KEY_TYPE)) { return CKR_TEMPLATE_INCOMPLETE;
}
/* now verify the common fields */
crv = sftk_defaultAttribute(object, CKA_ID, NULL, 0); if (crv != CKR_OK) return crv;
crv = sftk_defaultAttribute(object, CKA_START_DATE, NULL, 0); if (crv != CKR_OK) return crv;
crv = sftk_defaultAttribute(object, CKA_END_DATE, NULL, 0); if (crv != CKR_OK) return crv; /* CKA_DERIVE is common to all keys, but it's default value is
* key dependent */
crv = sftk_defaultAttribute(object, CKA_LOCAL, &ckfalse, sizeof(CK_BBOOL)); if (crv != CKR_OK) return crv;
/* get the key type */
attribute = sftk_FindAttribute(object, CKA_KEY_TYPE); if (!attribute) { return CKR_ATTRIBUTE_VALUE_INVALID;
}
key_type = *(CK_KEY_TYPE *)attribute->attrib.pValue;
sftk_FreeAttribute(attribute);
switch (object->objclass) { case CKO_PUBLIC_KEY: return sftk_handlePublicKeyObject(session, object, key_type); case CKO_PRIVATE_KEY: return sftk_handlePrivateKeyObject(session, object, key_type); case CKO_SECRET_KEY: /* make sure the required fields exist */ return sftk_handleSecretKeyObject(session, object, key_type,
(PRBool)(sftk_isFIPS(session->slot->slotID))); default: break;
} return CKR_ATTRIBUTE_VALUE_INVALID;
}
/* * check the consistancy and Verify a DSA Parameter Object
*/ static CK_RV
sftk_handleDSAParameterObject(SFTKSession *session, SFTKObject *object)
{
SFTKAttribute *primeAttr = NULL;
SFTKAttribute *subPrimeAttr = NULL;
SFTKAttribute *baseAttr = NULL;
SFTKAttribute *seedAttr = NULL;
SFTKAttribute *hAttr = NULL;
SFTKAttribute *attribute;
CK_RV crv = CKR_TEMPLATE_INCOMPLETE;
PQGParams params;
PQGVerify vfy, *verify = NULL;
SECStatus result, rv; /* This bool keeps track of whether or not we need verify parameters. * If a P, Q and G or supplied, we dont' need verify parameters, as we * have PQ and G. * - If G is not supplied, the presumption is that we want to * verify P and Q only. * - If counter is supplied, it is presumed we want to verify PQ because * the counter is only used in verification. * - If H is supplied, is is presumed we want to verify G because H is * only used to verify G. * - Any verification step must have the SEED (counter or H could be * missing depending on exactly what we want to verify). If SEED is supplied, * the code just goes ahead and runs verify (other errors are parameter * errors are detected by the PQG_VerifyParams function). If SEED is not * supplied, but we determined that we are trying to verify (because needVfy * is set, go ahead and return CKR_TEMPLATE_INCOMPLETE.
*/
PRBool needVfy = PR_FALSE;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.