summaryrefslogtreecommitdiffstats
path: root/security/nss/lib/softoken/pkcs11c.c
diff options
context:
space:
mode:
authorwolfbeast <mcwerewolf@wolfbeast.com>2020-01-02 21:06:40 +0100
committerwolfbeast <mcwerewolf@wolfbeast.com>2020-01-02 21:06:40 +0100
commitf4a12fc67689a830e9da1c87fd11afe5bc09deb3 (patch)
tree211ae0cd022a6c11b0026ecc7761a550c584583c /security/nss/lib/softoken/pkcs11c.c
parentf7d30133221896638f7bf4f66c504255c4b14f48 (diff)
downloadUXP-f4a12fc67689a830e9da1c87fd11afe5bc09deb3.tar
UXP-f4a12fc67689a830e9da1c87fd11afe5bc09deb3.tar.gz
UXP-f4a12fc67689a830e9da1c87fd11afe5bc09deb3.tar.lz
UXP-f4a12fc67689a830e9da1c87fd11afe5bc09deb3.tar.xz
UXP-f4a12fc67689a830e9da1c87fd11afe5bc09deb3.zip
Issue #1338 - Part 2: Update NSS to 3.48-RTM
Diffstat (limited to 'security/nss/lib/softoken/pkcs11c.c')
-rw-r--r--security/nss/lib/softoken/pkcs11c.c731
1 files changed, 550 insertions, 181 deletions
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 */