1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/nss/lib/softoken/tlsprf.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,190 @@ 1.4 +/* tlsprf.c - TLS Pseudo Random Function (PRF) implementation 1.5 + * 1.6 + * This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#include "pkcs11i.h" 1.11 +#include "blapi.h" 1.12 + 1.13 +#define SFTK_OFFSETOF(str, memb) ((PRPtrdiff)(&(((str *)0)->memb))) 1.14 + 1.15 +static void sftk_TLSPRFNull(void *data, PRBool freeit) 1.16 +{ 1.17 + return; 1.18 +} 1.19 + 1.20 +typedef struct { 1.21 + PRUint32 cxSize; /* size of allocated block, in bytes. */ 1.22 + PRUint32 cxBufSize; /* sizeof buffer at cxBufPtr. */ 1.23 + unsigned char *cxBufPtr; /* points to real buffer, may be cxBuf. */ 1.24 + PRUint32 cxKeyLen; /* bytes of cxBufPtr containing key. */ 1.25 + PRUint32 cxDataLen; /* bytes of cxBufPtr containing data. */ 1.26 + SECStatus cxRv; /* records failure of void functions. */ 1.27 + PRBool cxIsFIPS; /* true if conforming to FIPS 198. */ 1.28 + HASH_HashType cxHashAlg; /* hash algorithm to use for TLS 1.2+ */ 1.29 + unsigned char cxBuf[512]; /* actual size may be larger than 512. */ 1.30 +} TLSPRFContext; 1.31 + 1.32 +static void 1.33 +sftk_TLSPRFHashUpdate(TLSPRFContext *cx, const unsigned char *data, 1.34 + unsigned int data_len) 1.35 +{ 1.36 + PRUint32 bytesUsed = cx->cxKeyLen + cx->cxDataLen; 1.37 + 1.38 + if (cx->cxRv != SECSuccess) /* function has previously failed. */ 1.39 + return; 1.40 + if (bytesUsed + data_len > cx->cxBufSize) { 1.41 + /* We don't use realloc here because 1.42 + ** (a) realloc doesn't zero out the old block, and 1.43 + ** (b) if realloc fails, we lose the old block. 1.44 + */ 1.45 + PRUint32 newBufSize = bytesUsed + data_len + 512; 1.46 + unsigned char * newBuf = (unsigned char *)PORT_Alloc(newBufSize); 1.47 + if (!newBuf) { 1.48 + cx->cxRv = SECFailure; 1.49 + return; 1.50 + } 1.51 + PORT_Memcpy(newBuf, cx->cxBufPtr, bytesUsed); 1.52 + if (cx->cxBufPtr != cx->cxBuf) { 1.53 + PORT_ZFree(cx->cxBufPtr, bytesUsed); 1.54 + } 1.55 + cx->cxBufPtr = newBuf; 1.56 + cx->cxBufSize = newBufSize; 1.57 + } 1.58 + PORT_Memcpy(cx->cxBufPtr + bytesUsed, data, data_len); 1.59 + cx->cxDataLen += data_len; 1.60 +} 1.61 + 1.62 +static void 1.63 +sftk_TLSPRFEnd(TLSPRFContext *ctx, unsigned char *hashout, 1.64 + unsigned int *pDigestLen, unsigned int maxDigestLen) 1.65 +{ 1.66 + *pDigestLen = 0; /* tells Verify that no data has been input yet. */ 1.67 +} 1.68 + 1.69 +/* Compute the PRF values from the data previously input. */ 1.70 +static SECStatus 1.71 +sftk_TLSPRFUpdate(TLSPRFContext *cx, 1.72 + unsigned char *sig, /* output goes here. */ 1.73 + unsigned int * sigLen, /* how much output. */ 1.74 + unsigned int maxLen, /* output buffer size */ 1.75 + unsigned char *hash, /* unused. */ 1.76 + unsigned int hashLen) /* unused. */ 1.77 +{ 1.78 + SECStatus rv; 1.79 + SECItem sigItem; 1.80 + SECItem seedItem; 1.81 + SECItem secretItem; 1.82 + 1.83 + if (cx->cxRv != SECSuccess) 1.84 + return cx->cxRv; 1.85 + 1.86 + secretItem.data = cx->cxBufPtr; 1.87 + secretItem.len = cx->cxKeyLen; 1.88 + 1.89 + seedItem.data = cx->cxBufPtr + cx->cxKeyLen; 1.90 + seedItem.len = cx->cxDataLen; 1.91 + 1.92 + sigItem.data = sig; 1.93 + sigItem.len = maxLen; 1.94 + 1.95 + if (cx->cxHashAlg != HASH_AlgNULL) { 1.96 + rv = TLS_P_hash(cx->cxHashAlg, &secretItem, NULL, &seedItem, &sigItem, 1.97 + cx->cxIsFIPS); 1.98 + } else { 1.99 + rv = TLS_PRF(&secretItem, NULL, &seedItem, &sigItem, cx->cxIsFIPS); 1.100 + } 1.101 + if (rv == SECSuccess && sigLen != NULL) 1.102 + *sigLen = sigItem.len; 1.103 + return rv; 1.104 + 1.105 +} 1.106 + 1.107 +static SECStatus 1.108 +sftk_TLSPRFVerify(TLSPRFContext *cx, 1.109 + unsigned char *sig, /* input, for comparison. */ 1.110 + unsigned int sigLen, /* length of sig. */ 1.111 + unsigned char *hash, /* data to be verified. */ 1.112 + unsigned int hashLen) /* size of hash data. */ 1.113 +{ 1.114 + unsigned char * tmp = (unsigned char *)PORT_Alloc(sigLen); 1.115 + unsigned int tmpLen = sigLen; 1.116 + SECStatus rv; 1.117 + 1.118 + if (!tmp) 1.119 + return SECFailure; 1.120 + if (hashLen) { 1.121 + /* hashLen is non-zero when the user does a one-step verify. 1.122 + ** In this case, none of the data has been input yet. 1.123 + */ 1.124 + sftk_TLSPRFHashUpdate(cx, hash, hashLen); 1.125 + } 1.126 + rv = sftk_TLSPRFUpdate(cx, tmp, &tmpLen, sigLen, NULL, 0); 1.127 + if (rv == SECSuccess) { 1.128 + rv = (SECStatus)(1 - !PORT_Memcmp(tmp, sig, sigLen)); 1.129 + } 1.130 + PORT_ZFree(tmp, sigLen); 1.131 + return rv; 1.132 +} 1.133 + 1.134 +static void 1.135 +sftk_TLSPRFHashDestroy(TLSPRFContext *cx, PRBool freeit) 1.136 +{ 1.137 + if (freeit) { 1.138 + if (cx->cxBufPtr != cx->cxBuf) 1.139 + PORT_ZFree(cx->cxBufPtr, cx->cxBufSize); 1.140 + PORT_ZFree(cx, cx->cxSize); 1.141 + } 1.142 +} 1.143 + 1.144 +CK_RV 1.145 +sftk_TLSPRFInit(SFTKSessionContext *context, 1.146 + SFTKObject * key, 1.147 + CK_KEY_TYPE key_type, 1.148 + HASH_HashType hash_alg) 1.149 +{ 1.150 + SFTKAttribute * keyVal; 1.151 + TLSPRFContext * prf_cx; 1.152 + CK_RV crv = CKR_HOST_MEMORY; 1.153 + PRUint32 keySize; 1.154 + PRUint32 blockSize; 1.155 + 1.156 + if (key_type != CKK_GENERIC_SECRET) 1.157 + return CKR_KEY_TYPE_INCONSISTENT; /* CKR_KEY_FUNCTION_NOT_PERMITTED */ 1.158 + 1.159 + context->multi = PR_TRUE; 1.160 + 1.161 + keyVal = sftk_FindAttribute(key, CKA_VALUE); 1.162 + keySize = (!keyVal) ? 0 : keyVal->attrib.ulValueLen; 1.163 + blockSize = keySize + sizeof(TLSPRFContext); 1.164 + prf_cx = (TLSPRFContext *)PORT_Alloc(blockSize); 1.165 + if (!prf_cx) 1.166 + goto done; 1.167 + prf_cx->cxSize = blockSize; 1.168 + prf_cx->cxKeyLen = keySize; 1.169 + prf_cx->cxDataLen = 0; 1.170 + prf_cx->cxBufSize = blockSize - SFTK_OFFSETOF(TLSPRFContext, cxBuf); 1.171 + prf_cx->cxRv = SECSuccess; 1.172 + prf_cx->cxIsFIPS = (key->slot->slotID == FIPS_SLOT_ID); 1.173 + prf_cx->cxBufPtr = prf_cx->cxBuf; 1.174 + prf_cx->cxHashAlg = hash_alg; 1.175 + if (keySize) 1.176 + PORT_Memcpy(prf_cx->cxBufPtr, keyVal->attrib.pValue, keySize); 1.177 + 1.178 + context->hashInfo = (void *) prf_cx; 1.179 + context->cipherInfo = (void *) prf_cx; 1.180 + context->hashUpdate = (SFTKHash) sftk_TLSPRFHashUpdate; 1.181 + context->end = (SFTKEnd) sftk_TLSPRFEnd; 1.182 + context->update = (SFTKCipher) sftk_TLSPRFUpdate; 1.183 + context->verify = (SFTKVerify) sftk_TLSPRFVerify; 1.184 + context->destroy = (SFTKDestroy) sftk_TLSPRFNull; 1.185 + context->hashdestroy = (SFTKDestroy) sftk_TLSPRFHashDestroy; 1.186 + crv = CKR_OK; 1.187 + 1.188 +done: 1.189 + if (keyVal) 1.190 + sftk_FreeAttribute(keyVal); 1.191 + return crv; 1.192 +} 1.193 +