security/nss/lib/freebl/tlsprfalg.c

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/security/nss/lib/freebl/tlsprfalg.c	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,136 @@
     1.4 +/* tlsprfalg.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 +#ifdef FREEBL_NO_DEPEND
    1.11 +#include "stubs.h"
    1.12 +#endif
    1.13 +
    1.14 +#include "blapi.h"
    1.15 +#include "hasht.h"
    1.16 +#include "alghmac.h"
    1.17 +
    1.18 +
    1.19 +#define PHASH_STATE_MAX_LEN HASH_LENGTH_MAX
    1.20 +
    1.21 +/* TLS P_hash function */
    1.22 +SECStatus
    1.23 +TLS_P_hash(HASH_HashType hashType, const SECItem *secret, const char *label, 
    1.24 +	SECItem *seed, SECItem *result, PRBool isFIPS)
    1.25 +{
    1.26 +    unsigned char state[PHASH_STATE_MAX_LEN];
    1.27 +    unsigned char outbuf[PHASH_STATE_MAX_LEN];
    1.28 +    unsigned int state_len = 0, label_len = 0, outbuf_len = 0, chunk_size;
    1.29 +    unsigned int remaining;
    1.30 +    unsigned char *res;
    1.31 +    SECStatus status;
    1.32 +    HMACContext *cx;
    1.33 +    SECStatus rv = SECFailure;
    1.34 +    const SECHashObject *hashObj = HASH_GetRawHashObject(hashType);
    1.35 +
    1.36 +    PORT_Assert((secret != NULL) && (secret->data != NULL || !secret->len));
    1.37 +    PORT_Assert((seed != NULL) && (seed->data != NULL));
    1.38 +    PORT_Assert((result != NULL) && (result->data != NULL));
    1.39 +
    1.40 +    remaining = result->len;
    1.41 +    res = result->data;
    1.42 +
    1.43 +    if (label != NULL)
    1.44 +	label_len = PORT_Strlen(label);
    1.45 +
    1.46 +    cx = HMAC_Create(hashObj, secret->data, secret->len, isFIPS);
    1.47 +    if (cx == NULL)
    1.48 +	goto loser;
    1.49 +
    1.50 +    /* initialize the state = A(1) = HMAC_hash(secret, seed) */
    1.51 +    HMAC_Begin(cx);
    1.52 +    HMAC_Update(cx, (unsigned char *)label, label_len);
    1.53 +    HMAC_Update(cx, seed->data, seed->len);
    1.54 +    status = HMAC_Finish(cx, state, &state_len, sizeof(state));
    1.55 +    if (status != SECSuccess)
    1.56 +	goto loser;
    1.57 +
    1.58 +    /* generate a block at a time until we're done */
    1.59 +    while (remaining > 0) {
    1.60 +
    1.61 +	HMAC_Begin(cx);
    1.62 +	HMAC_Update(cx, state, state_len);
    1.63 +	if (label_len)
    1.64 +	    HMAC_Update(cx, (unsigned char *)label, label_len);
    1.65 +	HMAC_Update(cx, seed->data, seed->len);
    1.66 +	status = HMAC_Finish(cx, outbuf, &outbuf_len, sizeof(outbuf));
    1.67 +	if (status != SECSuccess)
    1.68 +	    goto loser;
    1.69 +
    1.70 +        /* Update the state = A(i) = HMAC_hash(secret, A(i-1)) */
    1.71 +	HMAC_Begin(cx); 
    1.72 +	HMAC_Update(cx, state, state_len); 
    1.73 +	status = HMAC_Finish(cx, state, &state_len, sizeof(state));
    1.74 +	if (status != SECSuccess)
    1.75 +	    goto loser;
    1.76 +
    1.77 +	chunk_size = PR_MIN(outbuf_len, remaining);
    1.78 +	PORT_Memcpy(res, &outbuf, chunk_size);
    1.79 +	res += chunk_size;
    1.80 +	remaining -= chunk_size;
    1.81 +    }
    1.82 +
    1.83 +    rv = SECSuccess;
    1.84 +
    1.85 +loser:
    1.86 +    /* clear out state so it's not left on the stack */
    1.87 +    if (cx) 
    1.88 +    	HMAC_Destroy(cx, PR_TRUE);
    1.89 +    PORT_Memset(state, 0, sizeof(state));
    1.90 +    PORT_Memset(outbuf, 0, sizeof(outbuf));
    1.91 +    return rv;
    1.92 +}
    1.93 +
    1.94 +SECStatus
    1.95 +TLS_PRF(const SECItem *secret, const char *label, SECItem *seed, 
    1.96 +         SECItem *result, PRBool isFIPS)
    1.97 +{
    1.98 +    SECStatus rv = SECFailure, status;
    1.99 +    unsigned int i;
   1.100 +    SECItem tmp = { siBuffer, NULL, 0};
   1.101 +    SECItem S1;
   1.102 +    SECItem S2;
   1.103 +
   1.104 +    PORT_Assert((secret != NULL) && (secret->data != NULL || !secret->len));
   1.105 +    PORT_Assert((seed != NULL) && (seed->data != NULL));
   1.106 +    PORT_Assert((result != NULL) && (result->data != NULL));
   1.107 +
   1.108 +    S1.type = siBuffer;
   1.109 +    S1.len  = (secret->len / 2) + (secret->len & 1);
   1.110 +    S1.data = secret->data;
   1.111 +
   1.112 +    S2.type = siBuffer;
   1.113 +    S2.len  = S1.len;
   1.114 +    S2.data = secret->data + (secret->len - S2.len);
   1.115 +
   1.116 +    tmp.data = (unsigned char*)PORT_Alloc(result->len);
   1.117 +    if (tmp.data == NULL)
   1.118 +	goto loser;
   1.119 +    tmp.len = result->len;
   1.120 +
   1.121 +    status = TLS_P_hash(HASH_AlgMD5, &S1, label, seed, result, isFIPS);
   1.122 +    if (status != SECSuccess)
   1.123 +	goto loser;
   1.124 +
   1.125 +    status = TLS_P_hash(HASH_AlgSHA1, &S2, label, seed, &tmp, isFIPS);
   1.126 +    if (status != SECSuccess)
   1.127 +	goto loser;
   1.128 +
   1.129 +    for (i = 0; i < result->len; i++)
   1.130 +	result->data[i] ^= tmp.data[i];
   1.131 +
   1.132 +    rv = SECSuccess;
   1.133 +
   1.134 +loser:
   1.135 +    if (tmp.data != NULL)
   1.136 +	PORT_ZFree(tmp.data, tmp.len);
   1.137 +    return rv;
   1.138 +}
   1.139 +

mercurial