diff options
Diffstat (limited to 'security/nss/lib/freebl/tlsprfalg.c')
-rw-r--r-- | security/nss/lib/freebl/tlsprfalg.c | 164 |
1 files changed, 164 insertions, 0 deletions
diff --git a/security/nss/lib/freebl/tlsprfalg.c b/security/nss/lib/freebl/tlsprfalg.c new file mode 100644 index 000000000..05f3f0d76 --- /dev/null +++ b/security/nss/lib/freebl/tlsprfalg.c @@ -0,0 +1,164 @@ +/* tlsprfalg.c - TLS Pseudo Random Function (PRF) implementation + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1994-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +/* $Id$ */ + +#include "sechash.h" +#include "alghmac.h" +#include "blapi.h" + +#define PHASH_STATE_MAX_LEN SHA1_LENGTH + +/* TLS P_hash function */ +static SECStatus +sftk_P_hash(HASH_HashType hashType, const SECItem *secret, const char *label, + SECItem *seed, SECItem *result, PRBool isFIPS) +{ + unsigned char state[PHASH_STATE_MAX_LEN]; + unsigned char outbuf[PHASH_STATE_MAX_LEN]; + unsigned int state_len = 0, label_len = 0, outbuf_len = 0, chunk_size; + unsigned int remaining; + unsigned char *res; + SECStatus status; + HMACContext *cx; + SECStatus rv = SECFailure; + const SECHashObject *hashObj = HASH_GetRawHashObject(hashType); + + PORT_Assert((secret != NULL) && (secret->data != NULL || !secret->len)); + PORT_Assert((seed != NULL) && (seed->data != NULL)); + PORT_Assert((result != NULL) && (result->data != NULL)); + + remaining = result->len; + res = result->data; + + if (label != NULL) + label_len = PORT_Strlen(label); + + cx = HMAC_Create(hashObj, secret->data, secret->len, isFIPS); + if (cx == NULL) + goto loser; + + /* initialize the state = A(1) = HMAC_hash(secret, seed) */ + HMAC_Begin(cx); + HMAC_Update(cx, (unsigned char *)label, label_len); + HMAC_Update(cx, seed->data, seed->len); + status = HMAC_Finish(cx, state, &state_len, sizeof(state)); + if (status != SECSuccess) + goto loser; + + /* generate a block at a time until we're done */ + while (remaining > 0) { + + HMAC_Begin(cx); + HMAC_Update(cx, state, state_len); + if (label_len) + HMAC_Update(cx, (unsigned char *)label, label_len); + HMAC_Update(cx, seed->data, seed->len); + status = HMAC_Finish(cx, outbuf, &outbuf_len, sizeof(outbuf)); + if (status != SECSuccess) + goto loser; + + /* Update the state = A(i) = HMAC_hash(secret, A(i-1)) */ + HMAC_Begin(cx); + HMAC_Update(cx, state, state_len); + status = HMAC_Finish(cx, state, &state_len, sizeof(state)); + if (status != SECSuccess) + goto loser; + + chunk_size = PR_MIN(outbuf_len, remaining); + PORT_Memcpy(res, &outbuf, chunk_size); + res += chunk_size; + remaining -= chunk_size; + } + + rv = SECSuccess; + +loser: + /* clear out state so it's not left on the stack */ + if (cx) + HMAC_Destroy(cx, PR_TRUE); + PORT_Memset(state, 0, sizeof(state)); + PORT_Memset(outbuf, 0, sizeof(outbuf)); + return rv; +} + +SECStatus +TLS_PRF(const SECItem *secret, const char *label, SECItem *seed, + SECItem *result, PRBool isFIPS) +{ + SECStatus rv = SECFailure, status; + unsigned int i; + SECItem tmp = { siBuffer, NULL, 0}; + SECItem S1; + SECItem S2; + + PORT_Assert((secret != NULL) && (secret->data != NULL || !secret->len)); + PORT_Assert((seed != NULL) && (seed->data != NULL)); + PORT_Assert((result != NULL) && (result->data != NULL)); + + S1.type = siBuffer; + S1.len = (secret->len / 2) + (secret->len & 1); + S1.data = secret->data; + + S2.type = siBuffer; + S2.len = S1.len; + S2.data = secret->data + (secret->len - S2.len); + + tmp.data = (unsigned char*)PORT_Alloc(result->len); + if (tmp.data == NULL) + goto loser; + tmp.len = result->len; + + status = sftk_P_hash(HASH_AlgMD5, &S1, label, seed, result, isFIPS); + if (status != SECSuccess) + goto loser; + + status = sftk_P_hash(HASH_AlgSHA1, &S2, label, seed, &tmp, isFIPS); + if (status != SECSuccess) + goto loser; + + for (i = 0; i < result->len; i++) + result->data[i] ^= tmp.data[i]; + + rv = SECSuccess; + +loser: + if (tmp.data != NULL) + PORT_ZFree(tmp.data, tmp.len); + return rv; +} + |