security/nss/lib/freebl/tlsprfalg.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

michael@0 1 /* tlsprfalg.c - TLS Pseudo Random Function (PRF) implementation
michael@0 2 *
michael@0 3 * This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 #ifdef FREEBL_NO_DEPEND
michael@0 8 #include "stubs.h"
michael@0 9 #endif
michael@0 10
michael@0 11 #include "blapi.h"
michael@0 12 #include "hasht.h"
michael@0 13 #include "alghmac.h"
michael@0 14
michael@0 15
michael@0 16 #define PHASH_STATE_MAX_LEN HASH_LENGTH_MAX
michael@0 17
michael@0 18 /* TLS P_hash function */
michael@0 19 SECStatus
michael@0 20 TLS_P_hash(HASH_HashType hashType, const SECItem *secret, const char *label,
michael@0 21 SECItem *seed, SECItem *result, PRBool isFIPS)
michael@0 22 {
michael@0 23 unsigned char state[PHASH_STATE_MAX_LEN];
michael@0 24 unsigned char outbuf[PHASH_STATE_MAX_LEN];
michael@0 25 unsigned int state_len = 0, label_len = 0, outbuf_len = 0, chunk_size;
michael@0 26 unsigned int remaining;
michael@0 27 unsigned char *res;
michael@0 28 SECStatus status;
michael@0 29 HMACContext *cx;
michael@0 30 SECStatus rv = SECFailure;
michael@0 31 const SECHashObject *hashObj = HASH_GetRawHashObject(hashType);
michael@0 32
michael@0 33 PORT_Assert((secret != NULL) && (secret->data != NULL || !secret->len));
michael@0 34 PORT_Assert((seed != NULL) && (seed->data != NULL));
michael@0 35 PORT_Assert((result != NULL) && (result->data != NULL));
michael@0 36
michael@0 37 remaining = result->len;
michael@0 38 res = result->data;
michael@0 39
michael@0 40 if (label != NULL)
michael@0 41 label_len = PORT_Strlen(label);
michael@0 42
michael@0 43 cx = HMAC_Create(hashObj, secret->data, secret->len, isFIPS);
michael@0 44 if (cx == NULL)
michael@0 45 goto loser;
michael@0 46
michael@0 47 /* initialize the state = A(1) = HMAC_hash(secret, seed) */
michael@0 48 HMAC_Begin(cx);
michael@0 49 HMAC_Update(cx, (unsigned char *)label, label_len);
michael@0 50 HMAC_Update(cx, seed->data, seed->len);
michael@0 51 status = HMAC_Finish(cx, state, &state_len, sizeof(state));
michael@0 52 if (status != SECSuccess)
michael@0 53 goto loser;
michael@0 54
michael@0 55 /* generate a block at a time until we're done */
michael@0 56 while (remaining > 0) {
michael@0 57
michael@0 58 HMAC_Begin(cx);
michael@0 59 HMAC_Update(cx, state, state_len);
michael@0 60 if (label_len)
michael@0 61 HMAC_Update(cx, (unsigned char *)label, label_len);
michael@0 62 HMAC_Update(cx, seed->data, seed->len);
michael@0 63 status = HMAC_Finish(cx, outbuf, &outbuf_len, sizeof(outbuf));
michael@0 64 if (status != SECSuccess)
michael@0 65 goto loser;
michael@0 66
michael@0 67 /* Update the state = A(i) = HMAC_hash(secret, A(i-1)) */
michael@0 68 HMAC_Begin(cx);
michael@0 69 HMAC_Update(cx, state, state_len);
michael@0 70 status = HMAC_Finish(cx, state, &state_len, sizeof(state));
michael@0 71 if (status != SECSuccess)
michael@0 72 goto loser;
michael@0 73
michael@0 74 chunk_size = PR_MIN(outbuf_len, remaining);
michael@0 75 PORT_Memcpy(res, &outbuf, chunk_size);
michael@0 76 res += chunk_size;
michael@0 77 remaining -= chunk_size;
michael@0 78 }
michael@0 79
michael@0 80 rv = SECSuccess;
michael@0 81
michael@0 82 loser:
michael@0 83 /* clear out state so it's not left on the stack */
michael@0 84 if (cx)
michael@0 85 HMAC_Destroy(cx, PR_TRUE);
michael@0 86 PORT_Memset(state, 0, sizeof(state));
michael@0 87 PORT_Memset(outbuf, 0, sizeof(outbuf));
michael@0 88 return rv;
michael@0 89 }
michael@0 90
michael@0 91 SECStatus
michael@0 92 TLS_PRF(const SECItem *secret, const char *label, SECItem *seed,
michael@0 93 SECItem *result, PRBool isFIPS)
michael@0 94 {
michael@0 95 SECStatus rv = SECFailure, status;
michael@0 96 unsigned int i;
michael@0 97 SECItem tmp = { siBuffer, NULL, 0};
michael@0 98 SECItem S1;
michael@0 99 SECItem S2;
michael@0 100
michael@0 101 PORT_Assert((secret != NULL) && (secret->data != NULL || !secret->len));
michael@0 102 PORT_Assert((seed != NULL) && (seed->data != NULL));
michael@0 103 PORT_Assert((result != NULL) && (result->data != NULL));
michael@0 104
michael@0 105 S1.type = siBuffer;
michael@0 106 S1.len = (secret->len / 2) + (secret->len & 1);
michael@0 107 S1.data = secret->data;
michael@0 108
michael@0 109 S2.type = siBuffer;
michael@0 110 S2.len = S1.len;
michael@0 111 S2.data = secret->data + (secret->len - S2.len);
michael@0 112
michael@0 113 tmp.data = (unsigned char*)PORT_Alloc(result->len);
michael@0 114 if (tmp.data == NULL)
michael@0 115 goto loser;
michael@0 116 tmp.len = result->len;
michael@0 117
michael@0 118 status = TLS_P_hash(HASH_AlgMD5, &S1, label, seed, result, isFIPS);
michael@0 119 if (status != SECSuccess)
michael@0 120 goto loser;
michael@0 121
michael@0 122 status = TLS_P_hash(HASH_AlgSHA1, &S2, label, seed, &tmp, isFIPS);
michael@0 123 if (status != SECSuccess)
michael@0 124 goto loser;
michael@0 125
michael@0 126 for (i = 0; i < result->len; i++)
michael@0 127 result->data[i] ^= tmp.data[i];
michael@0 128
michael@0 129 rv = SECSuccess;
michael@0 130
michael@0 131 loser:
michael@0 132 if (tmp.data != NULL)
michael@0 133 PORT_ZFree(tmp.data, tmp.len);
michael@0 134 return rv;
michael@0 135 }
michael@0 136

mercurial