security/nss/lib/softoken/tlsprf.c

changeset 0
6474c204b198
     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 +

mercurial