Tomato 1.26
[tomato.git] / release / src / router / matrixssl / src / sslv3.c
blobd53b74137327b446303d8d31e4f782be6de05022
1 /*
2 * sslv3.c
3 * Release $Name: MATRIXSSL_1_8_8_OPEN $
5 * SSLv3.0 specific code per http://wp.netscape.com/eng/ssl3.
6 * Primarily dealing with secret generation, message authentication codes
7 * and handshake hashing.
8 */
9 /*
10 * Copyright (c) PeerSec Networks, 2002-2009. All Rights Reserved.
11 * The latest version of this code is available at http://www.matrixssl.org
13 * This software is open source; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
18 * This General Public License does NOT permit incorporating this software
19 * into proprietary programs. If you are unable to comply with the GPL, a
20 * commercial license for this software may be purchased from PeerSec Networks
21 * at http://www.peersec.com
23 * This program is distributed in WITHOUT ANY WARRANTY; without even the
24 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
25 * See the GNU General Public License for more details.
27 * You should have received a copy of the GNU General Public License
28 * along with this program; if not, write to the Free Software
29 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
30 * http://www.gnu.org/copyleft/gpl.html
32 /******************************************************************************/
34 #include "matrixInternal.h"
36 /******************************************************************************/
38 Constants used for key generation
40 static const unsigned char SENDER_CLIENT[5] = "CLNT"; /* 0x434C4E54 */
41 static const unsigned char SENDER_SERVER[5] = "SRVR"; /* 0x53525652 */
43 static const unsigned char pad1[48]={
44 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
45 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
46 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
47 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
48 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
49 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36
52 static const unsigned char pad2[48]={
53 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
54 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
55 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
56 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
57 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
58 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c
61 static const unsigned char *salt[10]={
62 (const unsigned char *)"A",
63 (const unsigned char *)"BB",
64 (const unsigned char *)"CCC",
65 (const unsigned char *)"DDDD",
66 (const unsigned char *)"EEEEE",
67 (const unsigned char *)"FFFFFF",
68 (const unsigned char *)"GGGGGGG",
69 (const unsigned char *)"HHHHHHHH",
70 (const unsigned char *)"IIIIIIIII",
71 (const unsigned char *)"JJJJJJJJJJ"
74 /******************************************************************************/
76 static int32 createKeyBlock(ssl_t *ssl, unsigned char *clientRandom,
77 unsigned char *serverRandom,
78 unsigned char *masterSecret, int32 secretLen);
80 /******************************************************************************/
82 * Generates all key material.
84 int32 sslDeriveKeys(ssl_t *ssl)
86 sslMd5Context_t md5Ctx;
87 sslSha1Context_t sha1Ctx;
88 unsigned char buf[SSL_MD5_HASH_SIZE + SSL_SHA1_HASH_SIZE];
89 unsigned char *tmp;
90 int32 i;
93 If this session is resumed, we want to reuse the master secret to
94 regenerate the key block with the new random values.
96 if (ssl->flags & SSL_FLAGS_RESUMED) {
97 goto skipPremaster;
100 master_secret =
101 MD5(pre_master_secret + SHA('A' + pre_master_secret +
102 ClientHello.random + ServerHello.random)) +
103 MD5(pre_master_secret + SHA('BB' + pre_master_secret +
104 ClientHello.random + ServerHello.random)) +
105 MD5(pre_master_secret + SHA('CCC' + pre_master_secret +
106 ClientHello.random + ServerHello.random));
108 tmp = ssl->sec.masterSecret;
109 for (i = 0; i < 3; i++) {
110 matrixSha1Init(&sha1Ctx);
111 matrixSha1Update(&sha1Ctx, salt[i], i + 1);
112 matrixSha1Update(&sha1Ctx, ssl->sec.premaster, ssl->sec.premasterSize);
113 matrixSha1Update(&sha1Ctx, ssl->sec.clientRandom, SSL_HS_RANDOM_SIZE);
114 matrixSha1Update(&sha1Ctx, ssl->sec.serverRandom, SSL_HS_RANDOM_SIZE);
115 matrixSha1Final(&sha1Ctx, buf);
117 matrixMd5Init(&md5Ctx);
118 matrixMd5Update(&md5Ctx, ssl->sec.premaster, ssl->sec.premasterSize);
119 matrixMd5Update(&md5Ctx, buf, SSL_SHA1_HASH_SIZE);
120 matrixMd5Final(&md5Ctx, tmp);
121 tmp += SSL_MD5_HASH_SIZE;
123 memset(buf, 0x0, SSL_MD5_HASH_SIZE + SSL_SHA1_HASH_SIZE);
125 premaster is now allocated for DH reasons. Can free here
127 psFree(ssl->sec.premaster);
128 ssl->sec.premaster = NULL;
129 ssl->sec.premasterSize = 0;
131 skipPremaster:
132 if (createKeyBlock(ssl, ssl->sec.clientRandom, ssl->sec.serverRandom,
133 ssl->sec.masterSecret, SSL_HS_MASTER_SIZE) < 0) {
134 matrixStrDebugMsg("Unable to create key block\n", NULL);
135 return -1;
138 return SSL_HS_MASTER_SIZE;
141 /******************************************************************************/
143 Generate the key block as follows. '+' indicates concatination.
144 key_block =
145 MD5(master_secret + SHA(`A' + master_secret +
146 ServerHello.random + ClientHello.random)) +
147 MD5(master_secret + SHA(`BB' + master_secret +
148 ServerHello.random + ClientHello.random)) +
149 MD5(master_secret + SHA(`CCC' + master_secret +
150 ServerHello.random + ClientHello.random)) +
151 [...];
153 static int32 createKeyBlock(ssl_t *ssl, unsigned char *clientRandom,
154 unsigned char *serverRandom,
155 unsigned char *masterSecret, int32 secretLen)
157 sslMd5Context_t md5Ctx;
158 sslSha1Context_t sha1Ctx;
159 unsigned char buf[SSL_MD5_HASH_SIZE + SSL_SHA1_HASH_SIZE];
160 unsigned char *tmp;
161 int32 keyIter, i, ret = 0;
162 int32 reqKeyLen;
165 We must generate enough key material to fill the various keys
167 reqKeyLen = 2 * ssl->cipher->macSize +
168 2 * ssl->cipher->keySize +
169 2 * ssl->cipher->ivSize;
171 Find the right number of iterations to make the requested length key block
173 keyIter = 1;
174 while (SSL_MD5_HASH_SIZE * keyIter < reqKeyLen) {
175 keyIter++;
177 if (keyIter > sizeof(salt)/sizeof(char*)) {
178 matrixIntDebugMsg("Error: Not enough salt for key length of %d\n",
179 reqKeyLen);
180 return -1;
183 tmp = ssl->sec.keyBlock;
184 for (i = 0; i < keyIter; i++) {
185 matrixSha1Init(&sha1Ctx);
186 matrixSha1Update(&sha1Ctx, salt[i], i + 1);
187 matrixSha1Update(&sha1Ctx, masterSecret, secretLen);
188 matrixSha1Update(&sha1Ctx, serverRandom, SSL_HS_RANDOM_SIZE);
189 matrixSha1Update(&sha1Ctx, clientRandom, SSL_HS_RANDOM_SIZE);
190 matrixSha1Final(&sha1Ctx, buf);
192 matrixMd5Init(&md5Ctx);
193 matrixMd5Update(&md5Ctx, masterSecret, secretLen);
194 matrixMd5Update(&md5Ctx, buf, SSL_SHA1_HASH_SIZE);
195 matrixMd5Final(&md5Ctx, tmp);
196 tmp += SSL_MD5_HASH_SIZE;
197 ret += SSL_MD5_HASH_SIZE;
199 memset(buf, 0x0, SSL_MD5_HASH_SIZE + SSL_SHA1_HASH_SIZE);
201 Client and server use different read/write values, with the Client
202 write value being the server read value.
204 if (ssl->flags & SSL_FLAGS_SERVER) {
205 ssl->sec.rMACptr = ssl->sec.keyBlock;
206 ssl->sec.wMACptr = ssl->sec.rMACptr + ssl->cipher->macSize;
207 ssl->sec.rKeyptr = ssl->sec.wMACptr + ssl->cipher->macSize;
208 ssl->sec.wKeyptr = ssl->sec.rKeyptr + ssl->cipher->keySize;
209 ssl->sec.rIVptr = ssl->sec.wKeyptr + ssl->cipher->keySize;
210 ssl->sec.wIVptr = ssl->sec.rIVptr + ssl->cipher->ivSize;
211 } else {
212 ssl->sec.wMACptr = ssl->sec.keyBlock;
213 ssl->sec.rMACptr = ssl->sec.wMACptr + ssl->cipher->macSize;
214 ssl->sec.wKeyptr = ssl->sec.rMACptr + ssl->cipher->macSize;
215 ssl->sec.rKeyptr = ssl->sec.wKeyptr + ssl->cipher->keySize;
216 ssl->sec.wIVptr = ssl->sec.rKeyptr + ssl->cipher->keySize;
217 ssl->sec.rIVptr = ssl->sec.wIVptr + ssl->cipher->ivSize;
220 return ret;
223 /******************************************************************************/
225 Combine the running hash of the handshake mesages with some constants
226 and mix them up a bit more. Output the result to the given buffer.
227 This data will be part of the Finished handshake message.
229 int32 sslGenerateFinishedHash(sslMd5Context_t *md5, sslSha1Context_t *sha1,
230 unsigned char *masterSecret,
231 unsigned char *out, int32 sender)
233 sslMd5Context_t omd5;
234 sslSha1Context_t osha1;
236 unsigned char ihash[SSL_SHA1_HASH_SIZE];
239 md5Hash = MD5(master_secret + pad2 +
240 MD5(handshake_messages + sender + master_secret + pad1));
242 if (sender >= 0) {
243 matrixMd5Update(md5,
244 (sender & SSL_FLAGS_SERVER) ? SENDER_SERVER : SENDER_CLIENT, 4);
246 matrixMd5Update(md5, masterSecret, SSL_HS_MASTER_SIZE);
247 matrixMd5Update(md5, pad1, sizeof(pad1));
248 matrixMd5Final(md5, ihash);
250 matrixMd5Init(&omd5);
251 matrixMd5Update(&omd5, masterSecret, SSL_HS_MASTER_SIZE);
252 matrixMd5Update(&omd5, pad2, sizeof(pad2));
253 matrixMd5Update(&omd5, ihash, SSL_MD5_HASH_SIZE);
254 matrixMd5Final(&omd5, out);
256 The SHA1 hash is generated in the same way, except only 40 bytes
257 of pad1 and pad2 are used.
258 sha1Hash = SHA1(master_secret + pad2 +
259 SHA1(handshake_messages + sender + master_secret + pad1));
261 if (sender >= 0) {
262 matrixSha1Update(sha1,
263 (sender & SSL_FLAGS_SERVER) ? SENDER_SERVER : SENDER_CLIENT, 4);
265 matrixSha1Update(sha1, masterSecret, SSL_HS_MASTER_SIZE);
266 matrixSha1Update(sha1, pad1, 40);
267 matrixSha1Final(sha1, ihash);
269 matrixSha1Init(&osha1);
270 matrixSha1Update(&osha1, masterSecret, SSL_HS_MASTER_SIZE);
271 matrixSha1Update(&osha1, pad2, 40);
272 matrixSha1Update(&osha1, ihash, SSL_SHA1_HASH_SIZE);
273 matrixSha1Final(&osha1, out + SSL_MD5_HASH_SIZE);
275 return SSL_MD5_HASH_SIZE + SSL_SHA1_HASH_SIZE;
278 #ifdef USE_SHA1_MAC
279 /******************************************************************************/
281 SSLv3 uses a method similar to HMAC to generate the SHA1 message MAC.
282 For SHA1, 40 bytes of the pad are used.
284 SHA1(MAC_write_secret + pad2 +
285 SHA1(MAC_write_secret + pad1 + seq_num + length + content));
287 int32 ssl3HMACSha1(unsigned char *key, unsigned char *seq,
288 unsigned char type, unsigned char *data, int32 len,
289 unsigned char *mac)
291 sslSha1Context_t sha1;
292 unsigned char ihash[SSL_SHA1_HASH_SIZE];
293 int32 i;
295 matrixSha1Init(&sha1);
296 matrixSha1Update(&sha1, key, SSL_SHA1_HASH_SIZE);
297 matrixSha1Update(&sha1, pad1, 40);
298 matrixSha1Update(&sha1, seq, 8);
299 ihash[0] = type;
300 ihash[1] = (len & 0xFF00) >> 8;
301 ihash[2] = len & 0xFF;
302 matrixSha1Update(&sha1, ihash, 3);
303 matrixSha1Update(&sha1, data, len);
304 matrixSha1Final(&sha1, ihash);
306 matrixSha1Init(&sha1);
307 matrixSha1Update(&sha1, key, SSL_SHA1_HASH_SIZE);
308 matrixSha1Update(&sha1, pad2, 40);
309 matrixSha1Update(&sha1, ihash, SSL_SHA1_HASH_SIZE);
310 matrixSha1Final(&sha1, mac);
313 Increment sequence number
315 for (i = 7; i >= 0; i--) {
316 seq[i]++;
317 if (seq[i] != 0) {
318 break;
321 return SSL_SHA1_HASH_SIZE;
323 #endif /* USE_SHA1_MAC */
325 #ifdef USE_MD5_MAC
326 /******************************************************************************/
328 SSLv3 uses a method similar to HMAC to generate the MD5 message MAC.
329 For MD5, 48 bytes of the pad are used.
331 MD5(MAC_write_secret + pad2 +
332 MD5(MAC_write_secret + pad1 + seq_num + length + content));
334 int32 ssl3HMACMd5(unsigned char *key, unsigned char *seq,
335 unsigned char type, unsigned char *data, int32 len,
336 unsigned char *mac)
338 sslMd5Context_t md5;
339 unsigned char ihash[SSL_MD5_HASH_SIZE];
340 int32 i;
342 matrixMd5Init(&md5);
343 matrixMd5Update(&md5, key, SSL_MD5_HASH_SIZE);
344 matrixMd5Update(&md5, pad1, 48);
345 matrixMd5Update(&md5, seq, 8);
346 ihash[0] = type;
347 ihash[1] = (len & 0xFF00) >> 8;
348 ihash[2] = len & 0xFF;
349 matrixMd5Update(&md5, ihash, 3);
350 matrixMd5Update(&md5, data, len);
351 matrixMd5Final(&md5, ihash);
353 matrixMd5Init(&md5);
354 matrixMd5Update(&md5, key, SSL_MD5_HASH_SIZE);
355 matrixMd5Update(&md5, pad2, 48);
356 matrixMd5Update(&md5, ihash, SSL_MD5_HASH_SIZE);
357 matrixMd5Final(&md5, mac);
360 Increment sequence number
362 for (i = 7; i >= 0; i--) {
363 seq[i]++;
364 if (seq[i] != 0) {
365 break;
368 return SSL_MD5_HASH_SIZE;
371 #endif /* USE_MD5_MAC */
373 /******************************************************************************/