summaryrefslogtreecommitdiff
path: root/release/src/router/matrixssl/src/sslv3.c
diff options
context:
space:
mode:
authorAndreas Baumann <mail@andreasbaumann.cc>2015-01-03 13:58:15 +0100
committerAndreas Baumann <mail@andreasbaumann.cc>2015-01-03 13:58:15 +0100
commit4aca87515a5083ae0e31ce3177189fd43b6d05ac (patch)
tree7b1d9a31393ca090757dc6f0d3859b4fcd93f271 /release/src/router/matrixssl/src/sslv3.c
parent008d0be72b2f160382c6e880765e96b64a050c65 (diff)
downloadtomato-4aca87515a5083ae0e31ce3177189fd43b6d05ac.tar.gz
tomato-4aca87515a5083ae0e31ce3177189fd43b6d05ac.tar.bz2
patch to Vanilla Tomato 1.28
Diffstat (limited to 'release/src/router/matrixssl/src/sslv3.c')
-rw-r--r--release/src/router/matrixssl/src/sslv3.c375
1 files changed, 375 insertions, 0 deletions
diff --git a/release/src/router/matrixssl/src/sslv3.c b/release/src/router/matrixssl/src/sslv3.c
new file mode 100644
index 00000000..d53b7413
--- /dev/null
+++ b/release/src/router/matrixssl/src/sslv3.c
@@ -0,0 +1,375 @@
+/*
+ * sslv3.c
+ * Release $Name: MATRIXSSL_1_8_8_OPEN $
+ *
+ * SSLv3.0 specific code per http://wp.netscape.com/eng/ssl3.
+ * Primarily dealing with secret generation, message authentication codes
+ * and handshake hashing.
+ */
+/*
+ * Copyright (c) PeerSec Networks, 2002-2009. All Rights Reserved.
+ * The latest version of this code is available at http://www.matrixssl.org
+ *
+ * This software is open source; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This General Public License does NOT permit incorporating this software
+ * into proprietary programs. If you are unable to comply with the GPL, a
+ * commercial license for this software may be purchased from PeerSec Networks
+ * at http://www.peersec.com
+ *
+ * This program is distributed in WITHOUT ANY WARRANTY; without even the
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+/******************************************************************************/
+
+#include "matrixInternal.h"
+
+/******************************************************************************/
+/*
+ Constants used for key generation
+*/
+static const unsigned char SENDER_CLIENT[5] = "CLNT"; /* 0x434C4E54 */
+static const unsigned char SENDER_SERVER[5] = "SRVR"; /* 0x53525652 */
+
+static const unsigned char pad1[48]={
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36
+};
+
+static const unsigned char pad2[48]={
+ 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
+ 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
+ 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
+ 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
+ 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
+ 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c
+};
+
+static const unsigned char *salt[10]={
+ (const unsigned char *)"A",
+ (const unsigned char *)"BB",
+ (const unsigned char *)"CCC",
+ (const unsigned char *)"DDDD",
+ (const unsigned char *)"EEEEE",
+ (const unsigned char *)"FFFFFF",
+ (const unsigned char *)"GGGGGGG",
+ (const unsigned char *)"HHHHHHHH",
+ (const unsigned char *)"IIIIIIIII",
+ (const unsigned char *)"JJJJJJJJJJ"
+};
+
+/******************************************************************************/
+
+static int32 createKeyBlock(ssl_t *ssl, unsigned char *clientRandom,
+ unsigned char *serverRandom,
+ unsigned char *masterSecret, int32 secretLen);
+
+/******************************************************************************/
+/*
+ * Generates all key material.
+ */
+int32 sslDeriveKeys(ssl_t *ssl)
+{
+ sslMd5Context_t md5Ctx;
+ sslSha1Context_t sha1Ctx;
+ unsigned char buf[SSL_MD5_HASH_SIZE + SSL_SHA1_HASH_SIZE];
+ unsigned char *tmp;
+ int32 i;
+
+/*
+ If this session is resumed, we want to reuse the master secret to
+ regenerate the key block with the new random values.
+*/
+ if (ssl->flags & SSL_FLAGS_RESUMED) {
+ goto skipPremaster;
+ }
+/*
+ master_secret =
+ MD5(pre_master_secret + SHA('A' + pre_master_secret +
+ ClientHello.random + ServerHello.random)) +
+ MD5(pre_master_secret + SHA('BB' + pre_master_secret +
+ ClientHello.random + ServerHello.random)) +
+ MD5(pre_master_secret + SHA('CCC' + pre_master_secret +
+ ClientHello.random + ServerHello.random));
+*/
+ tmp = ssl->sec.masterSecret;
+ for (i = 0; i < 3; i++) {
+ matrixSha1Init(&sha1Ctx);
+ matrixSha1Update(&sha1Ctx, salt[i], i + 1);
+ matrixSha1Update(&sha1Ctx, ssl->sec.premaster, ssl->sec.premasterSize);
+ matrixSha1Update(&sha1Ctx, ssl->sec.clientRandom, SSL_HS_RANDOM_SIZE);
+ matrixSha1Update(&sha1Ctx, ssl->sec.serverRandom, SSL_HS_RANDOM_SIZE);
+ matrixSha1Final(&sha1Ctx, buf);
+
+ matrixMd5Init(&md5Ctx);
+ matrixMd5Update(&md5Ctx, ssl->sec.premaster, ssl->sec.premasterSize);
+ matrixMd5Update(&md5Ctx, buf, SSL_SHA1_HASH_SIZE);
+ matrixMd5Final(&md5Ctx, tmp);
+ tmp += SSL_MD5_HASH_SIZE;
+ }
+ memset(buf, 0x0, SSL_MD5_HASH_SIZE + SSL_SHA1_HASH_SIZE);
+/*
+ premaster is now allocated for DH reasons. Can free here
+*/
+ psFree(ssl->sec.premaster);
+ ssl->sec.premaster = NULL;
+ ssl->sec.premasterSize = 0;
+
+skipPremaster:
+ if (createKeyBlock(ssl, ssl->sec.clientRandom, ssl->sec.serverRandom,
+ ssl->sec.masterSecret, SSL_HS_MASTER_SIZE) < 0) {
+ matrixStrDebugMsg("Unable to create key block\n", NULL);
+ return -1;
+ }
+
+ return SSL_HS_MASTER_SIZE;
+}
+
+/******************************************************************************/
+/*
+ Generate the key block as follows. '+' indicates concatination.
+ key_block =
+ MD5(master_secret + SHA(`A' + master_secret +
+ ServerHello.random + ClientHello.random)) +
+ MD5(master_secret + SHA(`BB' + master_secret +
+ ServerHello.random + ClientHello.random)) +
+ MD5(master_secret + SHA(`CCC' + master_secret +
+ ServerHello.random + ClientHello.random)) +
+ [...];
+*/
+static int32 createKeyBlock(ssl_t *ssl, unsigned char *clientRandom,
+ unsigned char *serverRandom,
+ unsigned char *masterSecret, int32 secretLen)
+{
+ sslMd5Context_t md5Ctx;
+ sslSha1Context_t sha1Ctx;
+ unsigned char buf[SSL_MD5_HASH_SIZE + SSL_SHA1_HASH_SIZE];
+ unsigned char *tmp;
+ int32 keyIter, i, ret = 0;
+ int32 reqKeyLen;
+
+/*
+ We must generate enough key material to fill the various keys
+*/
+ reqKeyLen = 2 * ssl->cipher->macSize +
+ 2 * ssl->cipher->keySize +
+ 2 * ssl->cipher->ivSize;
+/*
+ Find the right number of iterations to make the requested length key block
+*/
+ keyIter = 1;
+ while (SSL_MD5_HASH_SIZE * keyIter < reqKeyLen) {
+ keyIter++;
+ }
+ if (keyIter > sizeof(salt)/sizeof(char*)) {
+ matrixIntDebugMsg("Error: Not enough salt for key length of %d\n",
+ reqKeyLen);
+ return -1;
+ }
+
+ tmp = ssl->sec.keyBlock;
+ for (i = 0; i < keyIter; i++) {
+ matrixSha1Init(&sha1Ctx);
+ matrixSha1Update(&sha1Ctx, salt[i], i + 1);
+ matrixSha1Update(&sha1Ctx, masterSecret, secretLen);
+ matrixSha1Update(&sha1Ctx, serverRandom, SSL_HS_RANDOM_SIZE);
+ matrixSha1Update(&sha1Ctx, clientRandom, SSL_HS_RANDOM_SIZE);
+ matrixSha1Final(&sha1Ctx, buf);
+
+ matrixMd5Init(&md5Ctx);
+ matrixMd5Update(&md5Ctx, masterSecret, secretLen);
+ matrixMd5Update(&md5Ctx, buf, SSL_SHA1_HASH_SIZE);
+ matrixMd5Final(&md5Ctx, tmp);
+ tmp += SSL_MD5_HASH_SIZE;
+ ret += SSL_MD5_HASH_SIZE;
+ }
+ memset(buf, 0x0, SSL_MD5_HASH_SIZE + SSL_SHA1_HASH_SIZE);
+/*
+ Client and server use different read/write values, with the Client
+ write value being the server read value.
+*/
+ if (ssl->flags & SSL_FLAGS_SERVER) {
+ ssl->sec.rMACptr = ssl->sec.keyBlock;
+ ssl->sec.wMACptr = ssl->sec.rMACptr + ssl->cipher->macSize;
+ ssl->sec.rKeyptr = ssl->sec.wMACptr + ssl->cipher->macSize;
+ ssl->sec.wKeyptr = ssl->sec.rKeyptr + ssl->cipher->keySize;
+ ssl->sec.rIVptr = ssl->sec.wKeyptr + ssl->cipher->keySize;
+ ssl->sec.wIVptr = ssl->sec.rIVptr + ssl->cipher->ivSize;
+ } else {
+ ssl->sec.wMACptr = ssl->sec.keyBlock;
+ ssl->sec.rMACptr = ssl->sec.wMACptr + ssl->cipher->macSize;
+ ssl->sec.wKeyptr = ssl->sec.rMACptr + ssl->cipher->macSize;
+ ssl->sec.rKeyptr = ssl->sec.wKeyptr + ssl->cipher->keySize;
+ ssl->sec.wIVptr = ssl->sec.rKeyptr + ssl->cipher->keySize;
+ ssl->sec.rIVptr = ssl->sec.wIVptr + ssl->cipher->ivSize;
+ }
+
+ return ret;
+}
+
+/******************************************************************************/
+/*
+ Combine the running hash of the handshake mesages with some constants
+ and mix them up a bit more. Output the result to the given buffer.
+ This data will be part of the Finished handshake message.
+*/
+int32 sslGenerateFinishedHash(sslMd5Context_t *md5, sslSha1Context_t *sha1,
+ unsigned char *masterSecret,
+ unsigned char *out, int32 sender)
+{
+ sslMd5Context_t omd5;
+ sslSha1Context_t osha1;
+
+ unsigned char ihash[SSL_SHA1_HASH_SIZE];
+
+/*
+ md5Hash = MD5(master_secret + pad2 +
+ MD5(handshake_messages + sender + master_secret + pad1));
+*/
+ if (sender >= 0) {
+ matrixMd5Update(md5,
+ (sender & SSL_FLAGS_SERVER) ? SENDER_SERVER : SENDER_CLIENT, 4);
+ }
+ matrixMd5Update(md5, masterSecret, SSL_HS_MASTER_SIZE);
+ matrixMd5Update(md5, pad1, sizeof(pad1));
+ matrixMd5Final(md5, ihash);
+
+ matrixMd5Init(&omd5);
+ matrixMd5Update(&omd5, masterSecret, SSL_HS_MASTER_SIZE);
+ matrixMd5Update(&omd5, pad2, sizeof(pad2));
+ matrixMd5Update(&omd5, ihash, SSL_MD5_HASH_SIZE);
+ matrixMd5Final(&omd5, out);
+/*
+ The SHA1 hash is generated in the same way, except only 40 bytes
+ of pad1 and pad2 are used.
+ sha1Hash = SHA1(master_secret + pad2 +
+ SHA1(handshake_messages + sender + master_secret + pad1));
+*/
+ if (sender >= 0) {
+ matrixSha1Update(sha1,
+ (sender & SSL_FLAGS_SERVER) ? SENDER_SERVER : SENDER_CLIENT, 4);
+ }
+ matrixSha1Update(sha1, masterSecret, SSL_HS_MASTER_SIZE);
+ matrixSha1Update(sha1, pad1, 40);
+ matrixSha1Final(sha1, ihash);
+
+ matrixSha1Init(&osha1);
+ matrixSha1Update(&osha1, masterSecret, SSL_HS_MASTER_SIZE);
+ matrixSha1Update(&osha1, pad2, 40);
+ matrixSha1Update(&osha1, ihash, SSL_SHA1_HASH_SIZE);
+ matrixSha1Final(&osha1, out + SSL_MD5_HASH_SIZE);
+
+ return SSL_MD5_HASH_SIZE + SSL_SHA1_HASH_SIZE;
+}
+
+#ifdef USE_SHA1_MAC
+/******************************************************************************/
+/*
+ SSLv3 uses a method similar to HMAC to generate the SHA1 message MAC.
+ For SHA1, 40 bytes of the pad are used.
+
+ SHA1(MAC_write_secret + pad2 +
+ SHA1(MAC_write_secret + pad1 + seq_num + length + content));
+*/
+int32 ssl3HMACSha1(unsigned char *key, unsigned char *seq,
+ unsigned char type, unsigned char *data, int32 len,
+ unsigned char *mac)
+{
+ sslSha1Context_t sha1;
+ unsigned char ihash[SSL_SHA1_HASH_SIZE];
+ int32 i;
+
+ matrixSha1Init(&sha1);
+ matrixSha1Update(&sha1, key, SSL_SHA1_HASH_SIZE);
+ matrixSha1Update(&sha1, pad1, 40);
+ matrixSha1Update(&sha1, seq, 8);
+ ihash[0] = type;
+ ihash[1] = (len & 0xFF00) >> 8;
+ ihash[2] = len & 0xFF;
+ matrixSha1Update(&sha1, ihash, 3);
+ matrixSha1Update(&sha1, data, len);
+ matrixSha1Final(&sha1, ihash);
+
+ matrixSha1Init(&sha1);
+ matrixSha1Update(&sha1, key, SSL_SHA1_HASH_SIZE);
+ matrixSha1Update(&sha1, pad2, 40);
+ matrixSha1Update(&sha1, ihash, SSL_SHA1_HASH_SIZE);
+ matrixSha1Final(&sha1, mac);
+
+/*
+ Increment sequence number
+*/
+ for (i = 7; i >= 0; i--) {
+ seq[i]++;
+ if (seq[i] != 0) {
+ break;
+ }
+ }
+ return SSL_SHA1_HASH_SIZE;
+}
+#endif /* USE_SHA1_MAC */
+
+#ifdef USE_MD5_MAC
+/******************************************************************************/
+/*
+ SSLv3 uses a method similar to HMAC to generate the MD5 message MAC.
+ For MD5, 48 bytes of the pad are used.
+
+ MD5(MAC_write_secret + pad2 +
+ MD5(MAC_write_secret + pad1 + seq_num + length + content));
+*/
+int32 ssl3HMACMd5(unsigned char *key, unsigned char *seq,
+ unsigned char type, unsigned char *data, int32 len,
+ unsigned char *mac)
+{
+ sslMd5Context_t md5;
+ unsigned char ihash[SSL_MD5_HASH_SIZE];
+ int32 i;
+
+ matrixMd5Init(&md5);
+ matrixMd5Update(&md5, key, SSL_MD5_HASH_SIZE);
+ matrixMd5Update(&md5, pad1, 48);
+ matrixMd5Update(&md5, seq, 8);
+ ihash[0] = type;
+ ihash[1] = (len & 0xFF00) >> 8;
+ ihash[2] = len & 0xFF;
+ matrixMd5Update(&md5, ihash, 3);
+ matrixMd5Update(&md5, data, len);
+ matrixMd5Final(&md5, ihash);
+
+ matrixMd5Init(&md5);
+ matrixMd5Update(&md5, key, SSL_MD5_HASH_SIZE);
+ matrixMd5Update(&md5, pad2, 48);
+ matrixMd5Update(&md5, ihash, SSL_MD5_HASH_SIZE);
+ matrixMd5Final(&md5, mac);
+
+/*
+ Increment sequence number
+*/
+ for (i = 7; i >= 0; i--) {
+ seq[i]++;
+ if (seq[i] != 0) {
+ break;
+ }
+ }
+ return SSL_MD5_HASH_SIZE;
+}
+
+#endif /* USE_MD5_MAC */
+
+/******************************************************************************/
+
+