security/nss/lib/softoken/tlsprf.c

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     1 /* tlsprf.c - TLS Pseudo Random Function (PRF) implementation
     2  *
     3  * This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 #include "pkcs11i.h"
     8 #include "blapi.h"
    10 #define SFTK_OFFSETOF(str, memb) ((PRPtrdiff)(&(((str *)0)->memb)))
    12 static void sftk_TLSPRFNull(void *data, PRBool freeit)
    13 {
    14     return;
    15 } 
    17 typedef struct {
    18     PRUint32	   cxSize;	/* size of allocated block, in bytes.        */
    19     PRUint32       cxBufSize;   /* sizeof buffer at cxBufPtr.                */
    20     unsigned char *cxBufPtr;	/* points to real buffer, may be cxBuf.      */
    21     PRUint32	   cxKeyLen;	/* bytes of cxBufPtr containing key.         */
    22     PRUint32	   cxDataLen;	/* bytes of cxBufPtr containing data.        */
    23     SECStatus	   cxRv;	/* records failure of void functions.        */
    24     PRBool	   cxIsFIPS;	/* true if conforming to FIPS 198.           */
    25     HASH_HashType  cxHashAlg;	/* hash algorithm to use for TLS 1.2+        */
    26     unsigned char  cxBuf[512];	/* actual size may be larger than 512.       */
    27 } TLSPRFContext;
    29 static void
    30 sftk_TLSPRFHashUpdate(TLSPRFContext *cx, const unsigned char *data, 
    31                         unsigned int data_len)
    32 {
    33     PRUint32 bytesUsed = cx->cxKeyLen + cx->cxDataLen;
    35     if (cx->cxRv != SECSuccess)	/* function has previously failed. */
    36     	return;
    37     if (bytesUsed + data_len > cx->cxBufSize) {
    38 	/* We don't use realloc here because 
    39 	** (a) realloc doesn't zero out the old block, and 
    40 	** (b) if realloc fails, we lose the old block.
    41 	*/
    42 	PRUint32 newBufSize = bytesUsed + data_len + 512;
    43     	unsigned char * newBuf = (unsigned char *)PORT_Alloc(newBufSize);
    44 	if (!newBuf) {
    45 	   cx->cxRv = SECFailure;
    46 	   return;
    47 	}
    48 	PORT_Memcpy(newBuf, cx->cxBufPtr, bytesUsed);
    49 	if (cx->cxBufPtr != cx->cxBuf) {
    50 	    PORT_ZFree(cx->cxBufPtr, bytesUsed);
    51 	}
    52 	cx->cxBufPtr  = newBuf;
    53 	cx->cxBufSize = newBufSize;
    54     }
    55     PORT_Memcpy(cx->cxBufPtr + bytesUsed, data, data_len);
    56     cx->cxDataLen += data_len;
    57 }
    59 static void 
    60 sftk_TLSPRFEnd(TLSPRFContext *ctx, unsigned char *hashout,
    61 	 unsigned int *pDigestLen, unsigned int maxDigestLen)
    62 {
    63     *pDigestLen = 0; /* tells Verify that no data has been input yet. */
    64 }
    66 /* Compute the PRF values from the data previously input. */
    67 static SECStatus
    68 sftk_TLSPRFUpdate(TLSPRFContext *cx, 
    69                   unsigned char *sig,		/* output goes here. */
    70 		  unsigned int * sigLen, 	/* how much output.  */
    71 		  unsigned int   maxLen, 	/* output buffer size */
    72 		  unsigned char *hash, 		/* unused. */
    73 		  unsigned int   hashLen)	/* unused. */
    74 {
    75     SECStatus rv;
    76     SECItem sigItem;
    77     SECItem seedItem;
    78     SECItem secretItem;
    80     if (cx->cxRv != SECSuccess)
    81     	return cx->cxRv;
    83     secretItem.data = cx->cxBufPtr;
    84     secretItem.len  = cx->cxKeyLen;
    86     seedItem.data = cx->cxBufPtr + cx->cxKeyLen;
    87     seedItem.len  = cx->cxDataLen;
    89     sigItem.data = sig;
    90     sigItem.len  = maxLen;
    92     if (cx->cxHashAlg != HASH_AlgNULL) {
    93 	rv = TLS_P_hash(cx->cxHashAlg, &secretItem, NULL, &seedItem, &sigItem,
    94 			cx->cxIsFIPS);
    95     } else {
    96 	rv = TLS_PRF(&secretItem, NULL, &seedItem, &sigItem, cx->cxIsFIPS);
    97     }
    98     if (rv == SECSuccess && sigLen != NULL)
    99     	*sigLen = sigItem.len;
   100     return rv;
   102 }
   104 static SECStatus
   105 sftk_TLSPRFVerify(TLSPRFContext *cx, 
   106                   unsigned char *sig, 		/* input, for comparison. */
   107 		  unsigned int   sigLen,	/* length of sig.         */
   108 		  unsigned char *hash, 		/* data to be verified.   */
   109 		  unsigned int   hashLen)	/* size of hash data.     */
   110 {
   111     unsigned char * tmp    = (unsigned char *)PORT_Alloc(sigLen);
   112     unsigned int    tmpLen = sigLen;
   113     SECStatus       rv;
   115     if (!tmp)
   116     	return SECFailure;
   117     if (hashLen) {
   118     	/* hashLen is non-zero when the user does a one-step verify.
   119 	** In this case, none of the data has been input yet.
   120 	*/
   121     	sftk_TLSPRFHashUpdate(cx, hash, hashLen);
   122     }
   123     rv = sftk_TLSPRFUpdate(cx, tmp, &tmpLen, sigLen, NULL, 0);
   124     if (rv == SECSuccess) {
   125     	rv = (SECStatus)(1 - !PORT_Memcmp(tmp, sig, sigLen));
   126     }
   127     PORT_ZFree(tmp, sigLen);
   128     return rv;
   129 }
   131 static void
   132 sftk_TLSPRFHashDestroy(TLSPRFContext *cx, PRBool freeit)
   133 {
   134     if (freeit) {
   135 	if (cx->cxBufPtr != cx->cxBuf) 
   136 	    PORT_ZFree(cx->cxBufPtr, cx->cxBufSize);
   137 	PORT_ZFree(cx, cx->cxSize);
   138     }
   139 }
   141 CK_RV
   142 sftk_TLSPRFInit(SFTKSessionContext *context, 
   143 		  SFTKObject *        key, 
   144 		  CK_KEY_TYPE         key_type,
   145 		  HASH_HashType       hash_alg)
   146 {
   147     SFTKAttribute * keyVal;
   148     TLSPRFContext * prf_cx;
   149     CK_RV           crv = CKR_HOST_MEMORY;
   150     PRUint32        keySize;
   151     PRUint32        blockSize;
   153     if (key_type != CKK_GENERIC_SECRET)
   154     	return CKR_KEY_TYPE_INCONSISTENT; /* CKR_KEY_FUNCTION_NOT_PERMITTED */
   156     context->multi = PR_TRUE;
   158     keyVal = sftk_FindAttribute(key, CKA_VALUE);
   159     keySize = (!keyVal) ? 0 : keyVal->attrib.ulValueLen;
   160     blockSize = keySize + sizeof(TLSPRFContext);
   161     prf_cx = (TLSPRFContext *)PORT_Alloc(blockSize);
   162     if (!prf_cx) 
   163     	goto done;
   164     prf_cx->cxSize    = blockSize;
   165     prf_cx->cxKeyLen  = keySize;
   166     prf_cx->cxDataLen = 0;
   167     prf_cx->cxBufSize = blockSize - SFTK_OFFSETOF(TLSPRFContext, cxBuf);
   168     prf_cx->cxRv      = SECSuccess;
   169     prf_cx->cxIsFIPS  = (key->slot->slotID == FIPS_SLOT_ID);
   170     prf_cx->cxBufPtr  = prf_cx->cxBuf;
   171     prf_cx->cxHashAlg = hash_alg;
   172     if (keySize)
   173 	PORT_Memcpy(prf_cx->cxBufPtr, keyVal->attrib.pValue, keySize);
   175     context->hashInfo    = (void *) prf_cx;
   176     context->cipherInfo  = (void *) prf_cx;
   177     context->hashUpdate  = (SFTKHash)    sftk_TLSPRFHashUpdate;
   178     context->end         = (SFTKEnd)     sftk_TLSPRFEnd;
   179     context->update      = (SFTKCipher)  sftk_TLSPRFUpdate;
   180     context->verify      = (SFTKVerify)  sftk_TLSPRFVerify;
   181     context->destroy     = (SFTKDestroy) sftk_TLSPRFNull;
   182     context->hashdestroy = (SFTKDestroy) sftk_TLSPRFHashDestroy;
   183     crv = CKR_OK;
   185 done:
   186     if (keyVal) 
   187 	sftk_FreeAttribute(keyVal);
   188     return crv;
   189 }

mercurial