Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
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 |