Back to index

lightning-sunbird  0.9+nobinonly
tlsprfalg.c
Go to the documentation of this file.
00001 /* tlsprfalg.c - TLS Pseudo Random Function (PRF) implementation
00002  *
00003  * ***** BEGIN LICENSE BLOCK *****
00004  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00005  *
00006  * The contents of this file are subject to the Mozilla Public License Version
00007  * 1.1 (the "License"); you may not use this file except in compliance with
00008  * the License. You may obtain a copy of the License at
00009  * http://www.mozilla.org/MPL/
00010  *
00011  * Software distributed under the License is distributed on an "AS IS" basis,
00012  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00013  * for the specific language governing rights and limitations under the
00014  * License.
00015  *
00016  * The Original Code is the Netscape security libraries.
00017  *
00018  * The Initial Developer of the Original Code is
00019  * Netscape Communications Corporation.
00020  * Portions created by the Initial Developer are Copyright (C) 1994-2000
00021  * the Initial Developer. All Rights Reserved.
00022  *
00023  * Contributor(s):
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either the GNU General Public License Version 2 or later (the "GPL"), or
00027  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 /* $Id: tlsprfalg.c,v 1.5 2005/11/05 01:00:14 wtchang%redhat.com Exp $ */
00039 
00040 #include "sechash.h"
00041 #include "alghmac.h"
00042 #include "blapi.h"
00043 
00044 #define PHASH_STATE_MAX_LEN SHA1_LENGTH
00045 
00046 /* TLS P_hash function */
00047 static SECStatus
00048 sftk_P_hash(HASH_HashType hashType, const SECItem *secret, const char *label, 
00049        SECItem *seed, SECItem *result, PRBool isFIPS)
00050 {
00051     unsigned char state[PHASH_STATE_MAX_LEN];
00052     unsigned char outbuf[PHASH_STATE_MAX_LEN];
00053     unsigned int state_len = 0, label_len = 0, outbuf_len = 0, chunk_size;
00054     unsigned int remaining;
00055     unsigned char *res;
00056     SECStatus status;
00057     HMACContext *cx;
00058     SECStatus rv = SECFailure;
00059     const SECHashObject *hashObj = HASH_GetRawHashObject(hashType);
00060 
00061     PORT_Assert((secret != NULL) && (secret->data != NULL || !secret->len));
00062     PORT_Assert((seed != NULL) && (seed->data != NULL));
00063     PORT_Assert((result != NULL) && (result->data != NULL));
00064 
00065     remaining = result->len;
00066     res = result->data;
00067 
00068     if (label != NULL)
00069        label_len = PORT_Strlen(label);
00070 
00071     cx = HMAC_Create(hashObj, secret->data, secret->len, isFIPS);
00072     if (cx == NULL)
00073        goto loser;
00074 
00075     /* initialize the state = A(1) = HMAC_hash(secret, seed) */
00076     HMAC_Begin(cx);
00077     HMAC_Update(cx, (unsigned char *)label, label_len);
00078     HMAC_Update(cx, seed->data, seed->len);
00079     status = HMAC_Finish(cx, state, &state_len, sizeof(state));
00080     if (status != SECSuccess)
00081        goto loser;
00082 
00083     /* generate a block at a time until we're done */
00084     while (remaining > 0) {
00085 
00086        HMAC_Begin(cx);
00087        HMAC_Update(cx, state, state_len);
00088        if (label_len)
00089            HMAC_Update(cx, (unsigned char *)label, label_len);
00090        HMAC_Update(cx, seed->data, seed->len);
00091        status = HMAC_Finish(cx, outbuf, &outbuf_len, sizeof(outbuf));
00092        if (status != SECSuccess)
00093            goto loser;
00094 
00095         /* Update the state = A(i) = HMAC_hash(secret, A(i-1)) */
00096        HMAC_Begin(cx); 
00097        HMAC_Update(cx, state, state_len); 
00098        status = HMAC_Finish(cx, state, &state_len, sizeof(state));
00099        if (status != SECSuccess)
00100            goto loser;
00101 
00102        chunk_size = PR_MIN(outbuf_len, remaining);
00103        PORT_Memcpy(res, &outbuf, chunk_size);
00104        res += chunk_size;
00105        remaining -= chunk_size;
00106     }
00107 
00108     rv = SECSuccess;
00109 
00110 loser:
00111     /* clear out state so it's not left on the stack */
00112     if (cx) 
00113        HMAC_Destroy(cx, PR_TRUE);
00114     PORT_Memset(state, 0, sizeof(state));
00115     PORT_Memset(outbuf, 0, sizeof(outbuf));
00116     return rv;
00117 }
00118 
00119 SECStatus
00120 TLS_PRF(const SECItem *secret, const char *label, SECItem *seed, 
00121          SECItem *result, PRBool isFIPS)
00122 {
00123     SECStatus rv = SECFailure, status;
00124     unsigned int i;
00125     SECItem tmp = { siBuffer, NULL, 0};
00126     SECItem S1;
00127     SECItem S2;
00128 
00129     PORT_Assert((secret != NULL) && (secret->data != NULL || !secret->len));
00130     PORT_Assert((seed != NULL) && (seed->data != NULL));
00131     PORT_Assert((result != NULL) && (result->data != NULL));
00132 
00133     S1.type = siBuffer;
00134     S1.len  = (secret->len / 2) + (secret->len & 1);
00135     S1.data = secret->data;
00136 
00137     S2.type = siBuffer;
00138     S2.len  = S1.len;
00139     S2.data = secret->data + (secret->len - S2.len);
00140 
00141     tmp.data = (unsigned char*)PORT_Alloc(result->len);
00142     if (tmp.data == NULL)
00143        goto loser;
00144     tmp.len = result->len;
00145 
00146     status = sftk_P_hash(HASH_AlgMD5, &S1, label, seed, result, isFIPS);
00147     if (status != SECSuccess)
00148        goto loser;
00149 
00150     status = sftk_P_hash(HASH_AlgSHA1, &S2, label, seed, &tmp, isFIPS);
00151     if (status != SECSuccess)
00152        goto loser;
00153 
00154     for (i = 0; i < result->len; i++)
00155        result->data[i] ^= tmp.data[i];
00156 
00157     rv = SECSuccess;
00158 
00159 loser:
00160     if (tmp.data != NULL)
00161        PORT_ZFree(tmp.data, tmp.len);
00162     return rv;
00163 }
00164