summaryrefslogtreecommitdiffstats
path: root/security/nss/lib/softoken
diff options
context:
space:
mode:
Diffstat (limited to 'security/nss/lib/softoken')
-rw-r--r--security/nss/lib/softoken/fipstest.c5
-rw-r--r--security/nss/lib/softoken/fipstokn.c28
-rw-r--r--security/nss/lib/softoken/legacydb/lgattr.c2
-rw-r--r--security/nss/lib/softoken/lgglue.c13
-rw-r--r--security/nss/lib/softoken/lowkey.c27
-rw-r--r--security/nss/lib/softoken/manifest.mn1
-rw-r--r--security/nss/lib/softoken/pkcs11.c147
-rw-r--r--security/nss/lib/softoken/pkcs11c.c731
-rw-r--r--security/nss/lib/softoken/pkcs11i.h132
-rw-r--r--security/nss/lib/softoken/pkcs11u.c43
-rw-r--r--security/nss/lib/softoken/sdb.c106
-rw-r--r--security/nss/lib/softoken/sftkdb.c10
-rw-r--r--security/nss/lib/softoken/sftkdb.h2
-rw-r--r--security/nss/lib/softoken/sftkdbti.h1
-rw-r--r--security/nss/lib/softoken/sftkhmac.c289
-rw-r--r--security/nss/lib/softoken/sftkike.c1294
-rw-r--r--security/nss/lib/softoken/sftkpwd.c307
-rw-r--r--security/nss/lib/softoken/softkver.h6
-rw-r--r--security/nss/lib/softoken/softoken.gyp3
-rw-r--r--security/nss/lib/softoken/tlsprf.c2
20 files changed, 2716 insertions, 433 deletions
diff --git a/security/nss/lib/softoken/fipstest.c b/security/nss/lib/softoken/fipstest.c
index 0cca74d6e..e765cde4c 100644
--- a/security/nss/lib/softoken/fipstest.c
+++ b/security/nss/lib/softoken/fipstest.c
@@ -12,6 +12,7 @@
#include "lowkeyi.h"
#include "secoid.h"
#include "secerr.h"
+#include "pkcs11i.h"
/*
* different platforms have different ways of calling and initial entry point
@@ -626,6 +627,10 @@ sftk_startup_tests(void)
* the token */
return;
}
+ rv = sftk_fips_IKE_PowerUpSelfTests();
+ if (rv != SECSuccess) {
+ return;
+ }
sftk_self_tests_success = PR_TRUE;
}
diff --git a/security/nss/lib/softoken/fipstokn.c b/security/nss/lib/softoken/fipstokn.c
index ca7d7998a..166f19de2 100644
--- a/security/nss/lib/softoken/fipstokn.c
+++ b/security/nss/lib/softoken/fipstokn.c
@@ -645,17 +645,37 @@ FC_SetPIN(CK_SESSION_HANDLE hSession, CK_CHAR_PTR pOldPin,
CHECK_FORK();
- if ((rv = sftk_fipsCheck()) == CKR_OK &&
- (rv = sftk_newPinCheck(pNewPin, usNewLen)) == CKR_OK) {
+ rv = sftk_fipsCheck();
+ if (rv != CKR_OK) {
+ goto loser;
+ }
+
+ if (isLevel2 || usNewLen > 0) {
+ rv = sftk_newPinCheck(pNewPin, usNewLen);
+ if (rv != CKR_OK) {
+ goto loser;
+ }
rv = NSC_SetPIN(hSession, pOldPin, usOldLen, pNewPin, usNewLen);
- if ((rv == CKR_OK) &&
- (sftk_SlotIDFromSessionHandle(hSession) == FIPS_SLOT_ID)) {
+ if (rv != CKR_OK) {
+ goto loser;
+ }
+ if (sftk_SlotIDFromSessionHandle(hSession) == FIPS_SLOT_ID) {
/* if we set the password in level1 we now go
* to level2. NOTE: we don't allow the user to
* go from level2 to level1 */
isLevel2 = PR_TRUE;
}
+ } else {
+ /* here both old and new passwords are empty, but we need to
+ * call NSC_SetPIN to force rekey the database entries */
+ PORT_Assert(usNewLen == 0);
+ rv = NSC_SetPIN(hSession, pOldPin, usOldLen, pNewPin, usNewLen);
+ if (rv != CKR_OK) {
+ goto loser;
+ }
}
+
+loser:
if (sftk_audit_enabled) {
char msg[128];
NSSAuditSeverity severity = (rv == CKR_OK) ? NSS_AUDIT_INFO : NSS_AUDIT_ERROR;
diff --git a/security/nss/lib/softoken/legacydb/lgattr.c b/security/nss/lib/softoken/legacydb/lgattr.c
index 3d77bd056..c1865a38e 100644
--- a/security/nss/lib/softoken/legacydb/lgattr.c
+++ b/security/nss/lib/softoken/legacydb/lgattr.c
@@ -1069,7 +1069,7 @@ lg_FindTrustAttribute(LGObjectCache *obj, CK_ATTRIBUTE_TYPE type,
NSSLOWCERTCertificate *cert;
unsigned char hash[SHA1_LENGTH];
unsigned int trustFlags;
- CK_RV crv;
+ CK_RV crv = CKR_CANCEL;
switch (type) {
case CKA_PRIVATE:
diff --git a/security/nss/lib/softoken/lgglue.c b/security/nss/lib/softoken/lgglue.c
index 67f17943b..8cfb4ec56 100644
--- a/security/nss/lib/softoken/lgglue.c
+++ b/security/nss/lib/softoken/lgglue.c
@@ -194,12 +194,15 @@ sftkdb_encrypt_stub(PLArenaPool *arena, SDB *sdb, SECItem *plainText,
/* PORT_SetError */
return SECFailure;
}
- if (handle->newKey) {
- key = handle->newKey;
- iterationCount = handle->newDefaultIterationCount;
+ key = handle->newKey ? handle->newKey : &handle->passwordKey;
+ if (sftk_isLegacyIterationCountAllowed()) {
+ if (handle->newKey) {
+ iterationCount = handle->newDefaultIterationCount;
+ } else {
+ iterationCount = handle->defaultIterationCount;
+ }
} else {
- key = &handle->passwordKey;
- iterationCount = handle->defaultIterationCount;
+ iterationCount = 1;
}
rv = sftkdb_EncryptAttribute(arena, key, iterationCount,
diff --git a/security/nss/lib/softoken/lowkey.c b/security/nss/lib/softoken/lowkey.c
index a28a3a55e..e9bbff1d9 100644
--- a/security/nss/lib/softoken/lowkey.c
+++ b/security/nss/lib/softoken/lowkey.c
@@ -261,6 +261,7 @@ NSSLOWKEYPublicKey *
nsslowkey_ConvertToPublicKey(NSSLOWKEYPrivateKey *privk)
{
NSSLOWKEYPublicKey *pubk;
+ SECItem publicValue;
PLArenaPool *arena;
arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
@@ -301,6 +302,19 @@ nsslowkey_ConvertToPublicKey(NSSLOWKEYPrivateKey *privk)
pubk->arena = arena;
pubk->keyType = privk->keyType;
+ /* if the public key value doesn't exist, calculate it */
+ if (privk->u.dsa.publicValue.len == 0) {
+ rv = DH_Derive(&privk->u.dsa.params.base, &privk->u.dsa.params.prime,
+ &privk->u.dsa.privateValue, &publicValue, 0);
+ if (rv != SECSuccess) {
+ break;
+ }
+ rv = SECITEM_CopyItem(privk->arena, &privk->u.dsa.publicValue, &publicValue);
+ SECITEM_FreeItem(&publicValue, PR_FALSE);
+ if (rv != SECSuccess) {
+ break;
+ }
+ }
rv = SECITEM_CopyItem(arena, &pubk->u.dsa.publicValue,
&privk->u.dsa.publicValue);
if (rv != SECSuccess)
@@ -327,6 +341,19 @@ nsslowkey_ConvertToPublicKey(NSSLOWKEYPrivateKey *privk)
pubk->arena = arena;
pubk->keyType = privk->keyType;
+ /* if the public key value doesn't exist, calculate it */
+ if (privk->u.dh.publicValue.len == 0) {
+ rv = DH_Derive(&privk->u.dh.base, &privk->u.dh.prime,
+ &privk->u.dh.privateValue, &publicValue, 0);
+ if (rv != SECSuccess) {
+ break;
+ }
+ rv = SECITEM_CopyItem(privk->arena, &privk->u.dh.publicValue, &publicValue);
+ SECITEM_FreeItem(&publicValue, PR_FALSE);
+ if (rv != SECSuccess) {
+ break;
+ }
+ }
rv = SECITEM_CopyItem(arena, &pubk->u.dh.publicValue,
&privk->u.dh.publicValue);
if (rv != SECSuccess)
diff --git a/security/nss/lib/softoken/manifest.mn b/security/nss/lib/softoken/manifest.mn
index 256d443ea..f25b97730 100644
--- a/security/nss/lib/softoken/manifest.mn
+++ b/security/nss/lib/softoken/manifest.mn
@@ -46,6 +46,7 @@ CSRCS = \
sdb.c \
sftkdb.c \
sftkhmac.c \
+ sftkike.c \
sftkpars.c \
sftkpwd.c \
softkver.c \
diff --git a/security/nss/lib/softoken/pkcs11.c b/security/nss/lib/softoken/pkcs11.c
index 7f0adf82f..7f3a01746 100644
--- a/security/nss/lib/softoken/pkcs11.c
+++ b/security/nss/lib/softoken/pkcs11.c
@@ -324,10 +324,14 @@ static const struct mechanismList mechanisms[] = {
{ CKM_AES_CBC, { 16, 32, CKF_EN_DE_WR_UN }, PR_TRUE },
{ CKM_AES_MAC, { 16, 32, CKF_SN_VR }, PR_TRUE },
{ CKM_AES_MAC_GENERAL, { 16, 32, CKF_SN_VR }, PR_TRUE },
+ { CKM_AES_CMAC, { 16, 32, CKF_SN_VR }, PR_TRUE },
+ { CKM_AES_CMAC_GENERAL, { 16, 32, CKF_SN_VR }, PR_TRUE },
{ CKM_AES_CBC_PAD, { 16, 32, CKF_EN_DE_WR_UN }, PR_TRUE },
{ CKM_AES_CTS, { 16, 32, CKF_EN_DE }, PR_TRUE },
{ CKM_AES_CTR, { 16, 32, CKF_EN_DE }, PR_TRUE },
{ CKM_AES_GCM, { 16, 32, CKF_EN_DE }, PR_TRUE },
+ { CKM_AES_XCBC_MAC_96, { 16, 16, CKF_SN_VR }, PR_TRUE },
+ { CKM_AES_XCBC_MAC, { 16, 16, CKF_SN_VR }, PR_TRUE },
/* ------------------------- Camellia Operations --------------------- */
{ CKM_CAMELLIA_KEY_GEN, { 16, 32, CKF_GENERATE }, PR_TRUE },
{ CKM_CAMELLIA_ECB, { 16, 32, CKF_EN_DE_WR_UN }, PR_TRUE },
@@ -346,6 +350,7 @@ static const struct mechanismList mechanisms[] = {
/* ------------------------- ChaCha20 Operations ---------------------- */
{ CKM_NSS_CHACHA20_KEY_GEN, { 32, 32, CKF_GENERATE }, PR_TRUE },
{ CKM_NSS_CHACHA20_POLY1305, { 32, 32, CKF_EN_DE }, PR_TRUE },
+ { CKM_NSS_CHACHA20_CTR, { 32, 32, CKF_EN_DE }, PR_TRUE },
#endif /* NSS_DISABLE_CHACHAPOLY */
/* ------------------------- Hashing Operations ----------------------- */
{ CKM_MD2, { 0, 0, CKF_DIGEST }, PR_FALSE },
@@ -509,7 +514,11 @@ static const struct mechanismList mechanisms[] = {
{ CKM_NSS_JPAKE_FINAL_SHA512, { 0, 0, CKF_DERIVE }, PR_TRUE },
/* -------------------- Constant Time TLS MACs ----------------------- */
{ CKM_NSS_HMAC_CONSTANT_TIME, { 0, 0, CKF_DIGEST }, PR_TRUE },
- { CKM_NSS_SSL3_MAC_CONSTANT_TIME, { 0, 0, CKF_DIGEST }, PR_TRUE }
+ { CKM_NSS_SSL3_MAC_CONSTANT_TIME, { 0, 0, CKF_DIGEST }, PR_TRUE },
+ /* --------------------IPSEC ----------------------- */
+ { CKM_NSS_IKE_PRF_PLUS_DERIVE, { 8, 255 * 64, CKF_DERIVE }, PR_TRUE },
+ { CKM_NSS_IKE_PRF_DERIVE, { 8, 64, CKF_DERIVE }, PR_TRUE },
+ { CKM_NSS_IKE1_PRF_DERIVE, { 8, 64, CKF_DERIVE }, PR_TRUE }
};
static const CK_ULONG mechanismCount = sizeof(mechanisms) / sizeof(mechanisms[0]);
@@ -1815,8 +1824,6 @@ sftk_GetPubKey(SFTKObject *object, CK_KEY_TYPE key_type,
break; /* key was not DER encoded, no need to unwrap */
}
- PORT_Assert(pubKey->u.ec.ecParams.name != ECCurve25519);
-
/* handle the encoded case */
if ((pubKey->u.ec.publicValue.data[0] == SEC_ASN1_OCTET_STRING) &&
pubKey->u.ec.publicValue.len > keyLen) {
@@ -1827,7 +1834,13 @@ sftk_GetPubKey(SFTKObject *object, CK_KEY_TYPE key_type,
SEC_ASN1_GET(SEC_OctetStringTemplate),
&pubKey->u.ec.publicValue);
/* nope, didn't decode correctly */
- if ((rv != SECSuccess) || (publicValue.data[0] != EC_POINT_FORM_UNCOMPRESSED) || (publicValue.len != keyLen)) {
+ if ((rv != SECSuccess) || (publicValue.len != keyLen)) {
+ crv = CKR_ATTRIBUTE_VALUE_INVALID;
+ break;
+ }
+ /* we don't handle compressed points except in the case of ECCurve25519 */
+ if ((pubKey->u.ec.ecParams.fieldID.type != ec_field_plain) &&
+ (publicValue.data[0] != EC_POINT_FORM_UNCOMPRESSED)) {
crv = CKR_ATTRIBUTE_VALUE_INVALID;
break;
}
@@ -2195,6 +2208,124 @@ sftk_GetPrivKey(SFTKObject *object, CK_KEY_TYPE key_type, CK_RV *crvp)
return priv;
}
+/* populate a public key object from a lowpublic keys structure */
+CK_RV
+sftk_PutPubKey(SFTKObject *publicKey, SFTKObject *privateKey, CK_KEY_TYPE keyType, NSSLOWKEYPublicKey *pubKey)
+{
+ CK_OBJECT_CLASS classType = CKO_PUBLIC_KEY;
+ CK_BBOOL cktrue = CK_TRUE;
+ CK_RV crv = CKR_OK;
+ sftk_DeleteAttributeType(publicKey, CKA_CLASS);
+ sftk_DeleteAttributeType(publicKey, CKA_KEY_TYPE);
+ sftk_DeleteAttributeType(publicKey, CKA_VALUE);
+
+ switch (keyType) {
+ case CKK_RSA:
+ sftk_DeleteAttributeType(publicKey, CKA_MODULUS);
+ sftk_DeleteAttributeType(publicKey, CKA_PUBLIC_EXPONENT);
+ /* format the keys */
+ /* fill in the RSA dependent paramenters in the public key */
+ crv = sftk_AddAttributeType(publicKey, CKA_MODULUS,
+ sftk_item_expand(&pubKey->u.rsa.modulus));
+ if (crv != CKR_OK) {
+ break;
+ }
+ crv = sftk_AddAttributeType(publicKey, CKA_PUBLIC_EXPONENT,
+ sftk_item_expand(&pubKey->u.rsa.publicExponent));
+ break;
+ case CKK_DSA:
+ sftk_DeleteAttributeType(publicKey, CKA_PRIME);
+ sftk_DeleteAttributeType(publicKey, CKA_SUBPRIME);
+ sftk_DeleteAttributeType(publicKey, CKA_BASE);
+ crv = sftk_AddAttributeType(publicKey, CKA_PRIME,
+ sftk_item_expand(&pubKey->u.dsa.params.prime));
+ if (crv != CKR_OK) {
+ break;
+ }
+ crv = sftk_AddAttributeType(publicKey, CKA_SUBPRIME,
+ sftk_item_expand(&pubKey->u.dsa.params.subPrime));
+ if (crv != CKR_OK) {
+ break;
+ }
+ crv = sftk_AddAttributeType(publicKey, CKA_BASE,
+ sftk_item_expand(&pubKey->u.dsa.params.base));
+ if (crv != CKR_OK) {
+ break;
+ }
+ crv = sftk_AddAttributeType(publicKey, CKA_VALUE,
+ sftk_item_expand(&pubKey->u.dsa.publicValue));
+ break;
+ case CKK_DH:
+ sftk_DeleteAttributeType(publicKey, CKA_PRIME);
+ sftk_DeleteAttributeType(publicKey, CKA_BASE);
+ crv = sftk_AddAttributeType(publicKey, CKA_PRIME,
+ sftk_item_expand(&pubKey->u.dh.prime));
+ if (crv != CKR_OK) {
+ break;
+ }
+ crv = sftk_AddAttributeType(publicKey, CKA_BASE,
+ sftk_item_expand(&pubKey->u.dh.base));
+ if (crv != CKR_OK) {
+ break;
+ }
+ crv = sftk_AddAttributeType(publicKey, CKA_VALUE,
+ sftk_item_expand(&pubKey->u.dh.publicValue));
+ break;
+ case CKK_EC:
+ sftk_DeleteAttributeType(publicKey, CKA_EC_PARAMS);
+ sftk_DeleteAttributeType(publicKey, CKA_EC_POINT);
+ crv = sftk_AddAttributeType(publicKey, CKA_EC_PARAMS,
+ sftk_item_expand(&pubKey->u.ec.ecParams.DEREncoding));
+ if (crv != CKR_OK) {
+ break;
+ }
+ crv = sftk_AddAttributeType(publicKey, CKA_EC_POINT,
+ sftk_item_expand(&pubKey->u.ec.publicValue));
+ break;
+ default:
+ return CKR_KEY_TYPE_INCONSISTENT;
+ }
+ if (crv != CKR_OK) {
+ return crv;
+ }
+ crv = sftk_AddAttributeType(publicKey, CKA_CLASS, &classType,
+ sizeof(CK_OBJECT_CLASS));
+ if (crv != CKR_OK) {
+ return crv;
+ }
+ crv = sftk_AddAttributeType(publicKey, CKA_KEY_TYPE, &keyType,
+ sizeof(CK_KEY_TYPE));
+ if (crv != CKR_OK) {
+ return crv;
+ }
+ /* now handle the operator attributes */
+ if (sftk_isTrue(privateKey, CKA_DECRYPT)) {
+ crv = sftk_forceAttribute(publicKey, CKA_ENCRYPT, &cktrue, sizeof(CK_BBOOL));
+ if (crv != CKR_OK) {
+ return crv;
+ }
+ }
+ if (sftk_isTrue(privateKey, CKA_SIGN)) {
+ crv = sftk_forceAttribute(publicKey, CKA_VERIFY, &cktrue, sizeof(CK_BBOOL));
+ if (crv != CKR_OK) {
+ return crv;
+ }
+ }
+ if (sftk_isTrue(privateKey, CKA_SIGN_RECOVER)) {
+ crv = sftk_forceAttribute(publicKey, CKA_VERIFY_RECOVER, &cktrue, sizeof(CK_BBOOL));
+ if (crv != CKR_OK) {
+ return crv;
+ }
+ }
+ if (sftk_isTrue(privateKey, CKA_DERIVE)) {
+ crv = sftk_forceAttribute(publicKey, CKA_DERIVE, &cktrue, sizeof(CK_BBOOL));
+ if (crv != CKR_OK) {
+ return crv;
+ }
+ }
+ return crv;
+}
+
/*
**************************** Symetric Key utils ************************
*/
@@ -3153,7 +3284,7 @@ nsc_CommonFinalize(CK_VOID_PTR pReserved, PRBool isFIPS)
* this call doesn't force freebl to be reloaded. */
BL_SetForkState(PR_FALSE);
-#ifndef NSS_TEST_BUILD
+#ifndef NSS_STATIC_SOFTOKEN
/* unload freeBL shared library from memory. This may only decrement the
* OS refcount if it's been loaded multiple times, eg. by libssl */
BL_Unload();
@@ -3777,7 +3908,10 @@ NSC_SetPIN(CK_SESSION_HANDLE hSession, CK_CHAR_PTR pOldPin,
crv = CKR_PIN_LEN_RANGE;
goto loser;
}
- if (ulNewLen < (CK_ULONG)slot->minimumPinLen) {
+ /* check the length of new pin, unless both old and new passwords
+ * are empty */
+ if ((ulNewLen != 0 || ulOldLen != 0) &&
+ ulNewLen < (CK_ULONG)slot->minimumPinLen) {
crv = CKR_PIN_LEN_RANGE;
goto loser;
}
@@ -3935,7 +4069,6 @@ NSC_CloseSession(CK_SESSION_HANDLE hSession)
session = NULL;
}
- sftk_FreeSession(session);
return CKR_OK;
}
diff --git a/security/nss/lib/softoken/pkcs11c.c b/security/nss/lib/softoken/pkcs11c.c
index 4837961f1..6bc5cc939 100644
--- a/security/nss/lib/softoken/pkcs11c.c
+++ b/security/nss/lib/softoken/pkcs11c.c
@@ -30,6 +30,7 @@
#include "lowpbe.h" /* We do PBE below */
#include "pkcs11t.h"
#include "secoid.h"
+#include "cmac.h"
#include "alghmac.h"
#include "softoken.h"
#include "secasn1.h"
@@ -39,7 +40,7 @@
#include "prenv.h"
#define __PASTE(x, y) x##y
-
+#define BAD_PARAM_CAST(pMech, typeSize) (!pMech->pParameter || pMech->ulParameterLen < typeSize)
/*
* we renamed all our internal functions, get the correct
* definitions for them...
@@ -96,42 +97,10 @@ sftk_Space(void *data, PRBool freeit)
/*
* map all the SEC_ERROR_xxx error codes that may be returned by freebl
- * functions to CKR_xxx. return CKR_DEVICE_ERROR by default for backward
- * compatibility.
+ * functions to CKR_xxx. Most of the mapping is done in
+ * sftk_mapCryptError (now in pkcs11u.c). The next two functions adjust
+ * that mapping based for different contexts (Decrypt or Verify).
*/
-static CK_RV
-sftk_MapCryptError(int error)
-{
- switch (error) {
- case SEC_ERROR_INVALID_ARGS:
- case SEC_ERROR_BAD_DATA: /* MP_RANGE gets mapped to this */
- return CKR_ARGUMENTS_BAD;
- case SEC_ERROR_INPUT_LEN:
- return CKR_DATA_LEN_RANGE;
- case SEC_ERROR_OUTPUT_LEN:
- return CKR_BUFFER_TOO_SMALL;
- case SEC_ERROR_LIBRARY_FAILURE:
- return CKR_GENERAL_ERROR;
- case SEC_ERROR_NO_MEMORY:
- return CKR_HOST_MEMORY;
- case SEC_ERROR_BAD_SIGNATURE:
- return CKR_SIGNATURE_INVALID;
- case SEC_ERROR_INVALID_KEY:
- return CKR_KEY_SIZE_RANGE;
- case SEC_ERROR_BAD_KEY: /* an EC public key that fails validation */
- return CKR_KEY_SIZE_RANGE; /* the closest error code */
- case SEC_ERROR_UNSUPPORTED_EC_POINT_FORM:
- return CKR_TEMPLATE_INCONSISTENT;
- case SEC_ERROR_UNSUPPORTED_KEYALG:
- return CKR_MECHANISM_INVALID;
- case SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE:
- return CKR_DOMAIN_PARAMS_INVALID;
- /* key pair generation failed after max number of attempts */
- case SEC_ERROR_NEED_RANDOM:
- return CKR_FUNCTION_FAILED;
- }
- return CKR_DEVICE_ERROR;
-}
/* used by Decrypt and UnwrapKey (indirectly) */
static CK_RV
@@ -760,6 +729,32 @@ sftk_ChaCha20Poly1305_Decrypt(const SFTKChaCha20Poly1305Info *ctx,
sizeof(ctx->nonce), ad, ctx->adLen);
}
+static SECStatus
+sftk_ChaCha20Ctr(const SFTKChaCha20CtrInfo *ctx,
+ unsigned char *output, unsigned int *outputLen,
+ unsigned int maxOutputLen,
+ const unsigned char *input, unsigned int inputLen)
+{
+ if (maxOutputLen < inputLen) {
+ PORT_SetError(SEC_ERROR_OUTPUT_LEN);
+ return SECFailure;
+ }
+ ChaCha20_Xor(output, input, inputLen, ctx->key,
+ ctx->nonce, ctx->counter);
+ *outputLen = inputLen;
+ return SECSuccess;
+}
+
+static void
+sftk_ChaCha20Ctr_DestroyContext(SFTKChaCha20CtrInfo *ctx,
+ PRBool freeit)
+{
+ memset(ctx, 0, sizeof(*ctx));
+ if (freeit) {
+ PORT_Free(ctx);
+ }
+}
+
/** NSC_CryptInit initializes an encryption/Decryption operation.
*
* Always called by NSC_EncryptInit, NSC_DecryptInit, NSC_WrapKey,NSC_UnwrapKey.
@@ -788,6 +783,10 @@ sftk_CryptInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
PRBool useNewKey = PR_FALSE;
int t;
+ if (!pMechanism) {
+ return CKR_MECHANISM_PARAM_INVALID;
+ }
+
crv = sftk_MechAllowsOperation(pMechanism->mechanism, mechUsage);
if (crv != CKR_OK)
return crv;
@@ -901,6 +900,11 @@ sftk_CryptInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
crv = CKR_KEY_HANDLE_INVALID;
break;
}
+
+ if (BAD_PARAM_CAST(pMechanism, sizeof(CK_RC2_CBC_PARAMS))) {
+ crv = CKR_MECHANISM_PARAM_INVALID;
+ break;
+ }
rc2_param = (CK_RC2_CBC_PARAMS *)pMechanism->pParameter;
effectiveKeyLength = (rc2_param->ulEffectiveBits + 7) / 8;
context->cipherInfo =
@@ -930,6 +934,11 @@ sftk_CryptInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
crv = CKR_KEY_HANDLE_INVALID;
break;
}
+
+ if (BAD_PARAM_CAST(pMechanism, sizeof(CK_RC5_CBC_PARAMS))) {
+ crv = CKR_MECHANISM_PARAM_INVALID;
+ break;
+ }
rc5_param = (CK_RC5_CBC_PARAMS *)pMechanism->pParameter;
context->blockSize = rc5_param->ulWordsize * 2;
rc5Key.data = (unsigned char *)att->attrib.pValue;
@@ -993,6 +1002,10 @@ sftk_CryptInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
crv = CKR_KEY_TYPE_INCONSISTENT;
break;
}
+ if (pMechanism->ulParameterLen < 8) {
+ crv = CKR_DOMAIN_PARAMS_INVALID;
+ break;
+ }
t = NSS_DES_CBC;
goto finish_des;
case CKM_DES3_ECB:
@@ -1010,6 +1023,10 @@ sftk_CryptInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
crv = CKR_KEY_TYPE_INCONSISTENT;
break;
}
+ if (pMechanism->ulParameterLen < 8) {
+ crv = CKR_DOMAIN_PARAMS_INVALID;
+ break;
+ }
t = NSS_DES_EDE3_CBC;
finish_des:
context->blockSize = 8;
@@ -1127,6 +1144,13 @@ sftk_CryptInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
case CKM_AES_CTS:
case CKM_AES_CTR:
case CKM_AES_GCM:
+ if ((pMechanism->mechanism == CKM_AES_GCM && BAD_PARAM_CAST(pMechanism, sizeof(CK_GCM_PARAMS))) ||
+ (pMechanism->mechanism == CKM_AES_CTR && BAD_PARAM_CAST(pMechanism, sizeof(CK_AES_CTR_PARAMS))) ||
+ ((pMechanism->mechanism == CKM_AES_CBC || pMechanism->mechanism == CKM_AES_CTS) && BAD_PARAM_CAST(pMechanism, AES_BLOCK_SIZE))) {
+ crv = CKR_MECHANISM_PARAM_INVALID;
+ break;
+ }
+
if (pMechanism->mechanism == CKM_AES_GCM) {
context->multi = PR_FALSE;
}
@@ -1180,6 +1204,48 @@ sftk_CryptInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
context->destroy = (SFTKDestroy)sftk_ChaCha20Poly1305_DestroyContext;
break;
+ case CKM_NSS_CHACHA20_CTR:
+ if (key_type != CKK_NSS_CHACHA20) {
+ crv = CKR_KEY_TYPE_INCONSISTENT;
+ break;
+ }
+ if (pMechanism->pParameter == NULL || pMechanism->ulParameterLen != 16) {
+ crv = CKR_MECHANISM_PARAM_INVALID;
+ break;
+ }
+
+ att = sftk_FindAttribute(key, CKA_VALUE);
+ if (att == NULL) {
+ crv = CKR_KEY_HANDLE_INVALID;
+ break;
+ }
+ SFTKChaCha20CtrInfo *ctx = PORT_ZNew(SFTKChaCha20CtrInfo);
+ if (!ctx) {
+ sftk_FreeAttribute(att);
+ crv = CKR_HOST_MEMORY;
+ break;
+ }
+ if (att->attrib.ulValueLen != sizeof(ctx->key)) {
+ sftk_FreeAttribute(att);
+ PORT_Free(ctx);
+ crv = CKR_KEY_HANDLE_INVALID;
+ break;
+ }
+ memcpy(ctx->key, att->attrib.pValue, att->attrib.ulValueLen);
+ sftk_FreeAttribute(att);
+
+ /* The counter is little endian. */
+ PRUint8 *param = pMechanism->pParameter;
+ int i = 0;
+ for (; i < 4; ++i) {
+ ctx->counter |= param[i] << (i * 8);
+ }
+ memcpy(ctx->nonce, param + 4, 12);
+ context->cipherInfo = ctx;
+ context->update = (SFTKCipher)sftk_ChaCha20Ctr;
+ context->destroy = (SFTKDestroy)sftk_ChaCha20Ctr_DestroyContext;
+ break;
+
case CKM_NSS_AES_KEY_WRAP_PAD:
context->doPad = PR_TRUE;
/* fall thru */
@@ -1311,8 +1377,11 @@ NSC_EncryptUpdate(CK_SESSION_HANDLE hSession,
/* do it: NOTE: this assumes buf size in is >= buf size out! */
rv = (*context->update)(context->cipherInfo, pEncryptedPart,
&outlen, maxout, pPart, ulPartLen);
+ if (rv != SECSuccess) {
+ return sftk_MapCryptError(PORT_GetError());
+ }
*pulEncryptedPartLen = (CK_ULONG)(outlen + padoutlen);
- return (rv == SECSuccess) ? CKR_OK : sftk_MapCryptError(PORT_GetError());
+ return CKR_OK;
}
/* NSC_EncryptFinal finishes a multiple-part encryption operation. */
@@ -1392,26 +1461,29 @@ NSC_Encrypt(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData,
return crv;
if (!pEncryptedData) {
- *pulEncryptedDataLen = context->rsa ? context->maxLen : ulDataLen + 2 * context->blockSize;
- goto finish;
+ outlen = context->rsa ? context->maxLen : ulDataLen + 2 * context->blockSize;
+ goto done;
}
if (context->doPad) {
if (context->multi) {
+ CK_ULONG updateLen = maxoutlen;
CK_ULONG finalLen;
/* padding is fairly complicated, have the update and final
* code deal with it */
sftk_FreeSession(session);
crv = NSC_EncryptUpdate(hSession, pData, ulDataLen, pEncryptedData,
- pulEncryptedDataLen);
- if (crv != CKR_OK)
- *pulEncryptedDataLen = 0;
- maxoutlen -= *pulEncryptedDataLen;
- pEncryptedData += *pulEncryptedDataLen;
+ &updateLen);
+ if (crv != CKR_OK) {
+ updateLen = 0;
+ }
+ maxoutlen -= updateLen;
+ pEncryptedData += updateLen;
finalLen = maxoutlen;
crv2 = NSC_EncryptFinal(hSession, pEncryptedData, &finalLen);
- if (crv2 == CKR_OK)
- *pulEncryptedDataLen += finalLen;
+ if (crv == CKR_OK && crv2 == CKR_OK) {
+ *pulEncryptedDataLen = updateLen + finalLen;
+ }
return crv == CKR_OK ? crv2 : crv;
}
/* doPad without multi means that padding must be done on the first
@@ -1437,14 +1509,15 @@ NSC_Encrypt(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData,
rv = (*context->update)(context->cipherInfo, pEncryptedData,
&outlen, maxoutlen, pText.data, pText.len);
crv = (rv == SECSuccess) ? CKR_OK : sftk_MapCryptError(PORT_GetError());
- *pulEncryptedDataLen = (CK_ULONG)outlen;
if (pText.data != pData)
PORT_ZFree(pText.data, pText.len);
fail:
sftk_TerminateOp(session, SFTK_ENCRYPT, context);
-finish:
+done:
sftk_FreeSession(session);
-
+ if (crv == CKR_OK) {
+ *pulEncryptedDataLen = (CK_ULONG)outlen;
+ }
return crv;
}
@@ -1533,8 +1606,73 @@ NSC_DecryptUpdate(CK_SESSION_HANDLE hSession,
/* do it: NOTE: this assumes buf size in is >= buf size out! */
rv = (*context->update)(context->cipherInfo, pPart, &outlen,
maxout, pEncryptedPart, ulEncryptedPartLen);
+ if (rv != SECSuccess) {
+ return sftk_MapDecryptError(PORT_GetError());
+ }
*pulPartLen = (CK_ULONG)(outlen + padoutlen);
- return (rv == SECSuccess) ? CKR_OK : sftk_MapDecryptError(PORT_GetError());
+ return CKR_OK;
+}
+
+/* From ssl3con.c: Constant-time helper macro that copies the MSB of x to all
+ * other bits. */
+#define DUPLICATE_MSB_TO_ALL(x) ((unsigned int)((int)(x) >> (sizeof(int) * 8 - 1)))
+/* CK_RVToMask returns, in constant time, a mask value of
+ * all ones if rv == CKR_OK. Otherwise it returns zero. */
+static unsigned int
+CK_RVToMask(CK_RV rv)
+{
+ unsigned int good;
+ /* rv ^ CKR_OK is zero iff rv == CKR_OK. Subtracting one results
+ * in the MSB being set to one iff it was zero before. */
+ good = rv ^ CKR_OK;
+ good--;
+ return DUPLICATE_MSB_TO_ALL(good);
+}
+/* Constant-time helper macro that selects l or r depending on all-1 or all-0
+ * mask m */
+#define CT_SEL(m, l, r) (((m) & (l)) | (~(m) & (r)))
+/* Constant-time helper macro that returns all-1s if x is not 0; and all-0s
+ * otherwise. */
+#define CT_NOT_ZERO(x) (DUPLICATE_MSB_TO_ALL(((x) | (0 - x))))
+
+/* sftk_CheckCBCPadding checks, in constant time, the padding validity and
+ * accordingly sets the pad length. */
+static CK_RV
+sftk_CheckCBCPadding(CK_BYTE_PTR pLastPart,
+ unsigned int blockSize, unsigned int *outPadSize)
+{
+ PORT_Assert(outPadSize);
+
+ unsigned int padSize = (unsigned int)pLastPart[blockSize - 1];
+
+ /* If padSize <= blockSize, set goodPad to all-1s and all-0s otherwise.*/
+ unsigned int goodPad = DUPLICATE_MSB_TO_ALL(~(blockSize - padSize));
+ /* padSize should not be 0 */
+ goodPad &= CT_NOT_ZERO(padSize);
+
+ unsigned int i;
+ for (i = 0; i < blockSize; i++) {
+ /* If i < padSize, set loopMask to all-1s and all-0s otherwise.*/
+ unsigned int loopMask = DUPLICATE_MSB_TO_ALL(~(padSize - 1 - i));
+ /* Get the padding value (should be padSize) from buffer */
+ unsigned int padVal = pLastPart[blockSize - 1 - i];
+ /* Update goodPad only if i < padSize */
+ goodPad &= CT_SEL(loopMask, ~(padVal ^ padSize), goodPad);
+ }
+
+ /* If any of the final padding bytes had the wrong value, one or more
+ * of the lower eight bits of |goodPad| will be cleared. We AND the
+ * bottom 8 bits together and duplicate the result to all the bits. */
+ goodPad &= goodPad >> 4;
+ goodPad &= goodPad >> 2;
+ goodPad &= goodPad >> 1;
+ goodPad <<= sizeof(goodPad) * 8 - 1;
+ goodPad = DUPLICATE_MSB_TO_ALL(goodPad);
+
+ /* Set outPadSize to padSize or 0 */
+ *outPadSize = CT_SEL(goodPad, padSize, 0);
+ /* Return OK if the pad is valid */
+ return CT_SEL(goodPad, CKR_OK, CKR_ENCRYPTED_DATA_INVALID);
}
/* NSC_DecryptFinal finishes a multiple-part decryption operation. */
@@ -1575,24 +1713,10 @@ NSC_DecryptFinal(CK_SESSION_HANDLE hSession,
if (rv != SECSuccess) {
crv = sftk_MapDecryptError(PORT_GetError());
} else {
- unsigned int padSize =
- (unsigned int)pLastPart[context->blockSize - 1];
- if ((padSize > context->blockSize) || (padSize == 0)) {
- crv = CKR_ENCRYPTED_DATA_INVALID;
- } else {
- unsigned int i;
- unsigned int badPadding = 0; /* used as a boolean */
- for (i = 0; i < padSize; i++) {
- badPadding |=
- (unsigned int)pLastPart[context->blockSize - 1 - i] ^
- padSize;
- }
- if (badPadding) {
- crv = CKR_ENCRYPTED_DATA_INVALID;
- } else {
- *pulLastPartLen = outlen - padSize;
- }
- }
+ unsigned int padSize = 0;
+ crv = sftk_CheckCBCPadding(&pLastPart[outlen - context->blockSize], context->blockSize, &padSize);
+ /* Update pulLastPartLen, in constant time, if crv is OK */
+ *pulLastPartLen = CT_SEL(CK_RVToMask(crv), outlen - padSize, *pulLastPartLen);
}
}
}
@@ -1625,52 +1749,48 @@ NSC_Decrypt(CK_SESSION_HANDLE hSession,
return crv;
if (!pData) {
- *pulDataLen = ulEncryptedDataLen + context->blockSize;
- goto finish;
+ *pulDataLen = (CK_ULONG)(ulEncryptedDataLen + context->blockSize);
+ goto done;
}
if (context->doPad && context->multi) {
+ CK_ULONG updateLen = maxoutlen;
CK_ULONG finalLen;
/* padding is fairly complicated, have the update and final
* code deal with it */
sftk_FreeSession(session);
crv = NSC_DecryptUpdate(hSession, pEncryptedData, ulEncryptedDataLen,
- pData, pulDataLen);
- if (crv != CKR_OK)
- *pulDataLen = 0;
- maxoutlen -= *pulDataLen;
- pData += *pulDataLen;
+ pData, &updateLen);
+ if (crv == CKR_OK) {
+ maxoutlen -= updateLen;
+ pData += updateLen;
+ }
finalLen = maxoutlen;
crv2 = NSC_DecryptFinal(hSession, pData, &finalLen);
- if (crv2 == CKR_OK)
- *pulDataLen += finalLen;
- return crv == CKR_OK ? crv2 : crv;
+ if (crv == CKR_OK) {
+ *pulDataLen = CT_SEL(CK_RVToMask(crv2), updateLen + finalLen, *pulDataLen);
+ return crv2;
+ } else {
+ return crv;
+ }
}
rv = (*context->update)(context->cipherInfo, pData, &outlen, maxoutlen,
pEncryptedData, ulEncryptedDataLen);
/* XXX need to do MUCH better error mapping than this. */
crv = (rv == SECSuccess) ? CKR_OK : sftk_MapDecryptError(PORT_GetError());
- if (rv == SECSuccess && context->doPad) {
- unsigned int padding = pData[outlen - 1];
- if (padding > context->blockSize || !padding) {
- crv = CKR_ENCRYPTED_DATA_INVALID;
+ if (rv == SECSuccess) {
+ if (context->doPad) {
+ unsigned int padSize = 0;
+ crv = sftk_CheckCBCPadding(&pData[outlen - context->blockSize], context->blockSize, &padSize);
+ /* Update pulDataLen, in constant time, if crv is OK */
+ *pulDataLen = CT_SEL(CK_RVToMask(crv), outlen - padSize, *pulDataLen);
} else {
- unsigned int i;
- unsigned int badPadding = 0; /* used as a boolean */
- for (i = 0; i < padding; i++) {
- badPadding |= (unsigned int)pData[outlen - 1 - i] ^ padding;
- }
- if (badPadding) {
- crv = CKR_ENCRYPTED_DATA_INVALID;
- } else {
- outlen -= padding;
- }
+ *pulDataLen = (CK_ULONG)outlen;
}
}
- *pulDataLen = (CK_ULONG)outlen;
sftk_TerminateOp(session, SFTK_DECRYPT, context);
-finish:
+done:
sftk_FreeSession(session);
return crv;
}
@@ -1880,58 +2000,59 @@ static SECStatus
sftk_HMACCmp(CK_ULONG *copyLen, unsigned char *sig, unsigned int sigLen,
unsigned char *hash, unsigned int hashLen)
{
- return (PORT_Memcmp(sig, hash, *copyLen) == 0) ? SECSuccess : SECFailure;
+ return (NSS_SecureMemcmp(sig, hash, *copyLen) == 0) ? SECSuccess : SECFailure;
}
/*
- * common HMAC initalization routine
+ * common HMAC + CMAC initialization routine
*/
static CK_RV
-sftk_doHMACInit(SFTKSessionContext *context, HASH_HashType hash,
- SFTKObject *key, CK_ULONG mac_size)
+sftk_doMACInit(CK_MECHANISM_TYPE mech, SFTKSessionContext *session,
+ SFTKObject *key, CK_ULONG mac_size)
{
- SFTKAttribute *keyval;
- HMACContext *HMACcontext;
+ CK_RV crv;
+ sftk_MACCtx *context;
CK_ULONG *intpointer;
- const SECHashObject *hashObj = HASH_GetRawHashObject(hash);
PRBool isFIPS = (key->slot->slotID == FIPS_SLOT_ID);
- /* required by FIPS 198 Section 4 */
- if (isFIPS && (mac_size < 4 || mac_size < hashObj->length / 2)) {
- return CKR_BUFFER_TOO_SMALL;
+ /* Set up the initial context. */
+ crv = sftk_MAC_Create(mech, key, &context);
+ if (crv != CKR_OK) {
+ return crv;
}
- keyval = sftk_FindAttribute(key, CKA_VALUE);
- if (keyval == NULL)
- return CKR_KEY_SIZE_RANGE;
+ session->hashInfo = context;
+ session->multi = PR_TRUE;
- HMACcontext = HMAC_Create(hashObj,
- (const unsigned char *)keyval->attrib.pValue,
- keyval->attrib.ulValueLen, isFIPS);
- context->hashInfo = HMACcontext;
- context->multi = PR_TRUE;
- sftk_FreeAttribute(keyval);
- if (context->hashInfo == NULL) {
- if (PORT_GetError() == SEC_ERROR_INVALID_ARGS) {
- return CKR_KEY_SIZE_RANGE;
- }
- return CKR_HOST_MEMORY;
+ /* Required by FIPS 198 Section 4. Delay this check until after the MAC
+ * has been initialized to steal the output size of the MAC. */
+ if (isFIPS && (mac_size < 4 || mac_size < context->mac_size / 2)) {
+ sftk_MAC_Destroy(context, PR_TRUE);
+ return CKR_BUFFER_TOO_SMALL;
}
- context->hashUpdate = (SFTKHash)HMAC_Update;
- context->end = (SFTKEnd)HMAC_Finish;
- context->hashdestroy = (SFTKDestroy)HMAC_Destroy;
+ /* Configure our helper functions appropriately. Note that these casts
+ * ignore the return values. */
+ session->hashUpdate = (SFTKHash)sftk_MAC_Update;
+ session->end = (SFTKEnd)sftk_MAC_Finish;
+ session->hashdestroy = (SFTKDestroy)sftk_MAC_Destroy;
+
intpointer = PORT_New(CK_ULONG);
if (intpointer == NULL) {
+ sftk_MAC_Destroy(context, PR_TRUE);
return CKR_HOST_MEMORY;
}
*intpointer = mac_size;
- context->cipherInfo = intpointer;
- context->destroy = (SFTKDestroy)sftk_Space;
- context->update = (SFTKCipher)sftk_SignCopy;
- context->verify = (SFTKVerify)sftk_HMACCmp;
- context->maxLen = hashObj->length;
- HMAC_Begin(HMACcontext);
+ session->cipherInfo = intpointer;
+
+ /* Since we're only "hashing", copy the result from session->end to the
+ * caller using sftk_SignCopy. */
+ session->update = (SFTKCipher)sftk_SignCopy;
+ session->verify = (SFTKVerify)sftk_HMACCmp;
+ session->destroy = (SFTKDestroy)sftk_Space;
+
+ session->maxLen = context->mac_size;
+
return CKR_OK;
}
@@ -1996,7 +2117,7 @@ sftk_SSLMACVerify(SFTKSSLMACInfo *info, unsigned char *sig, unsigned int sigLen,
info->update(info->hashContext, ssl_pad_2, info->padSize);
info->update(info->hashContext, hash, hashLen);
info->end(info->hashContext, tmpBuf, &out, SFTK_MAX_MAC_LENGTH);
- return (PORT_Memcmp(sig, tmpBuf, info->macSize) == 0) ? SECSuccess : SECFailure;
+ return (NSS_SecureMemcmp(sig, tmpBuf, info->macSize) == 0) ? SECSuccess : SECFailure;
}
/*
@@ -2080,13 +2201,20 @@ sftk_InitCBCMac(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
CK_RC5_MAC_GENERAL_PARAMS *rc5_mac;
#endif
unsigned char ivBlock[SFTK_MAX_BLOCK_SIZE];
+ unsigned char k2[SFTK_MAX_BLOCK_SIZE];
+ unsigned char k3[SFTK_MAX_BLOCK_SIZE];
SFTKSessionContext *context;
CK_RV crv;
unsigned int blockSize;
+ PRBool isXCBC = PR_FALSE;
+
+ if (!pMechanism) {
+ return CKR_MECHANISM_PARAM_INVALID;
+ }
switch (pMechanism->mechanism) {
case CKM_RC2_MAC_GENERAL:
- if (!pMechanism->pParameter) {
+ if (BAD_PARAM_CAST(pMechanism, sizeof(CK_RC2_MAC_GENERAL_PARAMS))) {
return CKR_MECHANISM_PARAM_INVALID;
}
mac_bytes =
@@ -2106,12 +2234,18 @@ sftk_InitCBCMac(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
break;
#if NSS_SOFTOKEN_DOES_RC5
case CKM_RC5_MAC_GENERAL:
+ if (BAD_PARAM_CAST(pMechanism, sizeof(CK_RC5_MAC_GENERAL_PARAMS))) {
+ return CKR_MECHANISM_PARAM_INVALID;
+ }
mac_bytes =
((CK_RC5_MAC_GENERAL_PARAMS *)pMechanism->pParameter)->ulMacLength;
/* fall through */
case CKM_RC5_MAC:
/* this works because ulEffectiveBits is in the same place in both the
* CK_RC5_MAC_GENERAL_PARAMS and CK_RC5_CBC_PARAMS */
+ if (BAD_PARAM_CAST(pMechanism, sizeof(CK_RC5_MAC_GENERAL_PARAMS))) {
+ return CKR_MECHANISM_PARAM_INVALID;
+ }
rc5_mac = (CK_RC5_MAC_GENERAL_PARAMS *)pMechanism->pParameter;
rc5_params.ulWordsize = rc5_mac->ulWordsize;
rc5_params.ulRounds = rc5_mac->ulRounds;
@@ -2186,6 +2320,26 @@ sftk_InitCBCMac(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
cbc_mechanism.pParameter = &ivBlock;
cbc_mechanism.ulParameterLen = blockSize;
break;
+ case CKM_AES_XCBC_MAC_96:
+ case CKM_AES_XCBC_MAC:
+ /* The only difference between CKM_AES_XCBC_MAC
+ * and CKM_AES_XCBC_MAC_96 is the size of the returned mac. */
+ mac_bytes = pMechanism->mechanism == CKM_AES_XCBC_MAC_96 ? 12 : 16;
+ blockSize = 16;
+ PORT_Memset(ivBlock, 0, blockSize);
+ cbc_mechanism.mechanism = CKM_AES_CBC;
+ cbc_mechanism.pParameter = &ivBlock;
+ cbc_mechanism.ulParameterLen = blockSize;
+ /* is XCBC requires extra processing at the end of the operation */
+ isXCBC = PR_TRUE;
+ /* The input key is used to generate k1, k2, and k3. k2 and k3
+ * are used at the end in the pad step. k1 replaces the input
+ * key in the aes cbc mac */
+ crv = sftk_aes_xcbc_new_keys(hSession, hKey, &hKey, k2, k3);
+ if (crv != CKR_OK) {
+ return crv;
+ }
+ break;
default:
return CKR_FUNCTION_NOT_SUPPORTED;
}
@@ -2195,24 +2349,43 @@ sftk_InitCBCMac(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
if (mac_bytes == SFTK_INVALID_MAC_SIZE)
mac_bytes = blockSize >> 1;
else {
- if (mac_bytes > blockSize)
- return CKR_MECHANISM_PARAM_INVALID;
+ if (mac_bytes > blockSize) {
+ crv = CKR_MECHANISM_PARAM_INVALID;
+ goto fail;
+ }
}
crv = sftk_CryptInit(hSession, &cbc_mechanism, hKey,
CKA_ENCRYPT, /* CBC mech is able to ENCRYPT, not SIGN/VERIFY */
keyUsage, contextType, PR_TRUE);
if (crv != CKR_OK)
- return crv;
+ goto fail;
crv = sftk_GetContext(hSession, &context, contextType, PR_TRUE, NULL);
/* this shouldn't happen! */
PORT_Assert(crv == CKR_OK);
if (crv != CKR_OK)
- return crv;
+ goto fail;
context->blockSize = blockSize;
context->macSize = mac_bytes;
+ context->isXCBC = isXCBC;
+ if (isXCBC) {
+ /* save the xcbc specific parameters */
+ PORT_Memcpy(context->k2, k2, blockSize);
+ PORT_Memcpy(context->k3, k3, blockSize);
+ PORT_Memset(k2, 0, blockSize);
+ PORT_Memset(k3, 0, blockSize);
+ /* get rid of the temp key now that the context has been created */
+ NSC_DestroyObject(hSession, hKey);
+ }
return CKR_OK;
+fail:
+ if (isXCBC) {
+ PORT_Memset(k2, 0, blockSize);
+ PORT_Memset(k3, 0, blockSize);
+ NSC_DestroyObject(hSession, hKey); /* get rid of our temp key */
+ }
+ return crv;
}
/*
@@ -2629,18 +2802,19 @@ NSC_SignInit(CK_SESSION_HANDLE hSession,
break;
-#define INIT_HMAC_MECH(mmm) \
- case CKM_##mmm##_HMAC_GENERAL: \
- PORT_Assert(pMechanism->pParameter); \
- if (!pMechanism->pParameter) { \
- crv = CKR_MECHANISM_PARAM_INVALID; \
- break; \
- } \
- crv = sftk_doHMACInit(context, HASH_Alg##mmm, key, \
- *(CK_ULONG *)pMechanism->pParameter); \
- break; \
- case CKM_##mmm##_HMAC: \
- crv = sftk_doHMACInit(context, HASH_Alg##mmm, key, mmm##_LENGTH); \
+#define INIT_HMAC_MECH(mmm) \
+ case CKM_##mmm##_HMAC_GENERAL: \
+ PORT_Assert(pMechanism->pParameter); \
+ if (!pMechanism->pParameter) { \
+ crv = CKR_MECHANISM_PARAM_INVALID; \
+ break; \
+ } \
+ crv = sftk_doMACInit(pMechanism->mechanism, context, key, \
+ *(CK_ULONG *)pMechanism->pParameter); \
+ break; \
+ case CKM_##mmm##_HMAC: \
+ crv = sftk_doMACInit(pMechanism->mechanism, context, key, \
+ mmm##_LENGTH); \
break;
INIT_HMAC_MECH(MD2)
@@ -2652,17 +2826,27 @@ NSC_SignInit(CK_SESSION_HANDLE hSession,
case CKM_SHA_1_HMAC_GENERAL:
PORT_Assert(pMechanism->pParameter);
- if (!pMechanism->pParameter) {
+ if (!pMechanism->pParameter || pMechanism->ulParameterLen != sizeof(CK_MAC_GENERAL_PARAMS)) {
crv = CKR_MECHANISM_PARAM_INVALID;
break;
}
- crv = sftk_doHMACInit(context, HASH_AlgSHA1, key,
- *(CK_ULONG *)pMechanism->pParameter);
+ crv = sftk_doMACInit(pMechanism->mechanism, context, key,
+ *(CK_ULONG *)pMechanism->pParameter);
break;
case CKM_SHA_1_HMAC:
- crv = sftk_doHMACInit(context, HASH_AlgSHA1, key, SHA1_LENGTH);
+ crv = sftk_doMACInit(pMechanism->mechanism, context, key, SHA1_LENGTH);
+ break;
+ case CKM_AES_CMAC_GENERAL:
+ PORT_Assert(pMechanism->pParameter);
+ if (!pMechanism->pParameter || pMechanism->ulParameterLen != sizeof(CK_MAC_GENERAL_PARAMS)) {
+ crv = CKR_MECHANISM_PARAM_INVALID;
+ break;
+ }
+ crv = sftk_doMACInit(pMechanism->mechanism, context, key, *(CK_ULONG *)pMechanism->pParameter);
+ break;
+ case CKM_AES_CMAC:
+ crv = sftk_doMACInit(pMechanism->mechanism, context, key, AES_BLOCK_SIZE);
break;
-
case CKM_SSL3_MD5_MAC:
PORT_Assert(pMechanism->pParameter);
if (!pMechanism->pParameter) {
@@ -2828,6 +3012,13 @@ sftk_MACFinal(SFTKSessionContext *ctx)
{
unsigned int padLen = ctx->padDataLength;
/* pad and proceed the residual */
+ if (ctx->isXCBC) {
+ CK_RV crv = sftk_xcbc_mac_pad(ctx->padBuf, padLen, ctx->blockSize,
+ ctx->k2, ctx->k3);
+ if (crv != CKR_OK)
+ return crv;
+ return sftk_MACBlock(ctx, ctx->padBuf);
+ }
if (padLen) {
/* shd clr ctx->padLen to make sftk_MACFinal idempotent */
PORT_Memset(ctx->padBuf + padLen, 0, ctx->blockSize - padLen);
@@ -2866,7 +3057,7 @@ sftk_MACUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart,
blkSize - context->padDataLength;
/* not enough data even for one block */
- if (ulPartLen < minInput) {
+ if (ulPartLen <= minInput) {
PORT_Memcpy(residual, pPart, ulPartLen);
context->padDataLength += ulPartLen;
goto cleanup;
@@ -2880,7 +3071,7 @@ sftk_MACUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart,
goto terminate;
}
/* MACing full blocks */
- while (ulPartLen >= blkSize) {
+ while (ulPartLen > blkSize) {
if (CKR_OK != (crv = sftk_MACBlock(context, pPart)))
goto terminate;
ulPartLen -= blkSize;
@@ -3329,11 +3520,11 @@ NSC_VerifyInit(CK_SESSION_HANDLE hSession,
crv = CKR_MECHANISM_PARAM_INVALID;
break;
}
- crv = sftk_doHMACInit(context, HASH_AlgSHA1, key,
- *(CK_ULONG *)pMechanism->pParameter);
+ crv = sftk_doMACInit(pMechanism->mechanism, context, key,
+ *(CK_ULONG *)pMechanism->pParameter);
break;
case CKM_SHA_1_HMAC:
- crv = sftk_doHMACInit(context, HASH_AlgSHA1, key, SHA1_LENGTH);
+ crv = sftk_doMACInit(pMechanism->mechanism, context, key, SHA1_LENGTH);
break;
case CKM_SSL3_MD5_MAC:
@@ -3459,7 +3650,7 @@ NSC_VerifyFinal(CK_SESSION_HANDLE hSession,
/* must be block cipher MACing */
crv = CKR_SIGNATURE_LEN_RANGE;
} else if (CKR_OK == (crv = sftk_MACFinal(context))) {
- if (PORT_Memcmp(pSignature, context->macBuf, ulSignatureLen))
+ if (NSS_SecureMemcmp(pSignature, context->macBuf, ulSignatureLen))
crv = CKR_SIGNATURE_INVALID;
}
@@ -3659,11 +3850,17 @@ nsc_pbe_key_gen(NSSPKCS5PBEParameter *pkcs5_pbe, CK_MECHANISM_PTR pMechanism,
iv.len = 0;
if (pMechanism->mechanism == CKM_PKCS5_PBKD2) {
+ if (BAD_PARAM_CAST(pMechanism, sizeof(CK_PKCS5_PBKD2_PARAMS))) {
+ return CKR_MECHANISM_PARAM_INVALID;
+ }
pbkd2_params = (CK_PKCS5_PBKD2_PARAMS *)pMechanism->pParameter;
pwitem.data = (unsigned char *)pbkd2_params->pPassword;
/* was this a typo in the PKCS #11 spec? */
pwitem.len = *pbkd2_params->ulPasswordLen;
} else {
+ if (BAD_PARAM_CAST(pMechanism, sizeof(CK_PBE_PARAMS))) {
+ return CKR_MECHANISM_PARAM_INVALID;
+ }
pbe_params = (CK_PBE_PARAMS *)pMechanism->pParameter;
pwitem.data = (unsigned char *)pbe_params->pPassword;
pwitem.len = pbe_params->ulPasswordLen;
@@ -3963,6 +4160,10 @@ nsc_SetupHMACKeyGen(CK_MECHANISM_PTR pMechanism, NSSPKCS5PBEParameter **pbe)
PORT_FreeArena(arena, PR_TRUE);
return CKR_HOST_MEMORY;
}
+ if (BAD_PARAM_CAST(pMechanism, sizeof(CK_PBE_PARAMS))) {
+ PORT_FreeArena(arena, PR_TRUE);
+ return CKR_MECHANISM_PARAM_INVALID;
+ }
params->poolp = arena;
params->ivLen = 0;
@@ -4042,10 +4243,10 @@ nsc_SetupPBEKeyGen(CK_MECHANISM_PTR pMechanism, NSSPKCS5PBEParameter **pbe,
}
if (pMechanism->mechanism == CKM_PKCS5_PBKD2) {
- pbkd2_params = (CK_PKCS5_PBKD2_PARAMS *)pMechanism->pParameter;
- if (pbkd2_params == NULL) {
+ if (BAD_PARAM_CAST(pMechanism, sizeof(CK_PKCS5_PBKD2_PARAMS))) {
return CKR_MECHANISM_PARAM_INVALID;
}
+ pbkd2_params = (CK_PKCS5_PBKD2_PARAMS *)pMechanism->pParameter;
switch (pbkd2_params->prf) {
case CKP_PKCS5_PBKD2_HMAC_SHA1:
hashType = HASH_AlgSHA1;
@@ -4072,6 +4273,9 @@ nsc_SetupPBEKeyGen(CK_MECHANISM_PTR pMechanism, NSSPKCS5PBEParameter **pbe,
salt.len = (unsigned int)pbkd2_params->ulSaltSourceDataLen;
iteration = pbkd2_params->iterations;
} else {
+ if (BAD_PARAM_CAST(pMechanism, sizeof(CK_PBE_PARAMS))) {
+ return CKR_MECHANISM_PARAM_INVALID;
+ }
pbe_params = (CK_PBE_PARAMS *)pMechanism->pParameter;
salt.data = (unsigned char *)pbe_params->pSalt;
salt.len = (unsigned int)pbe_params->ulSaltLen;
@@ -4118,11 +4322,12 @@ nsc_SetupPBEKeyGen(CK_MECHANISM_PTR pMechanism, NSSPKCS5PBEParameter **pbe,
break;
default:
crv = CKR_MECHANISM_INVALID;
- nsspkcs5_DestroyPBEParameter(params);
break;
}
if (crv == CKR_OK) {
*pbe = params;
+ } else {
+ nsspkcs5_DestroyPBEParameter(params);
}
return crv;
}
@@ -4187,12 +4392,12 @@ NSC_GenerateKey(CK_SESSION_HANDLE hSession,
}
crv = sftk_AddAttributeType(key, sftk_attr_expand(&pTemplate[i]));
- if (crv != CKR_OK)
+ if (crv != CKR_OK) {
break;
+ }
}
if (crv != CKR_OK) {
- sftk_FreeObject(key);
- return crv;
+ goto loser;
}
/* make sure we don't have any class, key_type, or value fields */
@@ -4305,8 +4510,10 @@ NSC_GenerateKey(CK_SESSION_HANDLE hSession,
}
if (crv != CKR_OK) {
- sftk_FreeObject(key);
- return crv;
+ if (pbe_param) {
+ nsspkcs5_DestroyPBEParameter(pbe_param);
+ }
+ goto loser;
}
/* if there was no error,
@@ -4324,6 +4531,10 @@ NSC_GenerateKey(CK_SESSION_HANDLE hSession,
break;
case nsc_ssl:
rsa_pms = (SSL3RSAPreMasterSecret *)buf;
+ if (BAD_PARAM_CAST(pMechanism, sizeof(CK_VERSION))) {
+ crv = CKR_MECHANISM_PARAM_INVALID;
+ goto loser;
+ }
version = (CK_VERSION *)pMechanism->pParameter;
rsa_pms->client_version[0] = version->major;
rsa_pms->client_version[1] = version->minor;
@@ -4342,6 +4553,10 @@ NSC_GenerateKey(CK_SESSION_HANDLE hSession,
crv = nsc_parameter_gen(key_type, key);
break;
case nsc_jpake:
+ if (BAD_PARAM_CAST(pMechanism, sizeof(CK_NSS_JPAKERound1Params))) {
+ crv = CKR_MECHANISM_PARAM_INVALID;
+ goto loser;
+ }
crv = jpake_Round1(hashType,
(CK_NSS_JPAKERound1Params *)pMechanism->pParameter,
key);
@@ -4349,34 +4564,30 @@ NSC_GenerateKey(CK_SESSION_HANDLE hSession,
}
if (crv != CKR_OK) {
- sftk_FreeObject(key);
- return crv;
+ goto loser;
}
/* Add the class, key_type, and value */
crv = sftk_AddAttributeType(key, CKA_CLASS, &objclass, sizeof(CK_OBJECT_CLASS));
if (crv != CKR_OK) {
- sftk_FreeObject(key);
- return crv;
+ goto loser;
}
crv = sftk_AddAttributeType(key, CKA_KEY_TYPE, &key_type, sizeof(CK_KEY_TYPE));
if (crv != CKR_OK) {
- sftk_FreeObject(key);
- return crv;
+ goto loser;
}
if (key_length != 0) {
crv = sftk_AddAttributeType(key, CKA_VALUE, buf, key_length);
if (crv != CKR_OK) {
- sftk_FreeObject(key);
- return crv;
+ goto loser;
}
}
/* get the session */
session = sftk_SessionFromHandle(hSession);
if (session == NULL) {
- sftk_FreeObject(key);
- return CKR_SESSION_HANDLE_INVALID;
+ crv = CKR_SESSION_HANDLE_INVALID;
+ goto loser;
}
/*
@@ -4393,6 +4604,7 @@ NSC_GenerateKey(CK_SESSION_HANDLE hSession,
if (crv == CKR_OK) {
*phKey = key->handle;
}
+loser:
sftk_FreeObject(key);
return crv;
}
@@ -4645,6 +4857,13 @@ sftk_PairwiseConsistencyCheck(CK_SESSION_HANDLE hSession,
return crv;
}
+ /* detect trivial signing transforms */
+ if ((signature_length >= pairwise_digest_length) &&
+ (PORT_Memcmp(known_digest, signature + (signature_length - pairwise_digest_length), pairwise_digest_length) == 0)) {
+ PORT_Free(signature);
+ return CKR_DEVICE_ERROR;
+ }
+
/* Verify the known hash using the public key. */
crv = NSC_VerifyInit(hSession, &mech, publicKey->handle);
if (crv != CKR_OK) {
@@ -4838,6 +5057,7 @@ NSC_GenerateKeyPair(CK_SESSION_HANDLE hSession,
bitSize = sftk_GetLengthInBits(pubExp.data, pubExp.len);
if (bitSize < 2) {
crv = CKR_ATTRIBUTE_VALUE_INVALID;
+ PORT_Free(pubExp.data);
break;
}
crv = sftk_AddAttributeType(privateKey, CKA_PUBLIC_EXPONENT,
@@ -5498,8 +5718,8 @@ NSC_WrapKey(CK_SESSION_HANDLE hSession,
}
key = sftk_ObjectFromHandle(hKey, session);
- sftk_FreeSession(session);
if (key == NULL) {
+ sftk_FreeSession(session);
return CKR_KEY_HANDLE_INVALID;
}
@@ -5605,7 +5825,7 @@ NSC_WrapKey(CK_SESSION_HANDLE hSession,
break;
}
sftk_FreeObject(key);
-
+ sftk_FreeSession(session);
return sftk_mapWrap(crv);
}
@@ -6414,7 +6634,6 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession,
CK_KEY_TYPE keyType = CKK_GENERIC_SECRET;
CK_OBJECT_CLASS classType = CKO_SECRET_KEY;
CK_KEY_DERIVATION_STRING_DATA *stringPtr;
- CK_MECHANISM_TYPE mechanism = pMechanism->mechanism;
PRBool isTLS = PR_FALSE;
PRBool isDH = PR_FALSE;
HASH_HashType tlsPrfHash = HASH_AlgNULL;
@@ -6432,6 +6651,11 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession,
if (!slot) {
return CKR_SESSION_HANDLE_INVALID;
}
+ if (!pMechanism) {
+ return CKR_MECHANISM_PARAM_INVALID;
+ }
+ CK_MECHANISM_TYPE mechanism = pMechanism->mechanism;
+
/*
* now lets create an object to hang the attributes off of
*/
@@ -6476,6 +6700,10 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession,
extractValue = PR_FALSE;
classType = CKO_PRIVATE_KEY;
break;
+ case CKM_NSS_PUB_FROM_PRIV:
+ extractValue = PR_FALSE;
+ classType = CKO_PUBLIC_KEY;
+ break;
case CKM_NSS_JPAKE_FINAL_SHA1: /* fall through */
case CKM_NSS_JPAKE_FINAL_SHA256: /* fall through */
case CKM_NSS_JPAKE_FINAL_SHA384: /* fall through */
@@ -6517,6 +6745,73 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession,
}
switch (mechanism) {
+ /* get a public key from a private key. nsslowkey_ConvertToPublickey()
+ * will generate the public portion if it doesn't already exist. */
+ case CKM_NSS_PUB_FROM_PRIV: {
+ NSSLOWKEYPrivateKey *privKey;
+ NSSLOWKEYPublicKey *pubKey;
+ int error;
+
+ crv = sftk_GetULongAttribute(sourceKey, CKA_KEY_TYPE, &keyType);
+ if (crv != CKR_OK) {
+ break;
+ }
+
+ /* privKey is stored in sourceKey and will be destroyed when
+ * the sourceKey is freed. */
+ privKey = sftk_GetPrivKey(sourceKey, keyType, &crv);
+ if (privKey == NULL) {
+ break;
+ }
+ pubKey = nsslowkey_ConvertToPublicKey(privKey);
+ if (pubKey == NULL) {
+ error = PORT_GetError();
+ crv = sftk_MapCryptError(error);
+ break;
+ }
+ crv = sftk_PutPubKey(key, sourceKey, keyType, pubKey);
+ nsslowkey_DestroyPublicKey(pubKey);
+ break;
+ }
+ case CKM_NSS_IKE_PRF_DERIVE:
+ if (pMechanism->ulParameterLen !=
+ sizeof(CK_NSS_IKE_PRF_DERIVE_PARAMS)) {
+ crv = CKR_MECHANISM_PARAM_INVALID;
+ break;
+ }
+ crv = sftk_ike_prf(hSession, att,
+ (CK_NSS_IKE_PRF_DERIVE_PARAMS *)pMechanism->pParameter, key);
+ break;
+ case CKM_NSS_IKE1_PRF_DERIVE:
+ if (pMechanism->ulParameterLen !=
+ sizeof(CK_NSS_IKE1_PRF_DERIVE_PARAMS)) {
+ crv = CKR_MECHANISM_PARAM_INVALID;
+ break;
+ }
+ crv = sftk_ike1_prf(hSession, att,
+ (CK_NSS_IKE1_PRF_DERIVE_PARAMS *)pMechanism->pParameter,
+ key, keySize);
+ break;
+ case CKM_NSS_IKE1_APP_B_PRF_DERIVE:
+ if (pMechanism->ulParameterLen !=
+ sizeof(CK_MECHANISM_TYPE)) {
+ crv = CKR_MECHANISM_PARAM_INVALID;
+ break;
+ }
+ crv = sftk_ike1_appendix_b_prf(hSession, att,
+ (CK_MECHANISM_TYPE *)pMechanism->pParameter,
+ key, keySize);
+ break;
+ case CKM_NSS_IKE_PRF_PLUS_DERIVE:
+ if (pMechanism->ulParameterLen !=
+ sizeof(CK_NSS_IKE_PRF_PLUS_DERIVE_PARAMS)) {
+ crv = CKR_MECHANISM_PARAM_INVALID;
+ break;
+ }
+ crv = sftk_ike_prf_plus(hSession, att,
+ (CK_NSS_IKE_PRF_PLUS_DERIVE_PARAMS *)pMechanism->pParameter,
+ key, keySize);
+ break;
/*
* generate the master secret
*/
@@ -6534,6 +6829,10 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession,
if ((mechanism == CKM_TLS12_MASTER_KEY_DERIVE) ||
(mechanism == CKM_TLS12_MASTER_KEY_DERIVE_DH)) {
+ if (BAD_PARAM_CAST(pMechanism, sizeof(CK_TLS12_MASTER_KEY_DERIVE_PARAMS))) {
+ crv = CKR_MECHANISM_PARAM_INVALID;
+ break;
+ }
CK_TLS12_MASTER_KEY_DERIVE_PARAMS *tls12_master =
(CK_TLS12_MASTER_KEY_DERIVE_PARAMS *)pMechanism->pParameter;
tlsPrfHash = GetHashTypeFromMechanism(tls12_master->prfHashMechanism);
@@ -6801,6 +7100,10 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession,
unsigned char crsrdata[SSL3_RANDOM_LENGTH * 2];
if (mechanism == CKM_TLS12_KEY_AND_MAC_DERIVE) {
+ if (BAD_PARAM_CAST(pMechanism, sizeof(CK_TLS12_KEY_MAT_PARAMS))) {
+ crv = CKR_MECHANISM_PARAM_INVALID;
+ break;
+ }
CK_TLS12_KEY_MAT_PARAMS *tls12_keys =
(CK_TLS12_KEY_MAT_PARAMS *)pMechanism->pParameter;
tlsPrfHash = GetHashTypeFromMechanism(tls12_keys->prfHashMechanism);
@@ -6844,6 +7147,13 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession,
crv = CKR_HOST_MEMORY;
break;
}
+
+ if (BAD_PARAM_CAST(pMechanism, sizeof(CK_SSL3_KEY_MAT_PARAMS))) {
+ MD5_DestroyContext(md5, PR_TRUE);
+ SHA1_DestroyContext(sha, PR_TRUE);
+ crv = CKR_MECHANISM_PARAM_INVALID;
+ break;
+ }
ssl3_keys = (CK_SSL3_KEY_MAT_PARAMS *)pMechanism->pParameter;
PORT_Memcpy(srcrdata,
@@ -7038,6 +7348,10 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession,
CK_ULONG len;
if (mechanism == CKM_DES3_ECB_ENCRYPT_DATA) {
+ if (BAD_PARAM_CAST(pMechanism, sizeof(CK_KEY_DERIVATION_STRING_DATA))) {
+ crv = CKR_MECHANISM_PARAM_INVALID;
+ break;
+ }
stringPtr = (CK_KEY_DERIVATION_STRING_DATA *)
pMechanism->pParameter;
mode = NSS_DES_EDE3;
@@ -7087,10 +7401,18 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession,
if (mechanism == CKM_AES_ECB_ENCRYPT_DATA) {
mode = NSS_AES;
iv = NULL;
+ if (BAD_PARAM_CAST(pMechanism, sizeof(CK_KEY_DERIVATION_STRING_DATA))) {
+ crv = CKR_MECHANISM_PARAM_INVALID;
+ break;
+ }
stringPtr = (CK_KEY_DERIVATION_STRING_DATA *)pMechanism->pParameter;
data = stringPtr->pData;
len = stringPtr->ulLen;
} else {
+ if (BAD_PARAM_CAST(pMechanism, sizeof(CK_AES_CBC_ENCRYPT_DATA_PARAMS))) {
+ crv = CKR_MECHANISM_PARAM_INVALID;
+ break;
+ }
aesEncryptPtr =
(CK_AES_CBC_ENCRYPT_DATA_PARAMS *)pMechanism->pParameter;
mode = NSS_AES_CBC;
@@ -7123,6 +7445,10 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession,
CK_ULONG len;
if (mechanism == CKM_CAMELLIA_ECB_ENCRYPT_DATA) {
+ if (BAD_PARAM_CAST(pMechanism, sizeof(CK_KEY_DERIVATION_STRING_DATA))) {
+ crv = CKR_MECHANISM_PARAM_INVALID;
+ break;
+ }
stringPtr = (CK_KEY_DERIVATION_STRING_DATA *)
pMechanism->pParameter;
aesEncryptPtr = NULL;
@@ -7131,6 +7457,10 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession,
len = stringPtr->ulLen;
iv = NULL;
} else {
+ if (BAD_PARAM_CAST(pMechanism, sizeof(CK_AES_CBC_ENCRYPT_DATA_PARAMS))) {
+ crv = CKR_MECHANISM_PARAM_INVALID;
+ break;
+ }
stringPtr = NULL;
aesEncryptPtr = (CK_AES_CBC_ENCRYPT_DATA_PARAMS *)
pMechanism->pParameter;
@@ -7164,6 +7494,10 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession,
CK_ULONG len;
if (mechanism == CKM_SEED_ECB_ENCRYPT_DATA) {
+ if (BAD_PARAM_CAST(pMechanism, sizeof(CK_KEY_DERIVATION_STRING_DATA))) {
+ crv = CKR_MECHANISM_PARAM_INVALID;
+ break;
+ }
mode = NSS_SEED;
stringPtr = (CK_KEY_DERIVATION_STRING_DATA *)
pMechanism->pParameter;
@@ -7172,6 +7506,10 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession,
len = stringPtr->ulLen;
iv = NULL;
} else {
+ if (BAD_PARAM_CAST(pMechanism, sizeof(CK_AES_CBC_ENCRYPT_DATA_PARAMS))) {
+ crv = CKR_MECHANISM_PARAM_INVALID;
+ break;
+ }
mode = NSS_SEED_CBC;
aesEncryptPtr = (CK_AES_CBC_ENCRYPT_DATA_PARAMS *)
pMechanism->pParameter;
@@ -7263,6 +7601,10 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession,
if (crv != CKR_OK)
break;
+ if (BAD_PARAM_CAST(pMechanism, sizeof(CK_KEY_DERIVATION_STRING_DATA))) {
+ crv = CKR_MECHANISM_PARAM_INVALID;
+ break;
+ }
stringPtr = (CK_KEY_DERIVATION_STRING_DATA *)pMechanism->pParameter;
tmpKeySize = att->attrib.ulValueLen + stringPtr->ulLen;
if (keySize == 0)
@@ -7289,6 +7631,10 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession,
if (crv != CKR_OK)
break;
+ if (BAD_PARAM_CAST(pMechanism, sizeof(CK_KEY_DERIVATION_STRING_DATA))) {
+ crv = CKR_MECHANISM_PARAM_INVALID;
+ break;
+ }
stringPtr = (CK_KEY_DERIVATION_STRING_DATA *)pMechanism->pParameter;
tmpKeySize = att->attrib.ulValueLen + stringPtr->ulLen;
if (keySize == 0)
@@ -7315,6 +7661,10 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession,
if (crv != CKR_OK)
break;
+ if (BAD_PARAM_CAST(pMechanism, sizeof(CK_KEY_DERIVATION_STRING_DATA))) {
+ crv = CKR_MECHANISM_PARAM_INVALID;
+ break;
+ }
stringPtr = (CK_KEY_DERIVATION_STRING_DATA *)pMechanism->pParameter;
tmpKeySize = PR_MIN(att->attrib.ulValueLen, stringPtr->ulLen);
if (keySize == 0)
@@ -7339,6 +7689,10 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession,
break;
case CKM_EXTRACT_KEY_FROM_KEY: {
+ if (BAD_PARAM_CAST(pMechanism, sizeof(CK_EXTRACT_PARAMS))) {
+ crv = CKR_MECHANISM_PARAM_INVALID;
+ break;
+ }
/* the following assumes 8 bits per byte */
CK_ULONG extract = *(CK_EXTRACT_PARAMS *)pMechanism->pParameter;
CK_ULONG shift = extract & 0x7; /* extract mod 8 the fast way */
@@ -7479,14 +7833,14 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession,
case CKM_DH_PKCS_DERIVE: {
SECItem derived, dhPublic;
- SECItem dhPrime, dhValue;
+ SECItem dhPrime, dhSubPrime, dhValue;
/* sourceKey - values for the local existing low key */
/* get prime and value attributes */
crv = sftk_Attribute2SecItem(NULL, &dhPrime, sourceKey, CKA_PRIME);
- if (crv != SECSuccess)
+ if (crv != CKR_OK)
break;
crv = sftk_Attribute2SecItem(NULL, &dhValue, sourceKey, CKA_VALUE);
- if (crv != SECSuccess) {
+ if (crv != CKR_OK) {
PORT_Free(dhPrime.data);
break;
}
@@ -7494,6 +7848,20 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession,
dhPublic.data = pMechanism->pParameter;
dhPublic.len = pMechanism->ulParameterLen;
+ /* If the caller bothered to provide Q, use Q to validate
+ * the public key. */
+ crv = sftk_Attribute2SecItem(NULL, &dhSubPrime, sourceKey, CKA_SUBPRIME);
+ if (crv == CKR_OK) {
+ rv = KEA_Verify(&dhPublic, &dhPrime, &dhSubPrime);
+ PORT_Free(dhSubPrime.data);
+ if (rv != SECSuccess) {
+ crv = CKR_ARGUMENTS_BAD;
+ PORT_Free(dhPrime.data);
+ PORT_Free(dhValue.data);
+ break;
+ }
+ }
+
/* calculate private value - oct */
rv = DH_Derive(&dhPublic, &dhPrime, &dhValue, &derived, keySize);
@@ -7503,6 +7871,7 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession,
if (rv == SECSuccess) {
sftk_forceAttribute(key, CKA_VALUE, derived.data, derived.len);
PORT_ZFree(derived.data, derived.len);
+ crv = CKR_OK;
} else
crv = CKR_HOST_MEMORY;
@@ -7668,7 +8037,7 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession,
const SECHashObject *rawHash;
unsigned hashLen;
CK_BYTE hashbuf[HASH_LENGTH_MAX];
- CK_BYTE *prk; /* psuedo-random key */
+ CK_BYTE *prk; /* psuedo-random key */
CK_ULONG prkLen;
CK_BYTE *okm; /* output keying material */
unsigned allocated_space = 0; /* If we need more work space, track it */
diff --git a/security/nss/lib/softoken/pkcs11i.h b/security/nss/lib/softoken/pkcs11i.h
index 1ba0bdb82..51127a32a 100644
--- a/security/nss/lib/softoken/pkcs11i.h
+++ b/security/nss/lib/softoken/pkcs11i.h
@@ -17,6 +17,9 @@
#include "chacha20poly1305.h"
#include "hasht.h"
+#include "alghmac.h"
+#include "cmac.h"
+
/*
* Configuration Defines
*
@@ -106,6 +109,7 @@ typedef struct SFTKOAEPEncryptInfoStr SFTKOAEPEncryptInfo;
typedef struct SFTKOAEPDecryptInfoStr SFTKOAEPDecryptInfo;
typedef struct SFTKSSLMACInfoStr SFTKSSLMACInfo;
typedef struct SFTKChaCha20Poly1305InfoStr SFTKChaCha20Poly1305Info;
+typedef struct SFTKChaCha20CtrInfoStr SFTKChaCha20CtrInfo;
typedef struct SFTKItemTemplateStr SFTKItemTemplate;
/* define function pointer typdefs for pointer tables */
@@ -253,12 +257,15 @@ struct SFTKSessionContextStr {
PRBool multi; /* is multipart */
PRBool rsa; /* is rsa */
PRBool doPad; /* use PKCS padding for block ciphers */
+ PRBool isXCBC; /* xcbc, use special handling in final */
unsigned int blockSize; /* blocksize for padding */
unsigned int padDataLength; /* length of the valid data in padbuf */
/** latest incomplete block of data for block cipher */
unsigned char padBuf[SFTK_MAX_BLOCK_SIZE];
/** result of MAC'ing of latest full block of data with block cipher */
unsigned char macBuf[SFTK_MAX_BLOCK_SIZE];
+ unsigned char k2[SFTK_MAX_BLOCK_SIZE];
+ unsigned char k3[SFTK_MAX_BLOCK_SIZE];
CK_ULONG macSize; /* size of a general block cipher mac*/
void *cipherInfo;
void *hashInfo;
@@ -408,6 +415,14 @@ struct SFTKChaCha20Poly1305InfoStr {
unsigned int adLen;
};
+/* SFTKChaCha20BlockInfoStr the key, nonce and counter for a
+ * ChaCha20 block operation. */
+struct SFTKChaCha20CtrInfoStr {
+ PRUint8 key[32];
+ PRUint8 nonce[12];
+ PRUint32 counter;
+};
+
/*
* Template based on SECItems, suitable for passing as arrays
*/
@@ -446,7 +461,7 @@ struct SFTKItemTemplateStr {
#define SFTK_TOKEN_KRL_HANDLE (SFTK_TOKEN_MAGIC | SFTK_TOKEN_TYPE_CRL | 1)
/* how big (in bytes) a password/pin we can deal with */
-#define SFTK_MAX_PIN 255
+#define SFTK_MAX_PIN 500
/* minimum password/pin length (in Unicode characters) in FIPS mode */
#define FIPS_MIN_PIN 7
@@ -583,6 +598,73 @@ typedef struct sftk_parametersStr {
#define CERT_DB_FMT "%scert%s.db"
#define KEY_DB_FMT "%skey%s.db"
+struct sftk_MACConstantTimeCtxStr {
+ const SECHashObject *hash;
+ unsigned char mac[64];
+ unsigned char secret[64];
+ unsigned int headerLength;
+ unsigned int secretLength;
+ unsigned int totalLength;
+ unsigned char header[75];
+};
+typedef struct sftk_MACConstantTimeCtxStr sftk_MACConstantTimeCtx;
+
+struct sftk_MACCtxStr {
+ /* This is a common MAC context that supports both HMAC and CMAC
+ * operations. This also presents a unified set of semantics:
+ *
+ * - Everything except Destroy returns a CK_RV, indicating success
+ * or failure. (This handles the difference between HMAC's and CMAC's
+ * interfaces, since the underlying AES _might_ fail with CMAC).
+ *
+ * - The underlying MAC is started on Init(...), so Update(...) can
+ * called right away. (This handles the difference between HMAC and
+ * CMAC in their *_Init(...) functions).
+ *
+ * - Calling semantics:
+ *
+ * - One of sftk_MAC_{Create,Init,InitRaw}(...) to set up the MAC
+ * context, checking the return code.
+ * - sftk_MAC_Update(...) as many times as necessary to process
+ * input data, checking the return code.
+ * - sftk_MAC_Finish(...) to get the output of the MAC; result_len
+ * may be NULL if the caller knows the expected output length,
+ * checking the return code. If result_len is NULL, this will
+ * PR_ASSERT(...) that the actual returned length was equal to
+ * max_result_len.
+ *
+ * Note: unlike HMAC_Finish(...), this allows the caller to specify
+ * a return value less than return length, to align with
+ * CMAC_Finish(...)'s semantics. This will force an additional
+ * stack allocation of size SFTK_MAX_MAC_LENGTH.
+ * - sftk_MAC_Reset(...) if the caller wishes to compute a new MAC
+ * with the same key, checking the return code.
+ * - sftk_MAC_Destroy(...) when the caller frees its associated
+ * memory, passing PR_TRUE if sftk_MAC_Create(...) was called,
+ * and PR_FALSE otherwise.
+ */
+
+ CK_MECHANISM_TYPE mech;
+ unsigned int mac_size;
+
+ union {
+ HMACContext *hmac;
+ CMACContext *cmac;
+
+ /* Functions to update when adding a new MAC or a new hash:
+ *
+ * - sftk_MAC_Init
+ * - sftk_MAC_Update
+ * - sftk_MAC_Finish
+ * - sftk_MAC_Reset
+ */
+ void *raw;
+ } mac;
+
+ void (*destroy_func)(void *ctx, PRBool free_it);
+};
+typedef struct sftk_MACCtxStr sftk_MACCtx;
+
SEC_BEGIN_PROTOS
/* shared functions between pkcs11.c and fipstokn.c */
@@ -604,6 +686,7 @@ extern CK_RV SFTK_ShutdownSlot(SFTKSlot *slot);
extern CK_RV sftk_CloseAllSessions(SFTKSlot *slot, PRBool logout);
/* internal utility functions used by pkcs11.c */
+extern CK_RV sftk_MapCryptError(int error);
extern SFTKAttribute *sftk_FindAttribute(SFTKObject *object,
CK_ATTRIBUTE_TYPE type);
extern void sftk_FreeAttribute(SFTKAttribute *attribute);
@@ -682,10 +765,36 @@ extern NSSLOWKEYPublicKey *sftk_GetPubKey(SFTKObject *object,
CK_KEY_TYPE key_type, CK_RV *crvp);
extern NSSLOWKEYPrivateKey *sftk_GetPrivKey(SFTKObject *object,
CK_KEY_TYPE key_type, CK_RV *crvp);
+extern CK_RV sftk_PutPubKey(SFTKObject *publicKey, SFTKObject *privKey, CK_KEY_TYPE keyType,
+ NSSLOWKEYPublicKey *pubKey);
extern void sftk_FormatDESKey(unsigned char *key, int length);
extern PRBool sftk_CheckDESKey(unsigned char *key);
extern PRBool sftk_IsWeakKey(unsigned char *key, CK_KEY_TYPE key_type);
+/* ike and xcbc helpers */
+extern CK_RV sftk_ike_prf(CK_SESSION_HANDLE hSession,
+ const SFTKAttribute *inKey,
+ const CK_NSS_IKE_PRF_DERIVE_PARAMS *params, SFTKObject *outKey);
+extern CK_RV sftk_ike1_prf(CK_SESSION_HANDLE hSession,
+ const SFTKAttribute *inKey,
+ const CK_NSS_IKE1_PRF_DERIVE_PARAMS *params, SFTKObject *outKey,
+ unsigned int keySize);
+extern CK_RV sftk_ike1_appendix_b_prf(CK_SESSION_HANDLE hSession,
+ const SFTKAttribute *inKey,
+ const CK_MECHANISM_TYPE *params, SFTKObject *outKey,
+ unsigned int keySize);
+extern CK_RV sftk_ike_prf_plus(CK_SESSION_HANDLE hSession,
+ const SFTKAttribute *inKey,
+ const CK_NSS_IKE_PRF_PLUS_DERIVE_PARAMS *params, SFTKObject *outKey,
+ unsigned int keySize);
+extern CK_RV sftk_aes_xcbc_new_keys(CK_SESSION_HANDLE hSession,
+ CK_OBJECT_HANDLE hKey, CK_OBJECT_HANDLE_PTR phKey,
+ unsigned char *k2, unsigned char *k3);
+extern CK_RV sftk_xcbc_mac_pad(unsigned char *padBuf, unsigned int bufLen,
+ int blockSize, const unsigned char *k2,
+ const unsigned char *k3);
+extern SECStatus sftk_fips_IKE_PowerUpSelfTests(void);
+
/* mechanism allows this operation */
extern CK_RV sftk_MechAllowsOperation(CK_MECHANISM_TYPE type, CK_ATTRIBUTE_TYPE op);
@@ -727,17 +836,6 @@ extern CK_RV jpake_Final(HASH_HashType hashType,
SFTKObject *sourceKey, SFTKObject *key);
/* Constant time MAC functions (hmacct.c) */
-
-struct sftk_MACConstantTimeCtxStr {
- const SECHashObject *hash;
- unsigned char mac[64];
- unsigned char secret[64];
- unsigned int headerLength;
- unsigned int secretLength;
- unsigned int totalLength;
- unsigned char header[75];
-};
-typedef struct sftk_MACConstantTimeCtxStr sftk_MACConstantTimeCtx;
sftk_MACConstantTimeCtx *sftk_HMACConstantTime_New(
CK_MECHANISM_PTR mech, SFTKObject *key);
sftk_MACConstantTimeCtx *sftk_SSLv3MACConstantTime_New(
@@ -759,6 +857,16 @@ sftk_TLSPRFInit(SFTKSessionContext *context,
HASH_HashType hash_alg,
unsigned int out_len);
+/* PKCS#11 MAC implementation. See sftk_MACCtxStr declaration above for
+ * calling semantics for these functions. */
+CK_RV sftk_MAC_Create(CK_MECHANISM_TYPE mech, SFTKObject *key, sftk_MACCtx **ret_ctx);
+CK_RV sftk_MAC_Init(sftk_MACCtx *ctx, CK_MECHANISM_TYPE mech, SFTKObject *key);
+CK_RV sftk_MAC_InitRaw(sftk_MACCtx *ctx, CK_MECHANISM_TYPE mech, const unsigned char *key, unsigned int key_len, PRBool isFIPS);
+CK_RV sftk_MAC_Update(sftk_MACCtx *ctx, CK_BYTE_PTR data, unsigned int data_len);
+CK_RV sftk_MAC_Finish(sftk_MACCtx *ctx, CK_BYTE_PTR result, unsigned int *result_len, unsigned int max_result_len);
+CK_RV sftk_MAC_Reset(sftk_MACCtx *ctx);
+void sftk_MAC_Destroy(sftk_MACCtx *ctx, PRBool free_it);
+
SEC_END_PROTOS
#endif /* _PKCS11I_H_ */
diff --git a/security/nss/lib/softoken/pkcs11u.c b/security/nss/lib/softoken/pkcs11u.c
index 8cb5d2e70..1f66e6f61 100644
--- a/security/nss/lib/softoken/pkcs11u.c
+++ b/security/nss/lib/softoken/pkcs11u.c
@@ -15,6 +15,47 @@
#include "softoken.h"
/*
+ * ******************** Error mapping *******************************
+ */
+/*
+ * map all the SEC_ERROR_xxx error codes that may be returned by freebl
+ * functions to CKR_xxx. return CKR_DEVICE_ERROR by default for backward
+ * compatibility.
+ */
+CK_RV
+sftk_MapCryptError(int error)
+{
+ switch (error) {
+ case SEC_ERROR_INVALID_ARGS:
+ case SEC_ERROR_BAD_DATA: /* MP_RANGE gets mapped to this */
+ return CKR_ARGUMENTS_BAD;
+ case SEC_ERROR_INPUT_LEN:
+ return CKR_DATA_LEN_RANGE;
+ case SEC_ERROR_OUTPUT_LEN:
+ return CKR_BUFFER_TOO_SMALL;
+ case SEC_ERROR_LIBRARY_FAILURE:
+ return CKR_GENERAL_ERROR;
+ case SEC_ERROR_NO_MEMORY:
+ return CKR_HOST_MEMORY;
+ case SEC_ERROR_BAD_SIGNATURE:
+ return CKR_SIGNATURE_INVALID;
+ case SEC_ERROR_INVALID_KEY:
+ return CKR_KEY_SIZE_RANGE;
+ case SEC_ERROR_BAD_KEY: /* an EC public key that fails validation */
+ return CKR_KEY_SIZE_RANGE; /* the closest error code */
+ case SEC_ERROR_UNSUPPORTED_EC_POINT_FORM:
+ return CKR_TEMPLATE_INCONSISTENT;
+ case SEC_ERROR_UNSUPPORTED_KEYALG:
+ return CKR_MECHANISM_INVALID;
+ case SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE:
+ return CKR_DOMAIN_PARAMS_INVALID;
+ /* key pair generation failed after max number of attempts */
+ case SEC_ERROR_NEED_RANDOM:
+ return CKR_FUNCTION_FAILED;
+ }
+ return CKR_DEVICE_ERROR;
+}
+/*
* ******************** Attribute Utilities *******************************
*/
@@ -100,7 +141,7 @@ sftk_DestroyAttribute(SFTKAttribute *attribute)
void
sftk_FreeAttribute(SFTKAttribute *attribute)
{
- if (attribute->freeAttr) {
+ if (attribute && attribute->freeAttr) {
sftk_DestroyAttribute(attribute);
return;
}
diff --git a/security/nss/lib/softoken/sdb.c b/security/nss/lib/softoken/sdb.c
index fb897d68c..c84476100 100644
--- a/security/nss/lib/softoken/sdb.c
+++ b/security/nss/lib/softoken/sdb.c
@@ -159,7 +159,7 @@ static const CK_ATTRIBUTE_TYPE known_attributes[] = {
CKA_TRUST_IPSEC_TUNNEL, CKA_TRUST_IPSEC_USER, CKA_TRUST_TIME_STAMPING,
CKA_TRUST_STEP_UP_APPROVED, CKA_CERT_SHA1_HASH, CKA_CERT_MD5_HASH,
CKA_NETSCAPE_DB, CKA_NETSCAPE_TRUST, CKA_NSS_OVERRIDE_EXTENSIONS,
- CKA_PUBLIC_KEY_INFO
+ CKA_PUBLIC_KEY_INFO, CKA_NSS_SERVER_DISTRUST_AFTER, CKA_NSS_EMAIL_DISTRUST_AFTER
};
static int known_attributes_size = sizeof(known_attributes) /
@@ -858,7 +858,6 @@ sdb_FindObjectsFinal(SDB *sdb, SDBFind *sdbFind)
return sdb_mapSQLError(sdb_p->type, sqlerr);
}
-static const char GET_ATTRIBUTE_CMD[] = "SELECT ALL %s FROM %s WHERE id=$ID;";
CK_RV
sdb_GetAttributeValueNoLock(SDB *sdb, CK_OBJECT_HANDLE object_id,
CK_ATTRIBUTE *template, CK_ULONG count)
@@ -866,8 +865,6 @@ sdb_GetAttributeValueNoLock(SDB *sdb, CK_OBJECT_HANDLE object_id,
SDBPrivate *sdb_p = sdb->private;
sqlite3 *sqlDB = NULL;
sqlite3_stmt *stmt = NULL;
- char *getStr = NULL;
- char *newStr = NULL;
const char *table = NULL;
int sqlerr = SQLITE_OK;
CK_RV error = CKR_OK;
@@ -875,59 +872,79 @@ sdb_GetAttributeValueNoLock(SDB *sdb, CK_OBJECT_HANDLE object_id,
int retry = 0;
unsigned int i;
+ if (count == 0) {
+ error = CKR_OBJECT_HANDLE_INVALID;
+ goto loser;
+ }
+
/* open a new db if necessary */
error = sdb_openDBLocal(sdb_p, &sqlDB, &table);
if (error != CKR_OK) {
goto loser;
}
+ char *columns = NULL;
for (i = 0; i < count; i++) {
- getStr = sqlite3_mprintf("a%x", template[i].type);
-
- if (getStr == NULL) {
- error = CKR_HOST_MEMORY;
- goto loser;
+ char *newColumns;
+ if (columns) {
+ newColumns = sqlite3_mprintf("%s, a%x", columns, template[i].type);
+ sqlite3_free(columns);
+ columns = NULL;
+ } else {
+ newColumns = sqlite3_mprintf("a%x", template[i].type);
}
-
- newStr = sqlite3_mprintf(GET_ATTRIBUTE_CMD, getStr, table);
- sqlite3_free(getStr);
- getStr = NULL;
- if (newStr == NULL) {
+ if (!newColumns) {
error = CKR_HOST_MEMORY;
goto loser;
}
+ columns = newColumns;
+ }
- sqlerr = sqlite3_prepare_v2(sqlDB, newStr, -1, &stmt, NULL);
- sqlite3_free(newStr);
- newStr = NULL;
- if (sqlerr == SQLITE_ERROR) {
- template[i].ulValueLen = -1;
- error = CKR_ATTRIBUTE_TYPE_INVALID;
- continue;
- } else if (sqlerr != SQLITE_OK) {
- goto loser;
- }
+ PORT_Assert(columns);
- sqlerr = sqlite3_bind_int(stmt, 1, object_id);
- if (sqlerr != SQLITE_OK) {
- goto loser;
- }
+ char *statement = sqlite3_mprintf("SELECT DISTINCT %s FROM %s where id=$ID LIMIT 1;",
+ columns, table);
+ sqlite3_free(columns);
+ columns = NULL;
+ if (!statement) {
+ error = CKR_HOST_MEMORY;
+ goto loser;
+ }
- do {
- sqlerr = sqlite3_step(stmt);
- if (sqlerr == SQLITE_BUSY) {
- PR_Sleep(SDB_BUSY_RETRY_TIME);
- }
- if (sqlerr == SQLITE_ROW) {
+ sqlerr = sqlite3_prepare_v2(sqlDB, statement, -1, &stmt, NULL);
+ sqlite3_free(statement);
+ statement = NULL;
+ if (sqlerr != SQLITE_OK) {
+ goto loser;
+ }
+
+ // NB: indices in sqlite3_bind_int are 1-indexed
+ sqlerr = sqlite3_bind_int(stmt, 1, object_id);
+ if (sqlerr != SQLITE_OK) {
+ goto loser;
+ }
+
+ do {
+ sqlerr = sqlite3_step(stmt);
+ if (sqlerr == SQLITE_BUSY) {
+ PR_Sleep(SDB_BUSY_RETRY_TIME);
+ }
+ if (sqlerr == SQLITE_ROW) {
+ PORT_Assert(!found);
+ for (i = 0; i < count; i++) {
unsigned int blobSize;
const char *blobData;
- blobSize = sqlite3_column_bytes(stmt, 0);
- blobData = sqlite3_column_blob(stmt, 0);
+ // NB: indices in sqlite_column_{bytes,blob} are 0-indexed
+ blobSize = sqlite3_column_bytes(stmt, i);
+ blobData = sqlite3_column_blob(stmt, i);
if (blobData == NULL) {
+ /* PKCS 11 requires that get attributes process all the
+ * attributes in the template, marking the attributes with
+ * issues with -1. Mark the error but continue */
template[i].ulValueLen = -1;
error = CKR_ATTRIBUTE_TYPE_INVALID;
- break;
+ continue;
}
/* If the blob equals our explicit NULL value, then the
* attribute is a NULL. */
@@ -938,20 +955,21 @@ sdb_GetAttributeValueNoLock(SDB *sdb, CK_OBJECT_HANDLE object_id,
}
if (template[i].pValue) {
if (template[i].ulValueLen < blobSize) {
+ /* like CKR_ATTRIBUTE_TYPE_INVALID, continue processing */
template[i].ulValueLen = -1;
error = CKR_BUFFER_TOO_SMALL;
- break;
+ continue;
}
PORT_Memcpy(template[i].pValue, blobData, blobSize);
}
template[i].ulValueLen = blobSize;
- found = 1;
}
- } while (!sdb_done(sqlerr, &retry));
- sqlite3_reset(stmt);
- sqlite3_finalize(stmt);
- stmt = NULL;
- }
+ found = 1;
+ }
+ } while (!sdb_done(sqlerr, &retry));
+ sqlite3_reset(stmt);
+ sqlite3_finalize(stmt);
+ stmt = NULL;
loser:
/* fix up the error if necessary */
diff --git a/security/nss/lib/softoken/sftkdb.c b/security/nss/lib/softoken/sftkdb.c
index 21796bbbb..61cb2ce8b 100644
--- a/security/nss/lib/softoken/sftkdb.c
+++ b/security/nss/lib/softoken/sftkdb.c
@@ -2451,7 +2451,7 @@ sftk_getDBForTokenObject(SFTKSlot *slot, CK_OBJECT_HANDLE objectID)
* initialize a new database handle
*/
static SFTKDBHandle *
-sftk_NewDBHandle(SDB *sdb, int type)
+sftk_NewDBHandle(SDB *sdb, int type, PRBool legacy)
{
SFTKDBHandle *handle = PORT_New(SFTKDBHandle);
handle->ref = 1;
@@ -2463,6 +2463,7 @@ sftk_NewDBHandle(SDB *sdb, int type)
handle->updatePasswordKey = NULL;
handle->updateID = NULL;
handle->type = type;
+ handle->usesLegacyStorage = legacy;
handle->passwordKey.data = NULL;
handle->passwordKey.len = 0;
handle->passwordLock = NULL;
@@ -2622,6 +2623,7 @@ sftk_DBInit(const char *configdir, const char *certPrefix,
PRBool newInit = PR_FALSE;
PRBool needUpdate = PR_FALSE;
char *nconfdir = NULL;
+ PRBool legacy = PR_TRUE;
if (!readOnly) {
flags = SDB_CREATE;
@@ -2654,12 +2656,14 @@ sftk_DBInit(const char *configdir, const char *certPrefix,
case NSS_DB_TYPE_EXTERN: /* SHOULD open a loadable db */
crv = s_open(confdir, certPrefix, keyPrefix, 9, 4, flags,
noCertDB ? NULL : &certSDB, noKeyDB ? NULL : &keySDB, &newInit);
+ legacy = PR_FALSE;
/*
* if we failed to open the DB's read only, use the old ones if
* the exists.
*/
if (crv != CKR_OK) {
+ legacy = PR_TRUE;
if ((flags & SDB_RDONLY) == SDB_RDONLY) {
nconfdir = sftk_legacyPathFromSDBPath(confdir);
}
@@ -2713,12 +2717,12 @@ sftk_DBInit(const char *configdir, const char *certPrefix,
goto done;
}
if (!noCertDB) {
- *certDB = sftk_NewDBHandle(certSDB, SFTK_CERTDB_TYPE);
+ *certDB = sftk_NewDBHandle(certSDB, SFTK_CERTDB_TYPE, legacy);
} else {
*certDB = NULL;
}
if (!noKeyDB) {
- *keyDB = sftk_NewDBHandle(keySDB, SFTK_KEYDB_TYPE);
+ *keyDB = sftk_NewDBHandle(keySDB, SFTK_KEYDB_TYPE, legacy);
} else {
*keyDB = NULL;
}
diff --git a/security/nss/lib/softoken/sftkdb.h b/security/nss/lib/softoken/sftkdb.h
index e30f3a237..bce39dc92 100644
--- a/security/nss/lib/softoken/sftkdb.h
+++ b/security/nss/lib/softoken/sftkdb.h
@@ -70,3 +70,5 @@ SFTKDBHandle *sftk_getKeyDB(SFTKSlot *slot);
SFTKDBHandle *sftk_getDBForTokenObject(SFTKSlot *slot,
CK_OBJECT_HANDLE objectID);
void sftk_freeDB(SFTKDBHandle *certHandle);
+
+PRBool sftk_isLegacyIterationCountAllowed(void);
diff --git a/security/nss/lib/softoken/sftkdbti.h b/security/nss/lib/softoken/sftkdbti.h
index 22655de56..a3a19414e 100644
--- a/security/nss/lib/softoken/sftkdbti.h
+++ b/security/nss/lib/softoken/sftkdbti.h
@@ -23,6 +23,7 @@ struct SFTKDBHandleStr {
SDB *update;
char *updateID;
PRBool updateDBIsInit;
+ PRBool usesLegacyStorage;
};
#define SFTK_KEYDB_TYPE 0x40000000
diff --git a/security/nss/lib/softoken/sftkhmac.c b/security/nss/lib/softoken/sftkhmac.c
index be6344c70..617e6fd4e 100644
--- a/security/nss/lib/softoken/sftkhmac.c
+++ b/security/nss/lib/softoken/sftkhmac.c
@@ -9,12 +9,14 @@
#include "softoken.h"
#include "hmacct.h"
-/* MACMechanismToHash converts a PKCS#11 MAC mechanism into a freebl hash
+/* HMACMechanismToHash converts a PKCS#11 MAC mechanism into a freebl hash
* type. */
static HASH_HashType
-MACMechanismToHash(CK_MECHANISM_TYPE mech)
+HMACMechanismToHash(CK_MECHANISM_TYPE mech)
{
switch (mech) {
+ case CKM_MD2_HMAC:
+ return HASH_AlgMD2;
case CKM_MD5_HMAC:
case CKM_SSL3_MD5_MAC:
return HASH_AlgMD5;
@@ -48,7 +50,7 @@ SetupMAC(CK_MECHANISM_PTR mech, SFTKObject *key)
return NULL;
}
- alg = MACMechanismToHash(params->macAlg);
+ alg = HMACMechanismToHash(params->macAlg);
if (alg == HASH_AlgNULL) {
return NULL;
}
@@ -188,3 +190,284 @@ sftk_MACConstantTime_DestroyContext(void *pctx, PRBool free)
{
PORT_Free(pctx);
}
+
+CK_RV
+sftk_MAC_Create(CK_MECHANISM_TYPE mech, SFTKObject *key, sftk_MACCtx **ret_ctx)
+{
+ CK_RV ret;
+
+ if (ret_ctx == NULL || key == NULL) {
+ return CKR_HOST_MEMORY;
+ }
+
+ *ret_ctx = PORT_New(sftk_MACCtx);
+ if (*ret_ctx == NULL) {
+ return CKR_HOST_MEMORY;
+ }
+
+ ret = sftk_MAC_Init(*ret_ctx, mech, key);
+ if (ret != CKR_OK) {
+ sftk_MAC_Destroy(*ret_ctx, PR_TRUE);
+ }
+
+ return ret;
+}
+
+CK_RV
+sftk_MAC_Init(sftk_MACCtx *ctx, CK_MECHANISM_TYPE mech, SFTKObject *key)
+{
+ SFTKAttribute *keyval = NULL;
+ PRBool isFIPS = (key->slot->slotID == FIPS_SLOT_ID);
+ CK_RV ret = CKR_OK;
+
+ /* Find the actual value of the key. */
+ keyval = sftk_FindAttribute(key, CKA_VALUE);
+ if (keyval == NULL) {
+ ret = CKR_KEY_SIZE_RANGE;
+ goto done;
+ }
+
+ ret = sftk_MAC_InitRaw(ctx, mech,
+ (const unsigned char *)keyval->attrib.pValue,
+ keyval->attrib.ulValueLen, isFIPS);
+
+done:
+ sftk_FreeAttribute(keyval);
+ return ret;
+}
+
+CK_RV
+sftk_MAC_InitRaw(sftk_MACCtx *ctx, CK_MECHANISM_TYPE mech, const unsigned char *key, unsigned int key_len, PRBool isFIPS)
+{
+ const SECHashObject *hashObj = NULL;
+ CK_RV ret = CKR_OK;
+
+ if (ctx == NULL) {
+ return CKR_HOST_MEMORY;
+ }
+
+ /* Clear the context before use. */
+ PORT_Memset(ctx, 0, sizeof(*ctx));
+
+ /* Save the mech. */
+ ctx->mech = mech;
+
+ /* Initialize the correct MAC context. */
+ switch (mech) {
+ case CKM_MD2_HMAC:
+ case CKM_MD5_HMAC:
+ case CKM_SHA_1_HMAC:
+ case CKM_SHA224_HMAC:
+ case CKM_SHA256_HMAC:
+ case CKM_SHA384_HMAC:
+ case CKM_SHA512_HMAC:
+ hashObj = HASH_GetRawHashObject(HMACMechanismToHash(mech));
+
+ /* Because we condition above only on hashes we know to be valid,
+ * hashObj should never be NULL. This assert is only useful when
+ * adding a new hash function (for which only partial support has
+ * been added); thus there is no need to turn it into an if and
+ * avoid the NULL dereference on the following line. */
+ PR_ASSERT(hashObj != NULL);
+ ctx->mac_size = hashObj->length;
+
+ goto hmac;
+ case CKM_AES_CMAC:
+ ctx->mac.cmac = CMAC_Create(CMAC_AES, key, key_len);
+ ctx->destroy_func = (void (*)(void *, PRBool))(&CMAC_Destroy);
+
+ /* Copy the behavior of sftk_doCMACInit here. */
+ if (ctx->mac.cmac == NULL) {
+ if (PORT_GetError() == SEC_ERROR_INVALID_ARGS) {
+ ret = CKR_KEY_SIZE_RANGE;
+ goto done;
+ }
+
+ ret = CKR_HOST_MEMORY;
+ goto done;
+ }
+
+ ctx->mac_size = AES_BLOCK_SIZE;
+
+ goto done;
+ default:
+ ret = CKR_MECHANISM_PARAM_INVALID;
+ goto done;
+ }
+
+hmac:
+ ctx->mac.hmac = HMAC_Create(hashObj, key, key_len, isFIPS);
+ ctx->destroy_func = (void (*)(void *, PRBool))(&HMAC_Destroy);
+
+ /* Copy the behavior of sftk_doHMACInit here. */
+ if (ctx->mac.hmac == NULL) {
+ if (PORT_GetError() == SEC_ERROR_INVALID_ARGS) {
+ ret = CKR_KEY_SIZE_RANGE;
+ goto done;
+ }
+ ret = CKR_HOST_MEMORY;
+ goto done;
+ }
+
+ /* Semantics: HMAC and CMAC should behave the same. Begin HMAC now. */
+ HMAC_Begin(ctx->mac.hmac);
+
+done:
+ /* Handle a failure: ctx->mac.raw should be NULL, but make sure
+ * destroy_func isn't set. */
+ if (ret != CKR_OK) {
+ ctx->destroy_func = NULL;
+ }
+
+ return ret;
+}
+
+CK_RV
+sftk_MAC_Reset(sftk_MACCtx *ctx)
+{
+ /* Useful for resetting the state of MAC prior to calling update again
+ *
+ * This lets the caller keep a single MAC instance and re-use it as long
+ * as the key stays the same. */
+ switch (ctx->mech) {
+ case CKM_MD2_HMAC:
+ case CKM_MD5_HMAC:
+ case CKM_SHA_1_HMAC:
+ case CKM_SHA224_HMAC:
+ case CKM_SHA256_HMAC:
+ case CKM_SHA384_HMAC:
+ case CKM_SHA512_HMAC:
+ HMAC_Begin(ctx->mac.hmac);
+ break;
+ case CKM_AES_CMAC:
+ if (CMAC_Begin(ctx->mac.cmac) != SECSuccess) {
+ return CKR_FUNCTION_FAILED;
+ }
+ break;
+ default:
+ /* This shouldn't happen -- asserting indicates partial support
+ * for a new MAC type. */
+ PR_ASSERT(PR_FALSE);
+ return CKR_FUNCTION_FAILED;
+ }
+
+ return CKR_OK;
+}
+
+CK_RV
+sftk_MAC_Update(sftk_MACCtx *ctx, CK_BYTE_PTR data, unsigned int data_len)
+{
+ switch (ctx->mech) {
+ case CKM_MD2_HMAC:
+ case CKM_MD5_HMAC:
+ case CKM_SHA_1_HMAC:
+ case CKM_SHA224_HMAC:
+ case CKM_SHA256_HMAC:
+ case CKM_SHA384_HMAC:
+ case CKM_SHA512_HMAC:
+ /* HMAC doesn't indicate failure in the return code. */
+ HMAC_Update(ctx->mac.hmac, data, data_len);
+ break;
+ case CKM_AES_CMAC:
+ /* CMAC indicates failure in the return code, however this is
+ * unlikely to occur. */
+ if (CMAC_Update(ctx->mac.cmac, data, data_len) != SECSuccess) {
+ return CKR_FUNCTION_FAILED;
+ }
+ break;
+ default:
+ /* This shouldn't happen -- asserting indicates partial support
+ * for a new MAC type. */
+ PR_ASSERT(PR_FALSE);
+ return CKR_FUNCTION_FAILED;
+ }
+ return CKR_OK;
+}
+
+CK_RV
+sftk_MAC_Finish(sftk_MACCtx *ctx, CK_BYTE_PTR result, unsigned int *result_len, unsigned int max_result_len)
+{
+ unsigned int actual_result_len;
+
+ switch (ctx->mech) {
+ case CKM_MD2_HMAC:
+ case CKM_MD5_HMAC:
+ case CKM_SHA_1_HMAC:
+ case CKM_SHA224_HMAC:
+ case CKM_SHA256_HMAC:
+ case CKM_SHA384_HMAC:
+ case CKM_SHA512_HMAC:
+ /* HMAC doesn't indicate failure in the return code. Additionally,
+ * unlike CMAC, it doesn't support partial results. This means that we
+ * need to allocate a buffer if max_result_len < ctx->mac_size. */
+ if (max_result_len >= ctx->mac_size) {
+ /* Split this into two calls to avoid an unnecessary stack
+ * allocation and memcpy when possible. */
+ HMAC_Finish(ctx->mac.hmac, result, &actual_result_len, max_result_len);
+ } else {
+ uint8_t tmp_buffer[SFTK_MAX_MAC_LENGTH];
+
+ /* Assumption: buffer is large enough to hold this HMAC's
+ * output. */
+ PR_ASSERT(SFTK_MAX_MAC_LENGTH >= ctx->mac_size);
+
+ HMAC_Finish(ctx->mac.hmac, tmp_buffer, &actual_result_len, SFTK_MAX_MAC_LENGTH);
+
+ if (actual_result_len > max_result_len) {
+ /* This should always be true since:
+ *
+ * (SFTK_MAX_MAC_LENGTH >= ctx->mac_size =
+ * actual_result_len) > max_result_len,
+ *
+ * but guard this truncation just in case. */
+ actual_result_len = max_result_len;
+ }
+
+ PORT_Memcpy(result, tmp_buffer, actual_result_len);
+ }
+ break;
+ case CKM_AES_CMAC:
+ /* CMAC indicates failure in the return code, however this is
+ * unlikely to occur. */
+ if (CMAC_Finish(ctx->mac.cmac, result, &actual_result_len, max_result_len) != SECSuccess) {
+ return CKR_FUNCTION_FAILED;
+ }
+ break;
+ default:
+ /* This shouldn't happen -- asserting indicates partial support
+ * for a new MAC type. */
+ PR_ASSERT(PR_FALSE);
+ return CKR_FUNCTION_FAILED;
+ }
+
+ if (result_len) {
+ /* When result length is passed, inform the caller of its value. */
+ *result_len = actual_result_len;
+ } else if (max_result_len == ctx->mac_size) {
+ /* Validate that the amount requested was what was actually given; the
+ * caller assumes that what they passed was the output size of the
+ * underlying MAC and that they got all the bytes the asked for. */
+ PR_ASSERT(actual_result_len == max_result_len);
+ }
+
+ return CKR_OK;
+}
+
+void
+sftk_MAC_Destroy(sftk_MACCtx *ctx, PRBool free_it)
+{
+ if (ctx == NULL) {
+ return;
+ }
+
+ if (ctx->mac.raw != NULL && ctx->destroy_func != NULL) {
+ ctx->destroy_func(ctx->mac.raw, PR_TRUE);
+ }
+
+ /* Clean up the struct so we don't double free accidentally. */
+ PORT_Memset(ctx, 0, sizeof(sftk_MACCtx));
+
+ if (free_it == PR_TRUE) {
+ PORT_Free(ctx);
+ }
+}
diff --git a/security/nss/lib/softoken/sftkike.c b/security/nss/lib/softoken/sftkike.c
new file mode 100644
index 000000000..7d5370bd4
--- /dev/null
+++ b/security/nss/lib/softoken/sftkike.c
@@ -0,0 +1,1294 @@
+/* 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 "secport.h"
+#include "blapi.h"
+#include "pkcs11.h"
+#include "pkcs11i.h"
+#include "pkcs1sig.h"
+#include "lowkeyi.h"
+#include "secder.h"
+#include "secdig.h"
+#include "lowpbe.h" /* We do PBE below */
+#include "pkcs11t.h"
+#include "secoid.h"
+#include "alghmac.h"
+#include "softoken.h"
+#include "secasn1.h"
+#include "secerr.h"
+
+#include "prprf.h"
+#include "prenv.h"
+
+/*
+ * A common prfContext to handle both hmac and aes xcbc
+ * hash contexts have non-null hashObj and hmac, aes
+ * contexts have non-null aes */
+typedef struct prfContextStr {
+ HASH_HashType hashType;
+ const SECHashObject *hashObj;
+ HMACContext *hmac;
+ AESContext *aes;
+ unsigned int nextChar;
+ unsigned char padBuf[AES_BLOCK_SIZE];
+ unsigned char macBuf[AES_BLOCK_SIZE];
+ unsigned char k1[AES_BLOCK_SIZE];
+ unsigned char k2[AES_BLOCK_SIZE];
+ unsigned char k3[AES_BLOCK_SIZE];
+} prfContext;
+
+/* iv full of zeros used in several places in aes xcbc */
+static const unsigned char iv_zero[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+/*
+ * Generate AES XCBC keys from the AES MAC key.
+ * k1 is used in the actual mac.
+ * k2 and k3 are used in the final pad step.
+ */
+static CK_RV
+sftk_aes_xcbc_get_keys(const unsigned char *keyValue, unsigned int keyLen,
+ unsigned char *k1, unsigned char *k2, unsigned char *k3)
+{
+ SECStatus rv;
+ CK_RV crv;
+ unsigned int tmpLen;
+ AESContext *aes_context = NULL;
+ unsigned char newKey[AES_BLOCK_SIZE];
+
+ /* AES XCBC keys. k1, k2, and k3 are derived by encrypting
+ * k1data, k2data, and k3data with the mac key.
+ */
+ static const unsigned char k1data[] = {
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01
+ };
+ static const unsigned char k2data[] = {
+ 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+ 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02
+ };
+ static const unsigned char k3data[] = {
+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03
+ };
+
+ /* k1_0 = aes_ecb(0, k1data) */
+ static const unsigned char k1_0[] = {
+ 0xe1, 0x4d, 0x5d, 0x0e, 0xe2, 0x77, 0x15, 0xdf,
+ 0x08, 0xb4, 0x15, 0x2b, 0xa2, 0x3d, 0xa8, 0xe0
+
+ };
+ /* k2_0 = aes_ecb(0, k2data) */
+ static const unsigned char k2_0[] = {
+ 0x5e, 0xba, 0x73, 0xf8, 0x91, 0x42, 0xc5, 0x48,
+ 0x80, 0xf6, 0x85, 0x94, 0x37, 0x3c, 0x5c, 0x37
+ };
+ /* k3_0 = aes_ecb(0, k3data) */
+ static const unsigned char k3_0[] = {
+ 0x8d, 0x34, 0xef, 0xcb, 0x3b, 0xd5, 0x45, 0xca,
+ 0x06, 0x2a, 0xec, 0xdf, 0xef, 0x7c, 0x0b, 0xfa
+ };
+
+ /* first make sure out input key is the correct length
+ * rfc 4434. If key is shorter, pad with zeros to the
+ * the right. If key is longer newKey = aes_xcbc(0, key, keyLen).
+ */
+ if (keyLen < AES_BLOCK_SIZE) {
+ PORT_Memcpy(newKey, keyValue, keyLen);
+ PORT_Memset(&newKey[keyLen], 0, AES_BLOCK_SIZE - keyLen);
+ keyValue = newKey;
+ } else if (keyLen > AES_BLOCK_SIZE) {
+ /* calculate our new key = aes_xcbc(0, key, keyLen). Because the
+ * key above is fixed (0), we can precalculate k1, k2, and k3.
+ * if this code ever needs to be more generic (support any xcbc
+ * function rather than just aes, we would probably want to just
+ * recurse here using our prf functions. This would be safe because
+ * the recurse case would have keyLen == blocksize and thus skip
+ * this conditional.
+ */
+ aes_context = AES_CreateContext(k1_0, iv_zero, NSS_AES_CBC,
+ PR_TRUE, AES_BLOCK_SIZE, AES_BLOCK_SIZE);
+ /* we know the following loop will execute at least once */
+ while (keyLen > AES_BLOCK_SIZE) {
+ rv = AES_Encrypt(aes_context, newKey, &tmpLen, AES_BLOCK_SIZE,
+ keyValue, AES_BLOCK_SIZE);
+ if (rv != SECSuccess) {
+ goto fail;
+ }
+ keyValue += AES_BLOCK_SIZE;
+ keyLen -= AES_BLOCK_SIZE;
+ }
+ PORT_Memcpy(newKey, keyValue, keyLen);
+ sftk_xcbc_mac_pad(newKey, keyLen, AES_BLOCK_SIZE, k2_0, k3_0);
+ rv = AES_Encrypt(aes_context, newKey, &tmpLen, AES_BLOCK_SIZE,
+ newKey, AES_BLOCK_SIZE);
+ if (rv != SECSuccess) {
+ goto fail;
+ }
+ keyValue = newKey;
+ AES_DestroyContext(aes_context, PR_TRUE);
+ }
+ /* the length of the key in keyValue is known to be AES_BLOCK_SIZE,
+ * either because it was on input, or it was shorter and extended, or
+ * because it was mac'd down using aes_xcbc_prf.
+ */
+ aes_context = AES_CreateContext(keyValue, iv_zero,
+ NSS_AES, PR_TRUE, AES_BLOCK_SIZE, AES_BLOCK_SIZE);
+ if (aes_context == NULL) {
+ goto fail;
+ }
+ rv = AES_Encrypt(aes_context, k1, &tmpLen, AES_BLOCK_SIZE,
+ k1data, sizeof(k1data));
+ if (rv != SECSuccess) {
+ goto fail;
+ }
+ rv = AES_Encrypt(aes_context, k2, &tmpLen, AES_BLOCK_SIZE,
+ k2data, sizeof(k2data));
+ if (rv != SECSuccess) {
+ goto fail;
+ }
+ rv = AES_Encrypt(aes_context, k3, &tmpLen, AES_BLOCK_SIZE,
+ k3data, sizeof(k3data));
+ if (rv != SECSuccess) {
+ goto fail;
+ }
+ AES_DestroyContext(aes_context, PR_TRUE);
+ PORT_Memset(newKey, 0, AES_BLOCK_SIZE);
+ return CKR_OK;
+fail:
+ crv = sftk_MapCryptError(PORT_GetError());
+ if (aes_context) {
+ AES_DestroyContext(aes_context, PR_TRUE);
+ }
+ PORT_Memset(k1, 0, AES_BLOCK_SIZE);
+ PORT_Memset(k2, 0, AES_BLOCK_SIZE);
+ PORT_Memset(k3, 0, AES_BLOCK_SIZE);
+ PORT_Memset(newKey, 0, AES_BLOCK_SIZE);
+ return crv;
+}
+
+/* encode the final pad block of aes xcbc, padBuf is modified */
+CK_RV
+sftk_xcbc_mac_pad(unsigned char *padBuf, unsigned int bufLen, int blockSize,
+ const unsigned char *k2, const unsigned char *k3)
+{
+ int i;
+ if (bufLen == blockSize) {
+ for (i = 0; i < blockSize; i++) {
+ padBuf[i] ^= k2[i];
+ }
+ } else {
+ padBuf[bufLen++] = 0x80;
+ for (i = bufLen; i < blockSize; i++) {
+ padBuf[i] = 0x00;
+ }
+ for (i = 0; i < blockSize; i++) {
+ padBuf[i] ^= k3[i];
+ }
+ }
+ return CKR_OK;
+}
+
+/* Map the mechanism to the underlying hash. If the type is not a hash
+ * or HMAC, return HASH_AlgNULL. This can happen legitimately if
+ * we are doing AES XCBC */
+static HASH_HashType
+sftk_map_hmac_to_hash(CK_MECHANISM_TYPE type)
+{
+ switch (type) {
+ case CKM_SHA_1_HMAC:
+ case CKM_SHA_1:
+ return HASH_AlgSHA1;
+ case CKM_MD5_HMAC:
+ case CKM_MD5:
+ return HASH_AlgMD5;
+ case CKM_MD2_HMAC:
+ case CKM_MD2:
+ return HASH_AlgMD2;
+ case CKM_SHA224_HMAC:
+ case CKM_SHA224:
+ return HASH_AlgSHA224;
+ case CKM_SHA256_HMAC:
+ case CKM_SHA256:
+ return HASH_AlgSHA256;
+ case CKM_SHA384_HMAC:
+ case CKM_SHA384:
+ return HASH_AlgSHA384;
+ case CKM_SHA512_HMAC:
+ case CKM_SHA512:
+ return HASH_AlgSHA512;
+ }
+ return HASH_AlgNULL;
+}
+
+/*
+ * Generally setup the context based on the mechanism.
+ * If the mech is HMAC, context->hashObj should be set
+ * Otherwise it is assumed to be AES XCBC. prf_setup
+ * checks these assumptions and will return an error
+ * if they are not met. NOTE: this function does not allocate
+ * anything, so there is no requirement to free context after
+ * prf_setup like there is if you call prf_init.
+ */
+static CK_RV
+prf_setup(prfContext *context, CK_MECHANISM_TYPE mech)
+{
+ context->hashType = sftk_map_hmac_to_hash(mech);
+ context->hashObj = NULL;
+ context->hmac = NULL;
+ context->aes = NULL;
+ if (context->hashType != HASH_AlgNULL) {
+ context->hashObj = HASH_GetRawHashObject(context->hashType);
+ if (context->hashObj == NULL) {
+ return CKR_GENERAL_ERROR;
+ }
+ return CKR_OK;
+ } else if (mech == CKM_AES_XCBC_MAC) {
+ return CKR_OK;
+ }
+ return CKR_MECHANISM_PARAM_INVALID;
+}
+
+/* return the underlying prf length for this context. This will
+ * function once the context is setup */
+static CK_RV
+prf_length(prfContext *context)
+{
+ if (context->hashObj) {
+ return context->hashObj->length;
+ }
+ return AES_BLOCK_SIZE; /* AES */
+}
+
+/* set up the key for the prf. prf_update or prf_final should not be called if
+ * prf_init has not been called first. Once prf_init returns hmac and
+ * aes contexts should set and valid.
+ */
+static CK_RV
+prf_init(prfContext *context, const unsigned char *keyValue,
+ unsigned int keyLen)
+{
+ CK_RV crv;
+
+ context->hmac = NULL;
+ if (context->hashObj) {
+ context->hmac = HMAC_Create(context->hashObj,
+ keyValue, keyLen, PR_FALSE);
+ if (context->hmac == NULL) {
+ return sftk_MapCryptError(PORT_GetError());
+ }
+ HMAC_Begin(context->hmac);
+ } else {
+ crv = sftk_aes_xcbc_get_keys(keyValue, keyLen, context->k1,
+ context->k2, context->k3);
+ if (crv != CKR_OK)
+ return crv;
+ context->nextChar = 0;
+ context->aes = AES_CreateContext(context->k1, iv_zero, NSS_AES_CBC,
+ PR_TRUE, sizeof(context->k1), AES_BLOCK_SIZE);
+ if (context->aes == NULL) {
+ crv = sftk_MapCryptError(PORT_GetError());
+ PORT_Memset(context->k1, 0, sizeof(context->k1));
+ PORT_Memset(context->k2, 0, sizeof(context->k2));
+ PORT_Memset(context->k3, 0, sizeof(context->k2));
+ return crv;
+ }
+ }
+ return CKR_OK;
+}
+
+/*
+ * process input to the prf
+ */
+static CK_RV
+prf_update(prfContext *context, const unsigned char *buf, unsigned int len)
+{
+ unsigned int tmpLen;
+ SECStatus rv;
+
+ if (context->hmac) {
+ HMAC_Update(context->hmac, buf, len);
+ } else {
+ /* AES MAC XCBC*/
+ /* We must keep the last block back so that it can be processed in
+ * final. This is why we only check that nextChar + len > blocksize,
+ * rather than checking that nextChar + len >= blocksize */
+ while (context->nextChar + len > AES_BLOCK_SIZE) {
+ if (context->nextChar != 0) {
+ /* first handle fill in any partial blocks in the buffer */
+ unsigned int left = AES_BLOCK_SIZE - context->nextChar;
+ /* note: left can be zero */
+ PORT_Memcpy(context->padBuf + context->nextChar, buf, left);
+ /* NOTE: AES MAC XCBC xors the data with the previous block
+ * We don't do that step here because our AES_Encrypt mode
+ * is CBC, which does the xor automatically */
+ rv = AES_Encrypt(context->aes, context->macBuf, &tmpLen,
+ sizeof(context->macBuf), context->padBuf,
+ sizeof(context->padBuf));
+ if (rv != SECSuccess) {
+ return sftk_MapCryptError(PORT_GetError());
+ }
+ context->nextChar = 0;
+ len -= left;
+ buf += left;
+ } else {
+ /* optimization. if we have complete blocks to write out
+ * (and will still have leftover blocks for padbuf in the end).
+ * we can mac directly out of our buffer without first copying
+ * them to padBuf */
+ rv = AES_Encrypt(context->aes, context->macBuf, &tmpLen,
+ sizeof(context->macBuf), buf, AES_BLOCK_SIZE);
+ if (rv != SECSuccess) {
+ return sftk_MapCryptError(PORT_GetError());
+ }
+ len -= AES_BLOCK_SIZE;
+ buf += AES_BLOCK_SIZE;
+ }
+ }
+ PORT_Memcpy(context->padBuf + context->nextChar, buf, len);
+ context->nextChar += len;
+ }
+ return CKR_OK;
+}
+
+/*
+ * free the data associated with the prf. Clear any possible CSPs
+ * This can safely be called on any context after prf_setup. It can
+ * also be called an an already freed context.
+ * A free context can be reused by calling prf_init again without
+ * the need to call prf_setup.
+ */
+static void
+prf_free(prfContext *context)
+{
+ if (context->hmac) {
+ HMAC_Destroy(context->hmac, PR_TRUE);
+ context->hmac = NULL;
+ }
+ if (context->aes) {
+ PORT_Memset(context->k1, 0, sizeof(context->k1));
+ PORT_Memset(context->k2, 0, sizeof(context->k2));
+ PORT_Memset(context->k3, 0, sizeof(context->k2));
+ PORT_Memset(context->padBuf, 0, sizeof(context->padBuf));
+ PORT_Memset(context->macBuf, 0, sizeof(context->macBuf));
+ AES_DestroyContext(context->aes, PR_TRUE);
+ context->aes = NULL;
+ }
+}
+
+/*
+ * extract the final prf value. On success, this has the side effect of
+ * also freeing the context data and clearing the keys
+ */
+static CK_RV
+prf_final(prfContext *context, unsigned char *buf, unsigned int len)
+{
+ unsigned int tmpLen;
+ SECStatus rv;
+
+ if (context->hmac) {
+ unsigned int outLen;
+ HMAC_Finish(context->hmac, buf, &outLen, len);
+ if (outLen != len) {
+ return CKR_GENERAL_ERROR;
+ }
+ } else {
+ /* prf_update had guarrenteed that the last full block is still in
+ * the padBuf if the input data is a multiple of the blocksize. This
+ * allows sftk_xcbc_mac_pad to process that pad buf accordingly */
+ CK_RV crv = sftk_xcbc_mac_pad(context->padBuf, context->nextChar,
+ AES_BLOCK_SIZE, context->k2, context->k3);
+ if (crv != CKR_OK) {
+ return crv;
+ }
+ rv = AES_Encrypt(context->aes, context->macBuf, &tmpLen,
+ sizeof(context->macBuf), context->padBuf, AES_BLOCK_SIZE);
+ if (rv != SECSuccess) {
+ return sftk_MapCryptError(PORT_GetError());
+ }
+ PORT_Memcpy(buf, context->macBuf, len);
+ }
+ prf_free(context);
+ return CKR_OK;
+}
+
+/*
+ * There are four flavors of ike prf functions here.
+ * ike_prf is used in both ikeV1 and ikeV2 to generate
+ * an initial key that all the other keys are generated with.
+ *
+ * These functions are called from NSC_DeriveKey with the inKey value
+ * already looked up, and it expects the CKA_VALUE for outKey to be set.
+ *
+ * Depending on usage it returns either:
+ * 1. prf(Ni|Nr, inKey); (bDataAsKey=TRUE, bRekey=FALSE)
+ * 2. prf(inKey, Ni|Nr); (bDataAsKkey=FALSE, bRekey=FALSE)
+ * 3. prf(inKey, newKey | Ni | Nr); (bDataAsKey=FALSE, bRekey=TRUE)
+ * The resulting output key is always the length of the underlying prf
+ * (as returned by prf_length()).
+ * The combination of bDataAsKey=TRUE and bRekey=TRUE is not allowed
+ *
+ * Case 1 is used in
+ * a. ikev2 (rfc5996) inKey is called g^ir, the output is called SKEYSEED
+ * b. ikev1 (rfc2409) inKey is called g^ir, the output is called SKEYID
+ * Case 2 is used in ikev1 (rfc2409) inkey is called pre-shared-key, output
+ * is called SKEYID
+ * Case 3 is used in ikev2 (rfc5996) rekey case, inKey is SK_d, newKey is
+ * g^ir (new), the output is called SKEYSEED
+ */
+CK_RV
+sftk_ike_prf(CK_SESSION_HANDLE hSession, const SFTKAttribute *inKey,
+ const CK_NSS_IKE_PRF_DERIVE_PARAMS *params, SFTKObject *outKey)
+{
+ SFTKAttribute *newKeyValue = NULL;
+ SFTKObject *newKeyObj = NULL;
+ unsigned char outKeyData[HASH_LENGTH_MAX];
+ unsigned char *newInKey = NULL;
+ unsigned int newInKeySize;
+ unsigned int macSize;
+ CK_RV crv = CKR_OK;
+ prfContext context;
+
+ crv = prf_setup(&context, params->prfMechanism);
+ if (crv != CKR_OK) {
+ return crv;
+ }
+ macSize = prf_length(&context);
+ if ((params->bDataAsKey) && (params->bRekey)) {
+ return CKR_ARGUMENTS_BAD;
+ }
+ if (params->bRekey) {
+ /* lookup the value of new key from the session and key handle */
+ SFTKSession *session = sftk_SessionFromHandle(hSession);
+ if (session == NULL) {
+ return CKR_SESSION_HANDLE_INVALID;
+ }
+ newKeyObj = sftk_ObjectFromHandle(params->hNewKey, session);
+ sftk_FreeSession(session);
+ if (newKeyObj == NULL) {
+ return CKR_KEY_HANDLE_INVALID;
+ }
+ newKeyValue = sftk_FindAttribute(newKeyObj, CKA_VALUE);
+ if (newKeyValue == NULL) {
+ crv = CKR_KEY_HANDLE_INVALID;
+ goto fail;
+ }
+ }
+ if (params->bDataAsKey) {
+ /* The key is Ni || Np, so we need to concatenate them together first */
+ newInKeySize = params->ulNiLen + params->ulNrLen;
+ newInKey = PORT_Alloc(newInKeySize);
+ if (newInKey == NULL) {
+ crv = CKR_HOST_MEMORY;
+ goto fail;
+ }
+ PORT_Memcpy(newInKey, params->pNi, params->ulNiLen);
+ PORT_Memcpy(newInKey + params->ulNiLen, params->pNr, params->ulNrLen);
+ crv = prf_init(&context, newInKey, newInKeySize);
+ if (crv != CKR_OK) {
+ goto fail;
+ }
+ /* key as the data */
+ crv = prf_update(&context, inKey->attrib.pValue,
+ inKey->attrib.ulValueLen);
+ if (crv != CKR_OK) {
+ goto fail;
+ }
+ } else {
+ crv = prf_init(&context, inKey->attrib.pValue,
+ inKey->attrib.ulValueLen);
+ if (crv != CKR_OK) {
+ goto fail;
+ }
+ if (newKeyValue) {
+ crv = prf_update(&context, newKeyValue->attrib.pValue,
+ newKeyValue->attrib.ulValueLen);
+ if (crv != CKR_OK) {
+ goto fail;
+ }
+ }
+ crv = prf_update(&context, params->pNi, params->ulNiLen);
+ if (crv != CKR_OK) {
+ goto fail;
+ }
+ crv = prf_update(&context, params->pNr, params->ulNrLen);
+ if (crv != CKR_OK) {
+ goto fail;
+ }
+ }
+ crv = prf_final(&context, outKeyData, macSize);
+ if (crv != CKR_OK) {
+ goto fail;
+ }
+
+ crv = sftk_forceAttribute(outKey, CKA_VALUE, outKeyData, macSize);
+fail:
+ if (newInKey) {
+ PORT_Free(newInKey);
+ }
+ if (newKeyValue) {
+ sftk_FreeAttribute(newKeyValue);
+ }
+ if (newKeyObj) {
+ sftk_FreeObject(newKeyObj);
+ }
+ PORT_Memset(outKeyData, 0, macSize);
+ prf_free(&context);
+ return crv;
+}
+
+/*
+ * The second flavor of ike prf is ike1_prf.
+ *
+ * It is used by ikeV1 to generate the various session keys used in the
+ * connection. It uses the initial key, an optional previous key, and a one byte
+ * key number to generate a unique key for each of the various session
+ * functions (encryption, decryption, mac). These keys expect a key size
+ * (as they may vary in length based on usage). If no length is provided,
+ * it will default to the length of the prf.
+ *
+ * This function returns either:
+ * prf(inKey, gxyKey || CKYi || CKYr || key_number)
+ * or
+ * prf(inKey, prevkey || gxyKey || CKYi || CKYr || key_number)
+ * depending on the stats of bHasPrevKey
+ *
+ * This is defined in rfc2409. For each of the following keys.
+ * inKey is SKEYID, gxyKey is g^xy
+ * for outKey = SKEYID_d, bHasPrevKey = false, key_number = 0
+ * for outKey = SKEYID_a, prevKey= SKEYID_d, key_number = 1
+ * for outKey = SKEYID_e, prevKey= SKEYID_a, key_number = 2
+ */
+CK_RV
+sftk_ike1_prf(CK_SESSION_HANDLE hSession, const SFTKAttribute *inKey,
+ const CK_NSS_IKE1_PRF_DERIVE_PARAMS *params, SFTKObject *outKey,
+ unsigned int keySize)
+{
+ SFTKAttribute *gxyKeyValue = NULL;
+ SFTKObject *gxyKeyObj = NULL;
+ SFTKAttribute *prevKeyValue = NULL;
+ SFTKObject *prevKeyObj = NULL;
+ SFTKSession *session;
+ unsigned char outKeyData[HASH_LENGTH_MAX];
+ unsigned int macSize;
+ CK_RV crv;
+ prfContext context;
+
+ crv = prf_setup(&context, params->prfMechanism);
+ if (crv != CKR_OK) {
+ return crv;
+ }
+ macSize = prf_length(&context);
+ if (keySize > macSize) {
+ return CKR_KEY_SIZE_RANGE;
+ }
+ if (keySize == 0) {
+ keySize = macSize;
+ }
+
+ /* lookup the two keys from their passed in handles */
+ session = sftk_SessionFromHandle(hSession);
+ if (session == NULL) {
+ return CKR_SESSION_HANDLE_INVALID;
+ }
+ gxyKeyObj = sftk_ObjectFromHandle(params->hKeygxy, session);
+ if (params->bHasPrevKey) {
+ prevKeyObj = sftk_ObjectFromHandle(params->hPrevKey, session);
+ }
+ sftk_FreeSession(session);
+ if ((gxyKeyObj == NULL) || ((params->bHasPrevKey) &&
+ (prevKeyObj == NULL))) {
+ crv = CKR_KEY_HANDLE_INVALID;
+ goto fail;
+ }
+ gxyKeyValue = sftk_FindAttribute(gxyKeyObj, CKA_VALUE);
+ if (gxyKeyValue == NULL) {
+ crv = CKR_KEY_HANDLE_INVALID;
+ goto fail;
+ }
+ if (prevKeyObj) {
+ prevKeyValue = sftk_FindAttribute(prevKeyObj, CKA_VALUE);
+ if (prevKeyValue == NULL) {
+ crv = CKR_KEY_HANDLE_INVALID;
+ goto fail;
+ }
+ }
+
+ /* outKey = prf(inKey, [prevKey|] gxyKey | CKYi | CKYr | keyNumber) */
+ crv = prf_init(&context, inKey->attrib.pValue, inKey->attrib.ulValueLen);
+ if (crv != CKR_OK) {
+ goto fail;
+ }
+ if (prevKeyValue) {
+ crv = prf_update(&context, prevKeyValue->attrib.pValue,
+ prevKeyValue->attrib.ulValueLen);
+ if (crv != CKR_OK) {
+ goto fail;
+ }
+ }
+ crv = prf_update(&context, gxyKeyValue->attrib.pValue,
+ gxyKeyValue->attrib.ulValueLen);
+ if (crv != CKR_OK) {
+ goto fail;
+ }
+ crv = prf_update(&context, params->pCKYi, params->ulCKYiLen);
+ if (crv != CKR_OK) {
+ goto fail;
+ }
+ crv = prf_update(&context, params->pCKYr, params->ulCKYrLen);
+ if (crv != CKR_OK) {
+ goto fail;
+ }
+ crv = prf_update(&context, &params->keyNumber, 1);
+ if (crv != CKR_OK) {
+ goto fail;
+ }
+ crv = prf_final(&context, outKeyData, macSize);
+ if (crv != CKR_OK) {
+ goto fail;
+ }
+
+ crv = sftk_forceAttribute(outKey, CKA_VALUE, outKeyData, keySize);
+fail:
+ if (gxyKeyValue) {
+ sftk_FreeAttribute(gxyKeyValue);
+ }
+ if (prevKeyValue) {
+ sftk_FreeAttribute(prevKeyValue);
+ }
+ if (gxyKeyObj) {
+ sftk_FreeObject(gxyKeyObj);
+ }
+ if (prevKeyObj) {
+ sftk_FreeObject(prevKeyObj);
+ }
+ PORT_Memset(outKeyData, 0, macSize);
+ prf_free(&context);
+ return crv;
+}
+
+/*
+ * The third flavor of ike prf is ike1_appendix_b.
+ *
+ * It is used by ikeV1 to generate longer key material from skeyid_e.
+ * Unlike ike1_prf, if no length is provided, this function
+ * will generate a KEY_RANGE_ERROR.
+ *
+ * This function returns (from rfc2409 appendix b):
+ * Ka = K1 | K2 | K3 | K4 |... Kn
+ * where:
+ * K1 = prf(K, 0x00)
+ * K2 = prf(K, K1)
+ * K3 = prf(K, K2)
+ * K4 = prf(K, K3)
+ * .
+ * Kn = prf(K, K(n-1))
+ * K = inKey
+ */
+CK_RV
+sftk_ike1_appendix_b_prf(CK_SESSION_HANDLE hSession, const SFTKAttribute *inKey,
+ const CK_MECHANISM_TYPE *mech, SFTKObject *outKey, unsigned int keySize)
+{
+ unsigned char *outKeyData = NULL;
+ unsigned char *thisKey = NULL;
+ unsigned char *lastKey = NULL;
+ unsigned int macSize;
+ unsigned int outKeySize;
+ unsigned int genKeySize;
+ CK_RV crv;
+ prfContext context;
+
+ crv = prf_setup(&context, *mech);
+ if (crv != CKR_OK) {
+ return crv;
+ }
+
+ macSize = prf_length(&context);
+
+ if (keySize == 0) {
+ keySize = macSize;
+ }
+
+ if (keySize <= inKey->attrib.ulValueLen) {
+ return sftk_forceAttribute(outKey, CKA_VALUE,
+ inKey->attrib.pValue, keySize);
+ }
+ outKeySize = PR_ROUNDUP(keySize, macSize);
+ outKeyData = PORT_Alloc(outKeySize);
+ if (outKeyData == NULL) {
+ crv = CKR_HOST_MEMORY;
+ goto fail;
+ }
+
+ /*
+ * this loop generates on block of the prf, basically
+ * kn = prf(key, Kn-1)
+ * Kn is thisKey, Kn-1 is lastKey
+ * key is inKey
+ */
+ thisKey = outKeyData;
+ for (genKeySize = 0; genKeySize <= keySize; genKeySize += macSize) {
+ crv = prf_init(&context, inKey->attrib.pValue, inKey->attrib.ulValueLen);
+ if (crv != CKR_OK) {
+ goto fail;
+ }
+ if (lastKey == NULL) {
+ const unsigned char zero = 0;
+ crv = prf_update(&context, &zero, 1);
+ } else {
+ crv = prf_update(&context, lastKey, macSize);
+ }
+ if (crv != CKR_OK) {
+ goto fail;
+ }
+ crv = prf_final(&context, thisKey, macSize);
+ if (crv != CKR_OK) {
+ goto fail;
+ }
+ lastKey = thisKey;
+ thisKey += macSize;
+ }
+ crv = sftk_forceAttribute(outKey, CKA_VALUE, outKeyData, keySize);
+fail:
+ if (outKeyData) {
+ PORT_ZFree(outKeyData, outKeySize);
+ }
+ prf_free(&context);
+ return crv;
+}
+
+/*
+ * The final flavor of ike prf is ike_prf_plus
+ *
+ * It is used by ikeV2 to generate the various session keys used in the
+ * connection. It uses the initial key and a feedback version of the prf
+ * to generate sufficient bytes to cover all the session keys. The application
+ * will then use CK_EXTRACT_KEY_FROM_KEY to pull out the various subkeys.
+ * This function expects a key size to be set by the application to cover
+ * all the keys. Unlike ike1_prf, if no length is provided, this function
+ * will generate a KEY_RANGE_ERROR
+ *
+ * This function returns (from rfc5996):
+ * prfplus = T1 | T2 | T3 | T4 |... Tn
+ * where:
+ * T1 = prf(K, S | 0x01)
+ * T2 = prf(K, T1 | S | 0x02)
+ * T3 = prf(K, T3 | S | 0x03)
+ * T4 = prf(K, T4 | S | 0x04)
+ * .
+ * Tn = prf(K, T(n-1) | n)
+ * K = inKey, S = seedKey | seedData
+ */
+
+CK_RV
+sftk_ike_prf_plus(CK_SESSION_HANDLE hSession, const SFTKAttribute *inKey,
+ const CK_NSS_IKE_PRF_PLUS_DERIVE_PARAMS *params, SFTKObject *outKey,
+ unsigned int keySize)
+{
+ SFTKAttribute *seedValue = NULL;
+ SFTKObject *seedKeyObj = NULL;
+ unsigned char *outKeyData = NULL;
+ unsigned int outKeySize;
+ unsigned char *thisKey;
+ unsigned char *lastKey = NULL;
+ unsigned char currentByte = 0;
+ unsigned int getKeySize;
+ unsigned int macSize;
+ CK_RV crv;
+ prfContext context;
+
+ if (keySize == 0) {
+ return CKR_KEY_SIZE_RANGE;
+ }
+
+ crv = prf_setup(&context, params->prfMechanism);
+ if (crv != CKR_OK) {
+ return crv;
+ }
+ /* pull in optional seedKey */
+ if (params->bHasSeedKey) {
+ SFTKSession *session = sftk_SessionFromHandle(hSession);
+ if (session == NULL) {
+ return CKR_SESSION_HANDLE_INVALID;
+ }
+ seedKeyObj = sftk_ObjectFromHandle(params->hSeedKey, session);
+ sftk_FreeSession(session);
+ if (seedKeyObj == NULL) {
+ return CKR_KEY_HANDLE_INVALID;
+ }
+ seedValue = sftk_FindAttribute(seedKeyObj, CKA_VALUE);
+ if (seedValue == NULL) {
+ crv = CKR_KEY_HANDLE_INVALID;
+ goto fail;
+ }
+ } else if (params->ulSeedDataLen == 0) {
+ crv = CKR_ARGUMENTS_BAD;
+ goto fail;
+ }
+ macSize = prf_length(&context);
+ outKeySize = PR_ROUNDUP(keySize, macSize);
+ outKeyData = PORT_Alloc(outKeySize);
+ if (outKeyData == NULL) {
+ crv = CKR_HOST_MEMORY;
+ goto fail;
+ }
+
+ /*
+ * this loop generates on block of the prf, basically
+ * Tn = prf(key, Tn-1 | S | n)
+ * Tn is thisKey, Tn-2 is lastKey, S is seedKey || seedData,
+ * key is inKey. currentByte = n-1 on entry.
+ */
+ thisKey = outKeyData;
+ for (getKeySize = 0; getKeySize < keySize; getKeySize += macSize) {
+ /* if currentByte is 255, we'll overflow when we increment it below.
+ * This can only happen if keysize > 255*macSize. In that case
+ * the application has asked for too much key material, so return
+ * an error */
+ if (currentByte == 255) {
+ crv = CKR_KEY_SIZE_RANGE;
+ goto fail;
+ }
+ crv = prf_init(&context, inKey->attrib.pValue,
+ inKey->attrib.ulValueLen);
+ if (crv != CKR_OK) {
+ goto fail;
+ }
+
+ if (lastKey) {
+ crv = prf_update(&context, lastKey, macSize);
+ if (crv != CKR_OK) {
+ goto fail;
+ }
+ }
+ /* prf the key first */
+ if (seedValue) {
+ crv = prf_update(&context, seedValue->attrib.pValue,
+ seedValue->attrib.ulValueLen);
+ if (crv != CKR_OK) {
+ goto fail;
+ }
+ }
+ /* then prf the data */
+ if (params->ulSeedDataLen != 0) {
+ crv = prf_update(&context, params->pSeedData,
+ params->ulSeedDataLen);
+ if (crv != CKR_OK) {
+ goto fail;
+ }
+ }
+ currentByte++;
+ crv = prf_update(&context, &currentByte, 1);
+ if (crv != CKR_OK) {
+ goto fail;
+ }
+ crv = prf_final(&context, thisKey, macSize);
+ if (crv != CKR_OK) {
+ goto fail;
+ }
+ lastKey = thisKey;
+ thisKey += macSize;
+ }
+ crv = sftk_forceAttribute(outKey, CKA_VALUE, outKeyData, keySize);
+fail:
+ if (outKeyData) {
+ PORT_ZFree(outKeyData, outKeySize);
+ }
+ if (seedValue) {
+ sftk_FreeAttribute(seedValue);
+ }
+ if (seedKeyObj) {
+ sftk_FreeObject(seedKeyObj);
+ }
+ prf_free(&context);
+ return crv;
+}
+
+/* sftk_aes_xcbc_new_keys:
+ *
+ * aes xcbc creates 3 new keys from the input key. The first key will be the
+ * base key of the underlying cbc. The sign code hooks directly into encrypt
+ * so we'll have to create a full PKCS #11 key with handle for that key. The
+ * caller needs to delete the key when it's through setting up the context.
+ *
+ * The other two keys will be stored in the sign context until we need them
+ * at the end.
+ */
+CK_RV
+sftk_aes_xcbc_new_keys(CK_SESSION_HANDLE hSession,
+ CK_OBJECT_HANDLE hKey, CK_OBJECT_HANDLE_PTR phKey,
+ unsigned char *k2, unsigned char *k3)
+{
+ SFTKObject *key = NULL;
+ SFTKSession *session = NULL;
+ SFTKObject *inKeyObj = NULL;
+ SFTKAttribute *inKeyValue = NULL;
+ CK_KEY_TYPE key_type = CKK_AES;
+ CK_OBJECT_CLASS objclass = CKO_SECRET_KEY;
+ CK_BBOOL ck_true = CK_TRUE;
+ CK_RV crv = CKR_OK;
+ SFTKSlot *slot = sftk_SlotFromSessionHandle(hSession);
+ unsigned char buf[AES_BLOCK_SIZE];
+
+ if (!slot) {
+ return CKR_SESSION_HANDLE_INVALID;
+ }
+
+ /* get the session */
+ session = sftk_SessionFromHandle(hSession);
+ if (session == NULL) {
+ crv = CKR_SESSION_HANDLE_INVALID;
+ goto fail;
+ }
+
+ inKeyObj = sftk_ObjectFromHandle(hKey, session);
+ if (inKeyObj == NULL) {
+ crv = CKR_KEY_HANDLE_INVALID;
+ goto fail;
+ }
+
+ inKeyValue = sftk_FindAttribute(inKeyObj, CKA_VALUE);
+ if (inKeyValue == NULL) {
+ crv = CKR_KEY_HANDLE_INVALID;
+ goto fail;
+ }
+
+ crv = sftk_aes_xcbc_get_keys(inKeyValue->attrib.pValue,
+ inKeyValue->attrib.ulValueLen, buf, k2, k3);
+
+ if (crv != CKR_OK) {
+ goto fail;
+ }
+
+ /*
+ * now lets create an object to hang the attributes off of
+ */
+ key = sftk_NewObject(slot); /* fill in the handle later */
+ if (key == NULL) {
+ crv = CKR_HOST_MEMORY;
+ goto fail;
+ }
+
+ /* make sure we don't have any class, key_type, or value fields */
+ sftk_DeleteAttributeType(key, CKA_CLASS);
+ sftk_DeleteAttributeType(key, CKA_KEY_TYPE);
+ sftk_DeleteAttributeType(key, CKA_VALUE);
+ sftk_DeleteAttributeType(key, CKA_SIGN);
+
+ /* Add the class, key_type, and value */
+ crv = sftk_AddAttributeType(key, CKA_CLASS, &objclass, sizeof(CK_OBJECT_CLASS));
+ if (crv != CKR_OK) {
+ goto fail;
+ }
+ crv = sftk_AddAttributeType(key, CKA_KEY_TYPE, &key_type, sizeof(CK_KEY_TYPE));
+ if (crv != CKR_OK) {
+ goto fail;
+ }
+ crv = sftk_AddAttributeType(key, CKA_SIGN, &ck_true, sizeof(CK_BBOOL));
+ if (crv != CKR_OK) {
+ goto fail;
+ }
+ crv = sftk_AddAttributeType(key, CKA_VALUE, buf, AES_BLOCK_SIZE);
+ if (crv != CKR_OK) {
+ goto fail;
+ }
+
+ /*
+ * finish filling in the key and link it with our global system.
+ */
+ crv = sftk_handleObject(key, session);
+ if (crv != CKR_OK) {
+ goto fail;
+ }
+ *phKey = key->handle;
+fail:
+ if (session) {
+ sftk_FreeSession(session);
+ }
+
+ if (inKeyValue) {
+ sftk_FreeAttribute(inKeyValue);
+ }
+ if (inKeyObj) {
+ sftk_FreeObject(inKeyObj);
+ }
+ if (key) {
+ sftk_FreeObject(key);
+ }
+ /* clear our CSPs */
+ PORT_Memset(buf, 0, sizeof(buf));
+ if (crv != CKR_OK) {
+ PORT_Memset(k2, 0, AES_BLOCK_SIZE);
+ PORT_Memset(k3, 0, AES_BLOCK_SIZE);
+ }
+ return crv;
+}
+
+/*
+ * Helper function that tests a single prf test vector
+ */
+static SECStatus
+prf_test(CK_MECHANISM_TYPE mech,
+ const unsigned char *inKey, unsigned int inKeyLen,
+ const unsigned char *plainText, unsigned int plainTextLen,
+ const unsigned char *expectedResult, unsigned int expectedResultLen)
+{
+ PRUint8 ike_computed_mac[HASH_LENGTH_MAX];
+ prfContext context;
+ unsigned int macSize;
+ CK_RV crv;
+
+ crv = prf_setup(&context, mech);
+ if (crv != CKR_OK) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
+ }
+ macSize = prf_length(&context);
+ crv = prf_init(&context, inKey, inKeyLen);
+ if (crv != CKR_OK) {
+ goto fail;
+ }
+ crv = prf_update(&context, plainText, plainTextLen);
+ if (crv != CKR_OK) {
+ goto fail;
+ }
+ crv = prf_final(&context, ike_computed_mac, macSize);
+ if (crv != CKR_OK) {
+ goto fail;
+ }
+
+ if (macSize != expectedResultLen) {
+ goto fail;
+ }
+ if (PORT_Memcmp(expectedResult, ike_computed_mac, macSize) != 0) {
+ goto fail;
+ }
+
+ /* only do the alignment if the plaintext is long enough */
+ if (plainTextLen <= macSize) {
+ return SECSuccess;
+ }
+ prf_free(&context);
+ /* do it again, but this time tweak with the alignment */
+ crv = prf_init(&context, inKey, inKeyLen);
+ if (crv != CKR_OK) {
+ goto fail;
+ }
+ crv = prf_update(&context, plainText, 1);
+ if (crv != CKR_OK) {
+ goto fail;
+ }
+ crv = prf_update(&context, &plainText[1], macSize);
+ if (crv != CKR_OK) {
+ goto fail;
+ }
+ crv = prf_update(&context, &plainText[1 + macSize], plainTextLen - (macSize + 1));
+ if (crv != CKR_OK) {
+ goto fail;
+ }
+ crv = prf_final(&context, ike_computed_mac, macSize);
+ if (crv != CKR_OK) {
+ goto fail;
+ }
+ if (PORT_Memcmp(expectedResult, ike_computed_mac, macSize) != 0) {
+ goto fail;
+ }
+ prf_free(&context);
+ return SECSuccess;
+fail:
+ prf_free(&context);
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
+}
+
+/*
+ * FIPS Power up Self Tests for IKE. This is in this function so it
+ * can access the private prf_ functions here. It's called out of fipstest.c
+ */
+SECStatus
+sftk_fips_IKE_PowerUpSelfTests(void)
+{
+ /* PRF known test vectors */
+ static const PRUint8 ike_xcbc_known_key[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
+ };
+ static const PRUint8 ike_xcbc_known_plain_text[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
+ };
+ static const PRUint8 ike_xcbc_known_mac[] = {
+ 0xd2, 0xa2, 0x46, 0xfa, 0x34, 0x9b, 0x68, 0xa7,
+ 0x99, 0x98, 0xa4, 0x39, 0x4f, 0xf7, 0xa2, 0x63
+ };
+ /* test 2 uses the same key as test 1 */
+ static const PRUint8 ike_xcbc_known_plain_text_2[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13
+ };
+ static const PRUint8 ike_xcbc_known_mac_2[] = {
+ 0x47, 0xf5, 0x1b, 0x45, 0x64, 0x96, 0x62, 0x15,
+ 0xb8, 0x98, 0x5c, 0x63, 0x05, 0x5e, 0xd3, 0x08
+ };
+ static const PRUint8 ike_xcbc_known_key_3[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09
+ };
+ /* test 3 uses the same plaintest as test 2 */
+ static const PRUint8 ike_xcbc_known_mac_3[] = {
+ 0x0f, 0xa0, 0x87, 0xaf, 0x7d, 0x86, 0x6e, 0x76,
+ 0x53, 0x43, 0x4e, 0x60, 0x2f, 0xdd, 0xe8, 0x35
+ };
+ static const PRUint8 ike_xcbc_known_key_4[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0xed, 0xcb
+ };
+ /* test 4 uses the same plaintest as test 2 */
+ static const PRUint8 ike_xcbc_known_mac_4[] = {
+ 0x8c, 0xd3, 0xc9, 0x3a, 0xe5, 0x98, 0xa9, 0x80,
+ 0x30, 0x06, 0xff, 0xb6, 0x7c, 0x40, 0xe9, 0xe4
+ };
+ static const PRUint8 ike_sha1_known_key[] = {
+ 0x59, 0x98, 0x2b, 0x5b, 0xa5, 0x7e, 0x62, 0xc0,
+ 0x46, 0x0d, 0xef, 0xc7, 0x1e, 0x18, 0x64, 0x63
+ };
+ static const PRUint8 ike_sha1_known_plain_text[] = {
+ 0x1c, 0x07, 0x32, 0x1a, 0x9a, 0x7e, 0x41, 0xcd,
+ 0x88, 0x0c, 0xa3, 0x7a, 0xdb, 0x10, 0xc7, 0x3b,
+ 0xf0, 0x0e, 0x7a, 0xe3, 0xcf, 0xc6, 0xfd, 0x8b,
+ 0x51, 0xbc, 0xe2, 0xb9, 0x90, 0xe6, 0xf2, 0x01
+ };
+ static const PRUint8 ike_sha1_known_mac[] = {
+ 0x0c, 0x2a, 0xf3, 0x42, 0x97, 0x15, 0x62, 0x1d,
+ 0x2a, 0xad, 0xc9, 0x94, 0x5a, 0x90, 0x26, 0xfa,
+ 0xc7, 0x91, 0xe2, 0x4b
+ };
+ static const PRUint8 ike_sha256_known_key[] = {
+ 0x9d, 0xa2, 0xd5, 0x8f, 0x57, 0xf0, 0x39, 0xf9,
+ 0x20, 0x4e, 0x0d, 0xd0, 0xef, 0x04, 0xf3, 0x72
+ };
+ static const PRUint8 ike_sha256_known_plain_text[] = {
+ 0x33, 0xf1, 0x7a, 0xfc, 0xb6, 0x13, 0x4c, 0xbf,
+ 0x1c, 0xab, 0x59, 0x87, 0x7d, 0x42, 0xdb, 0x35,
+ 0x82, 0x22, 0x6e, 0xff, 0x74, 0xdd, 0x37, 0xeb,
+ 0x8b, 0x75, 0xe6, 0x75, 0x64, 0x5f, 0xc1, 0x69
+ };
+ static const PRUint8 ike_sha256_known_mac[] = {
+ 0x80, 0x4b, 0x4a, 0x1e, 0x0e, 0xc5, 0x93, 0xcf,
+ 0xb6, 0xe4, 0x54, 0x52, 0x41, 0x49, 0x39, 0x6d,
+ 0xe2, 0x34, 0xd0, 0xda, 0xe2, 0x9f, 0x34, 0xa8,
+ 0xfd, 0xb5, 0xf9, 0xaf, 0xe7, 0x6e, 0xa6, 0x52
+ };
+ static const PRUint8 ike_sha384_known_key[] = {
+ 0xce, 0xc8, 0x9d, 0x84, 0x5a, 0xdd, 0x83, 0xef,
+ 0xce, 0xbd, 0x43, 0xab, 0x71, 0xd1, 0x7d, 0xb9
+ };
+ static const PRUint8 ike_sha384_known_plain_text[] = {
+ 0x17, 0x24, 0xdb, 0xd8, 0x93, 0x52, 0x37, 0x64,
+ 0xbf, 0xef, 0x8c, 0x6f, 0xa9, 0x27, 0x85, 0x6f,
+ 0xcc, 0xfb, 0x77, 0xae, 0x25, 0x43, 0x58, 0xcc,
+ 0xe2, 0x9c, 0x27, 0x69, 0xa3, 0x29, 0x15, 0xc1
+ };
+ static const PRUint8 ike_sha384_known_mac[] = {
+ 0x6e, 0x45, 0x14, 0x61, 0x0b, 0xf8, 0x2d, 0x0a,
+ 0xb7, 0xbf, 0x02, 0x60, 0x09, 0x6f, 0x61, 0x46,
+ 0xa1, 0x53, 0xc7, 0x12, 0x07, 0x1a, 0xbb, 0x63,
+ 0x3c, 0xed, 0x81, 0x3c, 0x57, 0x21, 0x56, 0xc7,
+ 0x83, 0xe3, 0x68, 0x74, 0xa6, 0x5a, 0x64, 0x69,
+ 0x0c, 0xa7, 0x01, 0xd4, 0x0d, 0x56, 0xea, 0x18
+ };
+ static const PRUint8 ike_sha512_known_key[] = {
+ 0xac, 0xad, 0xc6, 0x31, 0x4a, 0x69, 0xcf, 0xcd,
+ 0x4e, 0x4a, 0xd1, 0x77, 0x18, 0xfe, 0xa7, 0xce
+ };
+ static const PRUint8 ike_sha512_known_plain_text[] = {
+ 0xb1, 0x5a, 0x9c, 0xfc, 0xe8, 0xc8, 0xd7, 0xea,
+ 0xb8, 0x79, 0xd6, 0x24, 0x30, 0x29, 0xd4, 0x01,
+ 0x88, 0xd3, 0xb7, 0x40, 0x87, 0x5a, 0x6a, 0xc6,
+ 0x2f, 0x56, 0xca, 0xc4, 0x37, 0x7e, 0x2e, 0xdd
+ };
+ static const PRUint8 ike_sha512_known_mac[] = {
+ 0xf0, 0x5a, 0xa0, 0x36, 0xdf, 0xce, 0x45, 0xa5,
+ 0x58, 0xd4, 0x04, 0x18, 0xde, 0xa9, 0x80, 0x96,
+ 0xe5, 0x19, 0xbc, 0x78, 0x41, 0xe3, 0xdb, 0x3d,
+ 0xd9, 0x36, 0x58, 0xd1, 0x18, 0xc3, 0xe8, 0x3b,
+ 0x50, 0x2f, 0x39, 0x8e, 0xcb, 0x13, 0x61, 0xec,
+ 0x77, 0xd3, 0x8a, 0x88, 0x55, 0xef, 0xff, 0x40,
+ 0x7f, 0x6f, 0x77, 0x2e, 0x5d, 0x65, 0xb5, 0x8e,
+ 0xb1, 0x13, 0x40, 0x96, 0xe8, 0x47, 0x8d, 0x2b
+ };
+ SECStatus rv;
+
+ rv = prf_test(CKM_AES_XCBC_MAC,
+ ike_xcbc_known_key, sizeof(ike_xcbc_known_key),
+ ike_xcbc_known_plain_text, sizeof(ike_xcbc_known_plain_text),
+ ike_xcbc_known_mac, sizeof(ike_xcbc_known_mac));
+ if (rv != SECSuccess)
+ return rv;
+ rv = prf_test(CKM_AES_XCBC_MAC,
+ ike_xcbc_known_key, sizeof(ike_xcbc_known_key),
+ ike_xcbc_known_plain_text_2, sizeof(ike_xcbc_known_plain_text_2),
+ ike_xcbc_known_mac_2, sizeof(ike_xcbc_known_mac_2));
+ if (rv != SECSuccess)
+ return rv;
+ rv = prf_test(CKM_AES_XCBC_MAC,
+ ike_xcbc_known_key_3, sizeof(ike_xcbc_known_key_3),
+ ike_xcbc_known_plain_text_2, sizeof(ike_xcbc_known_plain_text_2),
+ ike_xcbc_known_mac_3, sizeof(ike_xcbc_known_mac_3));
+ if (rv != SECSuccess)
+ return rv;
+ rv = prf_test(CKM_AES_XCBC_MAC,
+ ike_xcbc_known_key_4, sizeof(ike_xcbc_known_key_4),
+ ike_xcbc_known_plain_text_2, sizeof(ike_xcbc_known_plain_text_2),
+ ike_xcbc_known_mac_4, sizeof(ike_xcbc_known_mac_4));
+ if (rv != SECSuccess)
+ return rv;
+ rv = prf_test(CKM_SHA_1_HMAC,
+ ike_sha1_known_key, sizeof(ike_sha1_known_key),
+ ike_sha1_known_plain_text, sizeof(ike_sha1_known_plain_text),
+ ike_sha1_known_mac, sizeof(ike_sha1_known_mac));
+ if (rv != SECSuccess)
+ return rv;
+ rv = prf_test(CKM_SHA256_HMAC,
+ ike_sha256_known_key, sizeof(ike_sha256_known_key),
+ ike_sha256_known_plain_text,
+ sizeof(ike_sha256_known_plain_text),
+ ike_sha256_known_mac, sizeof(ike_sha256_known_mac));
+ if (rv != SECSuccess)
+ return rv;
+ rv = prf_test(CKM_SHA384_HMAC,
+ ike_sha384_known_key, sizeof(ike_sha384_known_key),
+ ike_sha384_known_plain_text,
+ sizeof(ike_sha384_known_plain_text),
+ ike_sha384_known_mac, sizeof(ike_sha384_known_mac));
+ if (rv != SECSuccess)
+ return rv;
+ rv = prf_test(CKM_SHA512_HMAC,
+ ike_sha512_known_key, sizeof(ike_sha512_known_key),
+ ike_sha512_known_plain_text,
+ sizeof(ike_sha512_known_plain_text),
+ ike_sha512_known_mac, sizeof(ike_sha512_known_mac));
+ return rv;
+}
diff --git a/security/nss/lib/softoken/sftkpwd.c b/security/nss/lib/softoken/sftkpwd.c
index b6d098a07..f2acf7664 100644
--- a/security/nss/lib/softoken/sftkpwd.c
+++ b/security/nss/lib/softoken/sftkpwd.c
@@ -34,13 +34,40 @@
#include "secerr.h"
#include "softoken.h"
-const int NSS_DEFAULT_ITERATION_COUNT =
-#ifdef DEBUG
- 25
-#else
- 500
-#endif
- ;
+static const int NSS_MP_PBE_ITERATION_COUNT = 10000;
+
+static int
+getPBEIterationCount(void)
+{
+ int c = NSS_MP_PBE_ITERATION_COUNT;
+
+ char *val = getenv("NSS_MIN_MP_PBE_ITERATION_COUNT");
+ if (val) {
+ int minimum = atoi(val);
+ if (c < minimum) {
+ c = minimum;
+ }
+ }
+
+ val = getenv("NSS_MAX_MP_PBE_ITERATION_COUNT");
+ if (val) {
+ int maximum = atoi(val);
+ if (c > maximum) {
+ c = maximum;
+ }
+ }
+
+ return c;
+}
+
+PRBool
+sftk_isLegacyIterationCountAllowed(void)
+{
+ static const char *legacyCountEnvVar =
+ "NSS_ALLOW_LEGACY_DBM_ITERATION_COUNT";
+ char *iterEnv = getenv(legacyCountEnvVar);
+ return (iterEnv && strcmp("0", iterEnv) != 0);
+}
/******************************************************************
*
@@ -244,6 +271,7 @@ sftkdb_DecryptAttribute(SECItem *passKey, SECItem *cipherText,
if (rv != SECSuccess) {
goto loser;
}
+ /* fprintf(stderr, "sftkdb_DecryptAttribute iteration: %d\n", cipherValue.param->iter); */
*plain = nsspkcs5_CipherData(cipherValue.param, passKey, &cipherValue.value,
PR_FALSE, NULL);
@@ -682,7 +710,7 @@ sftkdb_finishPasswordCheck(SFTKDBHandle *keydb, SECItem *key,
/*
* check to see if we have the NULL password set.
* We special case the NULL password so that if you have no password set, you
- * don't do thousands of hash rounds. This allows us to startup and get
+ * don't do thousands of hash rounds. This allows us to startup and get
* webpages without slowdown in normal mode.
*/
SECStatus
@@ -823,11 +851,14 @@ sftkdb_finishPasswordCheck(SFTKDBHandle *keydb, SECItem *key, const char *pw,
{
SECItem *result = NULL;
SECStatus rv;
- int iterationCount = NSS_DEFAULT_ITERATION_COUNT;
+ int iterationCount = getPBEIterationCount();
if (*pw == 0) {
iterationCount = 1;
+ } else if (keydb->usesLegacyStorage && !sftk_isLegacyIterationCountAllowed()) {
+ iterationCount = 1;
}
+
/* decrypt the entry value */
rv = sftkdb_DecryptAttribute(key, value, &result);
if (rv != SECSuccess) {
@@ -974,92 +1005,78 @@ static CK_RV
sftk_updateMacs(PLArenaPool *arena, SFTKDBHandle *handle,
CK_OBJECT_HANDLE id, SECItem *newKey, int iterationCount)
{
- CK_ATTRIBUTE authAttrs[] = {
- { CKA_MODULUS, NULL, 0 },
- { CKA_PUBLIC_EXPONENT, NULL, 0 },
- { CKA_CERT_SHA1_HASH, NULL, 0 },
- { CKA_CERT_MD5_HASH, NULL, 0 },
- { CKA_TRUST_SERVER_AUTH, NULL, 0 },
- { CKA_TRUST_CLIENT_AUTH, NULL, 0 },
- { CKA_TRUST_EMAIL_PROTECTION, NULL, 0 },
- { CKA_TRUST_CODE_SIGNING, NULL, 0 },
- { CKA_TRUST_STEP_UP_APPROVED, NULL, 0 },
- { CKA_NSS_OVERRIDE_EXTENSIONS, NULL, 0 },
- };
- CK_ULONG authAttrCount = sizeof(authAttrs) / sizeof(CK_ATTRIBUTE);
- unsigned int i, count;
SFTKDBHandle *keyHandle = handle;
SDB *keyTarget = NULL;
-
- id &= SFTK_OBJ_ID_MASK;
-
if (handle->type != SFTK_KEYDB_TYPE) {
keyHandle = handle->peerDB;
}
-
if (keyHandle == NULL) {
return CKR_OK;
}
-
- /* old DB's don't have meta data, finished with MACs */
+ // Old DBs don't have metadata, so we can return early here.
keyTarget = SFTK_GET_SDB(keyHandle);
if ((keyTarget->sdb_flags & SDB_HAS_META) == 0) {
return CKR_OK;
}
- /*
- * STEP 1: find the MACed attributes of this object
- */
- (void)sftkdb_GetAttributeValue(handle, id, authAttrs, authAttrCount);
- count = 0;
- /* allocate space for the attributes */
- for (i = 0; i < authAttrCount; i++) {
- if ((authAttrs[i].ulValueLen == -1) || (authAttrs[i].ulValueLen == 0)) {
- continue;
- }
- count++;
- authAttrs[i].pValue = PORT_ArenaAlloc(arena, authAttrs[i].ulValueLen);
- if (authAttrs[i].pValue == NULL) {
- break;
- }
- }
-
- /* if count was zero, none were found, finished with MACs */
- if (count == 0) {
- return CKR_OK;
- }
-
- (void)sftkdb_GetAttributeValue(handle, id, authAttrs, authAttrCount);
- /* ignore error code, we expect some possible errors */
+ id &= SFTK_OBJ_ID_MASK;
- /* GetAttributeValue just verified the old macs, safe to write
- * them out then... */
- for (i = 0; i < authAttrCount; i++) {
- SECItem *signText;
- SECItem plainText;
- SECStatus rv;
+ CK_ATTRIBUTE_TYPE authAttrTypes[] = {
+ CKA_MODULUS,
+ CKA_PUBLIC_EXPONENT,
+ CKA_CERT_SHA1_HASH,
+ CKA_CERT_MD5_HASH,
+ CKA_TRUST_SERVER_AUTH,
+ CKA_TRUST_CLIENT_AUTH,
+ CKA_TRUST_EMAIL_PROTECTION,
+ CKA_TRUST_CODE_SIGNING,
+ CKA_TRUST_STEP_UP_APPROVED,
+ CKA_NSS_OVERRIDE_EXTENSIONS,
+ };
+ const CK_ULONG authAttrTypeCount = sizeof(authAttrTypes) / sizeof(authAttrTypes[0]);
- if ((authAttrs[i].ulValueLen == -1) || (authAttrs[i].ulValueLen == 0)) {
+ // We don't know what attributes this object has, so we update them one at a
+ // time.
+ unsigned int i;
+ for (i = 0; i < authAttrTypeCount; i++) {
+ CK_ATTRIBUTE authAttr = { authAttrTypes[i], NULL, 0 };
+ CK_RV rv = sftkdb_GetAttributeValue(handle, id, &authAttr, 1);
+ if (rv != CKR_OK) {
continue;
}
-
- if (authAttrs[i].ulValueLen == sizeof(CK_ULONG) &&
- sftkdb_isULONGAttribute(authAttrs[i].type)) {
- CK_ULONG value = *(CK_ULONG *)authAttrs[i].pValue;
- sftk_ULong2SDBULong(authAttrs[i].pValue, value);
- authAttrs[i].ulValueLen = SDB_ULONG_SIZE;
+ if ((authAttr.ulValueLen == -1) || (authAttr.ulValueLen == 0)) {
+ continue;
}
-
- plainText.data = authAttrs[i].pValue;
- plainText.len = authAttrs[i].ulValueLen;
- rv = sftkdb_SignAttribute(arena, newKey, iterationCount, id,
- authAttrs[i].type, &plainText, &signText);
- if (rv != SECSuccess) {
+ authAttr.pValue = PORT_ArenaAlloc(arena, authAttr.ulValueLen);
+ if (authAttr.pValue == NULL) {
+ return CKR_HOST_MEMORY;
+ }
+ rv = sftkdb_GetAttributeValue(handle, id, &authAttr, 1);
+ if (rv != CKR_OK) {
+ return rv;
+ }
+ if ((authAttr.ulValueLen == -1) || (authAttr.ulValueLen == 0)) {
return CKR_GENERAL_ERROR;
}
- rv = sftkdb_PutAttributeSignature(handle, keyTarget, id,
- authAttrs[i].type, signText);
- if (rv != SECSuccess) {
+ // GetAttributeValue just verified the old macs, so it is safe to write
+ // them out now.
+ if (authAttr.ulValueLen == sizeof(CK_ULONG) &&
+ sftkdb_isULONGAttribute(authAttr.type)) {
+ CK_ULONG value = *(CK_ULONG *)authAttr.pValue;
+ sftk_ULong2SDBULong(authAttr.pValue, value);
+ authAttr.ulValueLen = SDB_ULONG_SIZE;
+ }
+ SECItem *signText;
+ SECItem plainText;
+ plainText.data = authAttr.pValue;
+ plainText.len = authAttr.ulValueLen;
+ if (sftkdb_SignAttribute(arena, newKey, iterationCount, id,
+ authAttr.type, &plainText,
+ &signText) != SECSuccess) {
+ return CKR_GENERAL_ERROR;
+ }
+ if (sftkdb_PutAttributeSignature(handle, keyTarget, id, authAttr.type,
+ signText) != SECSuccess) {
return CKR_GENERAL_ERROR;
}
}
@@ -1071,112 +1088,66 @@ static CK_RV
sftk_updateEncrypted(PLArenaPool *arena, SFTKDBHandle *keydb,
CK_OBJECT_HANDLE id, SECItem *newKey, int iterationCount)
{
- CK_RV crv = CKR_OK;
- CK_RV crv2;
- CK_ATTRIBUTE *first, *last;
- CK_ATTRIBUTE privAttrs[] = {
- { CKA_VALUE, NULL, 0 },
- { CKA_PRIVATE_EXPONENT, NULL, 0 },
- { CKA_PRIME_1, NULL, 0 },
- { CKA_PRIME_2, NULL, 0 },
- { CKA_EXPONENT_1, NULL, 0 },
- { CKA_EXPONENT_2, NULL, 0 },
- { CKA_COEFFICIENT, NULL, 0 }
+ CK_ATTRIBUTE_TYPE privAttrTypes[] = {
+ CKA_VALUE,
+ CKA_PRIVATE_EXPONENT,
+ CKA_PRIME_1,
+ CKA_PRIME_2,
+ CKA_EXPONENT_1,
+ CKA_EXPONENT_2,
+ CKA_COEFFICIENT,
};
- CK_ULONG privAttrCount = sizeof(privAttrs) / sizeof(CK_ATTRIBUTE);
- unsigned int i, count;
+ const CK_ULONG privAttrCount = sizeof(privAttrTypes) / sizeof(privAttrTypes[0]);
- /*
- * STEP 1. Read the old attributes in the clear.
- */
-
- /* Get the attribute sizes.
- * ignore the error code, we will have unknown attributes here */
- crv2 = sftkdb_GetAttributeValue(keydb, id, privAttrs, privAttrCount);
-
- /*
- * find the valid block of attributes and fill allocate space for
- * their data */
- first = last = NULL;
+ // We don't know what attributes this object has, so we update them one at a
+ // time.
+ unsigned int i;
for (i = 0; i < privAttrCount; i++) {
- /* find the block of attributes that are appropriate for this
- * objects. There should only be once contiguous block, if not
- * there's an error.
- *
- * find the first and last good entry.
- */
- if ((privAttrs[i].ulValueLen == -1) || (privAttrs[i].ulValueLen == 0)) {
- if (!first)
- continue;
- if (!last) {
- /* previous entry was last good entry */
- last = &privAttrs[i - 1];
- }
+ // Read the old attribute in the clear.
+ CK_ATTRIBUTE privAttr = { privAttrTypes[i], NULL, 0 };
+ CK_RV crv = sftkdb_GetAttributeValue(keydb, id, &privAttr, 1);
+ if (crv != CKR_OK) {
continue;
}
- if (!first) {
- first = &privAttrs[i];
+ if ((privAttr.ulValueLen == -1) || (privAttr.ulValueLen == 0)) {
+ continue;
}
- if (last) {
- /* OOPS, we've found another good entry beyond the end of the
- * last good entry, we need to fail here. */
- crv = CKR_GENERAL_ERROR;
- break;
+ privAttr.pValue = PORT_ArenaAlloc(arena, privAttr.ulValueLen);
+ if (privAttr.pValue == NULL) {
+ return CKR_HOST_MEMORY;
}
- privAttrs[i].pValue = PORT_ArenaAlloc(arena, privAttrs[i].ulValueLen);
- if (privAttrs[i].pValue == NULL) {
- crv = CKR_HOST_MEMORY;
- break;
+ crv = sftkdb_GetAttributeValue(keydb, id, &privAttr, 1);
+ if (crv != CKR_OK) {
+ return crv;
+ }
+ if ((privAttr.ulValueLen == -1) || (privAttr.ulValueLen == 0)) {
+ return CKR_GENERAL_ERROR;
}
- }
- if (first == NULL) {
- /* no valid entries found, return error based on crv2 */
- return crv2;
- }
- if (last == NULL) {
- last = &privAttrs[privAttrCount - 1];
- }
- if (crv != CKR_OK) {
- return crv;
- }
- /* read the attributes */
- count = (last - first) + 1;
- crv = sftkdb_GetAttributeValue(keydb, id, first, count);
- if (crv != CKR_OK) {
- return crv;
- }
-
- /*
- * STEP 2: read the encrypt the attributes with the new key.
- */
- for (i = 0; i < count; i++) {
SECItem plainText;
SECItem *result;
- SECStatus rv;
-
- plainText.data = first[i].pValue;
- plainText.len = first[i].ulValueLen;
- rv = sftkdb_EncryptAttribute(arena, newKey, iterationCount,
- &plainText, &result);
- if (rv != SECSuccess) {
+ plainText.data = privAttr.pValue;
+ plainText.len = privAttr.ulValueLen;
+ if (sftkdb_EncryptAttribute(arena, newKey, iterationCount,
+ &plainText, &result) != SECSuccess) {
return CKR_GENERAL_ERROR;
}
- first[i].pValue = result->data;
- first[i].ulValueLen = result->len;
- /* clear our sensitive data out */
+ privAttr.pValue = result->data;
+ privAttr.ulValueLen = result->len;
+ // Clear sensitive data.
PORT_Memset(plainText.data, 0, plainText.len);
- }
- /*
- * STEP 3: write the newly encrypted attributes out directly
- */
- id &= SFTK_OBJ_ID_MASK;
- keydb->newKey = newKey;
- keydb->newDefaultIterationCount = iterationCount;
- crv = (*keydb->db->sdb_SetAttributeValue)(keydb->db, id, first, count);
- keydb->newKey = NULL;
+ // Write the newly encrypted attributes out directly.
+ CK_OBJECT_HANDLE newId = id & SFTK_OBJ_ID_MASK;
+ keydb->newKey = newKey;
+ keydb->newDefaultIterationCount = iterationCount;
+ crv = (*keydb->db->sdb_SetAttributeValue)(keydb->db, newId, &privAttr, 1);
+ keydb->newKey = NULL;
+ if (crv != CKR_OK) {
+ return crv;
+ }
+ }
- return crv;
+ return CKR_OK;
}
static CK_RV
@@ -1266,7 +1237,7 @@ sftkdb_ChangePassword(SFTKDBHandle *keydb,
SFTKDBHandle *certdb;
unsigned char saltData[SDB_MAX_META_DATA_LEN];
unsigned char valueData[SDB_MAX_META_DATA_LEN];
- int iterationCount = NSS_DEFAULT_ITERATION_COUNT;
+ int iterationCount = getPBEIterationCount();
CK_RV crv;
SDB *db;
@@ -1304,6 +1275,8 @@ sftkdb_ChangePassword(SFTKDBHandle *keydb,
if (newPin && *newPin == 0) {
iterationCount = 1;
+ } else if (keydb->usesLegacyStorage && !sftk_isLegacyIterationCountAllowed()) {
+ iterationCount = 1;
}
rv = sftkdb_passwordToKey(keydb, &salt, newPin, &newKey);
diff --git a/security/nss/lib/softoken/softkver.h b/security/nss/lib/softoken/softkver.h
index 3c1842f6e..fce11cd6d 100644
--- a/security/nss/lib/softoken/softkver.h
+++ b/security/nss/lib/softoken/softkver.h
@@ -17,10 +17,10 @@
* The format of the version string should be
* "<major version>.<minor version>[.<patch level>[.<build number>]][ <ECC>][ <Beta>]"
*/
-#define SOFTOKEN_VERSION "3.41.4" SOFTOKEN_ECC_STRING
+#define SOFTOKEN_VERSION "3.48" SOFTOKEN_ECC_STRING
#define SOFTOKEN_VMAJOR 3
-#define SOFTOKEN_VMINOR 41
-#define SOFTOKEN_VPATCH 4
+#define SOFTOKEN_VMINOR 48
+#define SOFTOKEN_VPATCH 0
#define SOFTOKEN_VBUILD 0
#define SOFTOKEN_BETA PR_FALSE
diff --git a/security/nss/lib/softoken/softoken.gyp b/security/nss/lib/softoken/softoken.gyp
index ba917cfc8..8b6751182 100644
--- a/security/nss/lib/softoken/softoken.gyp
+++ b/security/nss/lib/softoken/softoken.gyp
@@ -10,7 +10,7 @@
'target_name': 'softokn_static',
'type': 'static_library',
'defines': [
- 'NSS_TEST_BUILD',
+ 'NSS_STATIC_SOFTOKEN',
],
'dependencies': [
'softokn_base',
@@ -58,6 +58,7 @@
'sdb.c',
'sftkdb.c',
'sftkhmac.c',
+ 'sftkike.c',
'sftkpars.c',
'sftkpwd.c',
'softkver.c',
diff --git a/security/nss/lib/softoken/tlsprf.c b/security/nss/lib/softoken/tlsprf.c
index 05e246887..b96733b1f 100644
--- a/security/nss/lib/softoken/tlsprf.c
+++ b/security/nss/lib/softoken/tlsprf.c
@@ -129,7 +129,7 @@ sftk_TLSPRFVerify(TLSPRFContext *cx,
}
rv = sftk_TLSPRFUpdate(cx, tmp, &tmpLen, sigLen, NULL, 0);
if (rv == SECSuccess) {
- rv = (SECStatus)(1 - !PORT_Memcmp(tmp, sig, sigLen));
+ rv = (SECStatus)(1 - !NSS_SecureMemcmp(tmp, sig, sigLen));
}
PORT_ZFree(tmp, sigLen);
return rv;