mirror of
https://github.com/rn10950/RetroZilla.git
synced 2024-11-14 03:30:17 +01:00
44b7f056d9
bug1001332, 56b691c003ad, bug1086145, bug1054069, bug1155922, bug991783, bug1125025, bug1162521, bug1162644, bug1132941, bug1164364, bug1166205, bug1166163, bug1166515, bug1138554, bug1167046, bug1167043, bug1169451, bug1172128, bug1170322, bug102794, bug1128184, bug557830, bug1174648, bug1180244, bug1177784, bug1173413, bug1169174, bug1084669, bug951455, bug1183395, bug1177430, bug1183827, bug1160139, bug1154106, bug1142209, bug1185033, bug1193467, bug1182667(with sha512 changes backed out, which breaks VC6 compilation), bug1158489, bug337796
202 lines
6.2 KiB
C
202 lines
6.2 KiB
C
/* tlsprf.c - TLS Pseudo Random Function (PRF) implementation
|
|
*
|
|
* 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/. */
|
|
|
|
#include "pkcs11i.h"
|
|
#include "blapi.h"
|
|
#include "secerr.h"
|
|
|
|
#define SFTK_OFFSETOF(str, memb) ((PRPtrdiff)(&(((str *)0)->memb)))
|
|
|
|
static void sftk_TLSPRFNull(void *data, PRBool freeit)
|
|
{
|
|
return;
|
|
}
|
|
|
|
typedef struct {
|
|
PRUint32 cxSize; /* size of allocated block, in bytes. */
|
|
PRUint32 cxBufSize; /* sizeof buffer at cxBufPtr. */
|
|
unsigned char *cxBufPtr; /* points to real buffer, may be cxBuf. */
|
|
PRUint32 cxKeyLen; /* bytes of cxBufPtr containing key. */
|
|
PRUint32 cxDataLen; /* bytes of cxBufPtr containing data. */
|
|
SECStatus cxRv; /* records failure of void functions. */
|
|
PRBool cxIsFIPS; /* true if conforming to FIPS 198. */
|
|
HASH_HashType cxHashAlg; /* hash algorithm to use for TLS 1.2+ */
|
|
unsigned int cxOutLen; /* bytes of output if nonzero */
|
|
unsigned char cxBuf[512]; /* actual size may be larger than 512. */
|
|
} TLSPRFContext;
|
|
|
|
static void
|
|
sftk_TLSPRFHashUpdate(TLSPRFContext *cx, const unsigned char *data,
|
|
unsigned int data_len)
|
|
{
|
|
PRUint32 bytesUsed = cx->cxKeyLen + cx->cxDataLen;
|
|
|
|
if (cx->cxRv != SECSuccess) /* function has previously failed. */
|
|
return;
|
|
if (bytesUsed + data_len > cx->cxBufSize) {
|
|
/* We don't use realloc here because
|
|
** (a) realloc doesn't zero out the old block, and
|
|
** (b) if realloc fails, we lose the old block.
|
|
*/
|
|
PRUint32 newBufSize = bytesUsed + data_len + 512;
|
|
unsigned char * newBuf = (unsigned char *)PORT_Alloc(newBufSize);
|
|
if (!newBuf) {
|
|
cx->cxRv = SECFailure;
|
|
return;
|
|
}
|
|
PORT_Memcpy(newBuf, cx->cxBufPtr, bytesUsed);
|
|
if (cx->cxBufPtr != cx->cxBuf) {
|
|
PORT_ZFree(cx->cxBufPtr, bytesUsed);
|
|
}
|
|
cx->cxBufPtr = newBuf;
|
|
cx->cxBufSize = newBufSize;
|
|
}
|
|
PORT_Memcpy(cx->cxBufPtr + bytesUsed, data, data_len);
|
|
cx->cxDataLen += data_len;
|
|
}
|
|
|
|
static void
|
|
sftk_TLSPRFEnd(TLSPRFContext *ctx, unsigned char *hashout,
|
|
unsigned int *pDigestLen, unsigned int maxDigestLen)
|
|
{
|
|
*pDigestLen = 0; /* tells Verify that no data has been input yet. */
|
|
}
|
|
|
|
/* Compute the PRF values from the data previously input. */
|
|
static SECStatus
|
|
sftk_TLSPRFUpdate(TLSPRFContext *cx,
|
|
unsigned char *sig, /* output goes here. */
|
|
unsigned int * sigLen, /* how much output. */
|
|
unsigned int maxLen, /* output buffer size */
|
|
unsigned char *hash, /* unused. */
|
|
unsigned int hashLen) /* unused. */
|
|
{
|
|
SECStatus rv;
|
|
SECItem sigItem;
|
|
SECItem seedItem;
|
|
SECItem secretItem;
|
|
|
|
if (cx->cxRv != SECSuccess)
|
|
return cx->cxRv;
|
|
|
|
secretItem.data = cx->cxBufPtr;
|
|
secretItem.len = cx->cxKeyLen;
|
|
|
|
seedItem.data = cx->cxBufPtr + cx->cxKeyLen;
|
|
seedItem.len = cx->cxDataLen;
|
|
|
|
sigItem.data = sig;
|
|
if (cx->cxOutLen == 0) {
|
|
sigItem.len = maxLen;
|
|
} else if (cx->cxOutLen <= maxLen) {
|
|
sigItem.len = cx->cxOutLen;
|
|
} else {
|
|
PORT_SetError(SEC_ERROR_OUTPUT_LEN);
|
|
return SECFailure;
|
|
}
|
|
|
|
if (cx->cxHashAlg != HASH_AlgNULL) {
|
|
rv = TLS_P_hash(cx->cxHashAlg, &secretItem, NULL, &seedItem, &sigItem,
|
|
cx->cxIsFIPS);
|
|
} else {
|
|
rv = TLS_PRF(&secretItem, NULL, &seedItem, &sigItem, cx->cxIsFIPS);
|
|
}
|
|
if (rv == SECSuccess && sigLen != NULL)
|
|
*sigLen = sigItem.len;
|
|
return rv;
|
|
|
|
}
|
|
|
|
static SECStatus
|
|
sftk_TLSPRFVerify(TLSPRFContext *cx,
|
|
unsigned char *sig, /* input, for comparison. */
|
|
unsigned int sigLen, /* length of sig. */
|
|
unsigned char *hash, /* data to be verified. */
|
|
unsigned int hashLen) /* size of hash data. */
|
|
{
|
|
unsigned char * tmp = (unsigned char *)PORT_Alloc(sigLen);
|
|
unsigned int tmpLen = sigLen;
|
|
SECStatus rv;
|
|
|
|
if (!tmp)
|
|
return SECFailure;
|
|
if (hashLen) {
|
|
/* hashLen is non-zero when the user does a one-step verify.
|
|
** In this case, none of the data has been input yet.
|
|
*/
|
|
sftk_TLSPRFHashUpdate(cx, hash, hashLen);
|
|
}
|
|
rv = sftk_TLSPRFUpdate(cx, tmp, &tmpLen, sigLen, NULL, 0);
|
|
if (rv == SECSuccess) {
|
|
rv = (SECStatus)(1 - !PORT_Memcmp(tmp, sig, sigLen));
|
|
}
|
|
PORT_ZFree(tmp, sigLen);
|
|
return rv;
|
|
}
|
|
|
|
static void
|
|
sftk_TLSPRFHashDestroy(TLSPRFContext *cx, PRBool freeit)
|
|
{
|
|
if (freeit) {
|
|
if (cx->cxBufPtr != cx->cxBuf)
|
|
PORT_ZFree(cx->cxBufPtr, cx->cxBufSize);
|
|
PORT_ZFree(cx, cx->cxSize);
|
|
}
|
|
}
|
|
|
|
CK_RV
|
|
sftk_TLSPRFInit(SFTKSessionContext *context,
|
|
SFTKObject * key,
|
|
CK_KEY_TYPE key_type,
|
|
HASH_HashType hash_alg,
|
|
unsigned int out_len)
|
|
{
|
|
SFTKAttribute * keyVal;
|
|
TLSPRFContext * prf_cx;
|
|
CK_RV crv = CKR_HOST_MEMORY;
|
|
PRUint32 keySize;
|
|
PRUint32 blockSize;
|
|
|
|
if (key_type != CKK_GENERIC_SECRET)
|
|
return CKR_KEY_TYPE_INCONSISTENT; /* CKR_KEY_FUNCTION_NOT_PERMITTED */
|
|
|
|
context->multi = PR_TRUE;
|
|
|
|
keyVal = sftk_FindAttribute(key, CKA_VALUE);
|
|
keySize = (!keyVal) ? 0 : keyVal->attrib.ulValueLen;
|
|
blockSize = keySize + sizeof(TLSPRFContext);
|
|
prf_cx = (TLSPRFContext *)PORT_Alloc(blockSize);
|
|
if (!prf_cx)
|
|
goto done;
|
|
prf_cx->cxSize = blockSize;
|
|
prf_cx->cxKeyLen = keySize;
|
|
prf_cx->cxDataLen = 0;
|
|
prf_cx->cxBufSize = blockSize - SFTK_OFFSETOF(TLSPRFContext, cxBuf);
|
|
prf_cx->cxRv = SECSuccess;
|
|
prf_cx->cxIsFIPS = (key->slot->slotID == FIPS_SLOT_ID);
|
|
prf_cx->cxBufPtr = prf_cx->cxBuf;
|
|
prf_cx->cxHashAlg = hash_alg;
|
|
prf_cx->cxOutLen = out_len;
|
|
if (keySize)
|
|
PORT_Memcpy(prf_cx->cxBufPtr, keyVal->attrib.pValue, keySize);
|
|
|
|
context->hashInfo = (void *) prf_cx;
|
|
context->cipherInfo = (void *) prf_cx;
|
|
context->hashUpdate = (SFTKHash) sftk_TLSPRFHashUpdate;
|
|
context->end = (SFTKEnd) sftk_TLSPRFEnd;
|
|
context->update = (SFTKCipher) sftk_TLSPRFUpdate;
|
|
context->verify = (SFTKVerify) sftk_TLSPRFVerify;
|
|
context->destroy = (SFTKDestroy) sftk_TLSPRFNull;
|
|
context->hashdestroy = (SFTKDestroy) sftk_TLSPRFHashDestroy;
|
|
crv = CKR_OK;
|
|
|
|
done:
|
|
if (keyVal)
|
|
sftk_FreeAttribute(keyVal);
|
|
return crv;
|
|
}
|
|
|