3 * Copyright (C) 2006-2012 Sawtooth Consulting Ltd.
5 * This file is part of CyaSSL.
7 * CyaSSL is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * CyaSSL is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
26 #include <cyassl/ssl.h>
27 #include <cyassl/internal.h>
28 #include <cyassl/error.h>
29 #include <cyassl/ctaocrypt/hmac.h>
38 static INLINE word32 min(word32 a, word32 b)
46 /* calculate XOR for TLSv1 PRF */
47 static INLINE void get_xor(byte *digest, word32 digLen, byte* md5, byte* sha)
51 for (i = 0; i < digLen; i++)
52 digest[i] = md5[i] ^ sha[i];
57 #define PHASH_MAX_DIGEST_SIZE SHA384_DIGEST_SIZE
59 #define PHASH_MAX_DIGEST_SIZE SHA256_DIGEST_SIZE
62 /* compute p_hash for MD5, SHA-1, SHA-256, or SHA-384 for TLSv1 PRF */
63 static void p_hash(byte* result, word32 resLen, const byte* secret,
64 word32 secLen, const byte* seed, word32 seedLen, int hash)
66 word32 len = MD5_DIGEST_SIZE;
72 byte previous[PHASH_MAX_DIGEST_SIZE]; /* max size */
73 byte current[PHASH_MAX_DIGEST_SIZE]; /* max size */
77 if (hash == md5_mac) {
80 else if (hash == sha_mac) {
81 len = SHA_DIGEST_SIZE;
83 } else if (hash == sha256_mac) {
84 len = SHA256_DIGEST_SIZE;
88 else if (hash == sha384_mac)
90 len = SHA384_DIGEST_SIZE;
96 lastLen = resLen % len;
97 if (lastLen) times += 1;
100 HmacSetKey(&hmac, hash, secret, secLen);
101 HmacUpdate(&hmac, seed, seedLen); /* A0 = seed */
102 HmacFinal(&hmac, previous); /* A1 */
104 for (i = 0; i < times; i++) {
105 HmacUpdate(&hmac, previous, len);
106 HmacUpdate(&hmac, seed, seedLen);
107 HmacFinal(&hmac, current);
109 if ( (i == lastTime) && lastLen)
110 XMEMCPY(&result[idx], current, min(lastLen, sizeof(current)));
112 XMEMCPY(&result[idx], current, len);
114 HmacUpdate(&hmac, previous, len);
115 HmacFinal(&hmac, previous);
122 /* compute TLSv1 PRF (pseudo random function using HMAC) */
123 static void PRF(byte* digest, word32 digLen, const byte* secret, word32 secLen,
124 const byte* label, word32 labLen, const byte* seed, word32 seedLen,
125 int useAtLeastSha256, int hash_type)
127 word32 half = (secLen + 1) / 2;
129 byte md5_half[MAX_PRF_HALF]; /* half is real size */
130 byte sha_half[MAX_PRF_HALF]; /* half is real size */
131 byte labelSeed[MAX_PRF_LABSEED]; /* labLen + seedLen is real size */
132 byte md5_result[MAX_PRF_DIG]; /* digLen is real size */
133 byte sha_result[MAX_PRF_DIG]; /* digLen is real size */
135 if (half > MAX_PRF_HALF)
137 if (labLen + seedLen > MAX_PRF_LABSEED)
139 if (digLen > MAX_PRF_DIG)
142 XMEMCPY(md5_half, secret, half);
143 XMEMCPY(sha_half, secret + half - secLen % 2, half);
145 XMEMCPY(labelSeed, label, labLen);
146 XMEMCPY(labelSeed + labLen, seed, seedLen);
148 if (useAtLeastSha256) {
149 /* If a cipher suite wants an algorithm better than sha256, it
150 * should use better. */
151 if (hash_type < sha256_mac)
152 hash_type = sha256_mac;
153 p_hash(digest, digLen, secret, secLen, labelSeed, labLen + seedLen,
158 p_hash(md5_result, digLen, md5_half, half, labelSeed, labLen + seedLen,
160 p_hash(sha_result, digLen, sha_half, half, labelSeed, labLen + seedLen,
162 get_xor(digest, digLen, md5_result, sha_result);
167 #define HSHASH_SZ SHA384_DIGEST_SIZE
169 #define HSHASH_SZ FINISHED_SZ
173 void BuildTlsFinished(CYASSL* ssl, Hashes* hashes, const byte* sender)
176 byte handshake_hash[HSHASH_SZ];
177 word32 hashSz = FINISHED_SZ;
179 Md5Final(&ssl->hashMd5, handshake_hash);
180 ShaFinal(&ssl->hashSha, &handshake_hash[MD5_DIGEST_SIZE]);
181 if (IsAtLeastTLSv1_2(ssl)) {
183 if (ssl->specs.mac_algorithm <= sha256_mac) {
184 Sha256Final(&ssl->hashSha256, handshake_hash);
185 hashSz = SHA256_DIGEST_SIZE;
189 if (ssl->specs.mac_algorithm == sha384_mac) {
190 Sha384Final(&ssl->hashSha384, handshake_hash);
191 hashSz = SHA384_DIGEST_SIZE;
196 if ( XSTRNCMP((const char*)sender, (const char*)client, SIZEOF_SENDER) == 0)
201 PRF(hashes->md5, TLS_FINISHED_SZ, ssl->arrays.masterSecret, SECRET_LEN,
202 side, FINISHED_LABEL_SZ, handshake_hash, hashSz, IsAtLeastTLSv1_2(ssl),
203 ssl->specs.mac_algorithm);
207 ProtocolVersion MakeTLSv1(void)
210 pv.major = SSLv3_MAJOR;
211 pv.minor = TLSv1_MINOR;
217 ProtocolVersion MakeTLSv1_1(void)
220 pv.major = SSLv3_MAJOR;
221 pv.minor = TLSv1_1_MINOR;
227 ProtocolVersion MakeTLSv1_2(void)
230 pv.major = SSLv3_MAJOR;
231 pv.minor = TLSv1_2_MINOR;
237 static const byte master_label[MASTER_LABEL_SZ + 1] = "master secret";
238 static const byte key_label [KEY_LABEL_SZ + 1] = "key expansion";
241 int DeriveTlsKeys(CYASSL* ssl)
243 int length = 2 * ssl->specs.hash_size +
244 2 * ssl->specs.key_size +
245 2 * ssl->specs.iv_size;
247 byte key_data[MAX_PRF_DIG];
249 XMEMCPY(seed, ssl->arrays.serverRandom, RAN_LEN);
250 XMEMCPY(&seed[RAN_LEN], ssl->arrays.clientRandom, RAN_LEN);
252 PRF(key_data, length, ssl->arrays.masterSecret, SECRET_LEN, key_label,
253 KEY_LABEL_SZ, seed, SEED_LEN, IsAtLeastTLSv1_2(ssl),
254 ssl->specs.mac_algorithm);
256 return StoreKeys(ssl, key_data);
260 int MakeTlsMasterSecret(CYASSL* ssl)
264 XMEMCPY(seed, ssl->arrays.clientRandom, RAN_LEN);
265 XMEMCPY(&seed[RAN_LEN], ssl->arrays.serverRandom, RAN_LEN);
267 PRF(ssl->arrays.masterSecret, SECRET_LEN,
268 ssl->arrays.preMasterSecret, ssl->arrays.preMasterSz,
269 master_label, MASTER_LABEL_SZ,
270 seed, SEED_LEN, IsAtLeastTLSv1_2(ssl), ssl->specs.mac_algorithm);
275 printf("master secret: ");
276 for (i = 0; i < SECRET_LEN; i++)
277 printf("%02x", ssl->arrays.masterSecret[i]);
282 return DeriveTlsKeys(ssl);
286 /*** next for static INLINE s copied from cyassl_int.c ***/
288 /* convert 16 bit integer to opaque */
289 INLINE static void c16toa(word16 u16, byte* c)
291 c[0] = (u16 >> 8) & 0xff;
296 /* convert 32 bit integer to opaque */
297 static INLINE void c32toa(word32 u32, byte* c)
299 c[0] = (u32 >> 24) & 0xff;
300 c[1] = (u32 >> 16) & 0xff;
301 c[2] = (u32 >> 8) & 0xff;
306 static INLINE word32 GetSEQIncrement(CYASSL* ssl, int verify)
309 if (ssl->options.dtls) {
311 return ssl->keys.dtls_peer_sequence_number; /* explicit from peer */
313 return ssl->keys.dtls_sequence_number - 1; /* already incremented */
317 return ssl->keys.peer_sequence_number++;
319 return ssl->keys.sequence_number++;
325 static INLINE word32 GetEpoch(CYASSL* ssl, int verify)
328 return ssl->keys.dtls_peer_epoch;
330 return ssl->keys.dtls_epoch;
333 #endif /* CYASSL_DTLS */
336 static INLINE const byte* GetMacSecret(CYASSL* ssl, int verify)
338 if ( (ssl->options.side == CLIENT_END && !verify) ||
339 (ssl->options.side == SERVER_END && verify) )
340 return ssl->keys.client_write_MAC_secret;
342 return ssl->keys.server_write_MAC_secret;
349 void TLS_hmac(CYASSL* ssl, byte* digest, const byte* in, word32 sz,
350 int content, int verify)
353 byte seq[SEQ_SZ] = { 0x00, 0x00, 0x00, 0x00 };
354 byte length[LENGTH_SZ];
355 byte inner[ENUM_LEN + VERSION_SZ + LENGTH_SZ]; /* type + version +len */
358 c16toa((word16)sz, length);
360 if (ssl->options.dtls)
361 c16toa(GetEpoch(ssl, verify), seq);
363 c32toa(GetSEQIncrement(ssl, verify), &seq[sizeof(word32)]);
365 if (ssl->specs.mac_algorithm == md5_mac)
367 else if (ssl->specs.mac_algorithm == sha_mac)
371 HmacSetKey(&hmac, type, GetMacSecret(ssl, verify), ssl->specs.hash_size);
373 HmacUpdate(&hmac, seq, SEQ_SZ); /* seq_num */
374 inner[0] = (byte)content; /* type */
375 inner[ENUM_LEN] = ssl->version.major;
376 inner[ENUM_LEN + ENUM_LEN] = ssl->version.minor; /* version */
377 XMEMCPY(&inner[ENUM_LEN + VERSION_SZ], length, LENGTH_SZ); /* length */
378 HmacUpdate(&hmac, inner, sizeof(inner));
379 HmacUpdate(&hmac, in, sz); /* content */
380 HmacFinal(&hmac, digest);
384 #ifndef NO_CYASSL_CLIENT
386 CYASSL_METHOD* CyaTLSv1_client_method(void)
388 CYASSL_METHOD* method =
389 (CYASSL_METHOD*) XMALLOC(sizeof(CYASSL_METHOD), 0,
390 DYNAMIC_TYPE_METHOD);
392 InitSSL_Method(method, MakeTLSv1());
397 CYASSL_METHOD* CyaTLSv1_1_client_method(void)
399 CYASSL_METHOD* method =
400 (CYASSL_METHOD*) XMALLOC(sizeof(CYASSL_METHOD), 0,
401 DYNAMIC_TYPE_METHOD);
403 InitSSL_Method(method, MakeTLSv1_1());
408 #ifndef NO_SHA256 /* can't use without SHA256 */
410 CYASSL_METHOD* CyaTLSv1_2_client_method(void)
412 CYASSL_METHOD* method =
413 (CYASSL_METHOD*) XMALLOC(sizeof(CYASSL_METHOD), 0,
414 DYNAMIC_TYPE_METHOD);
416 InitSSL_Method(method, MakeTLSv1_2());
423 CYASSL_METHOD* CyaSSLv23_client_method(void)
425 CYASSL_METHOD* method =
426 (CYASSL_METHOD*) XMALLOC(sizeof(CYASSL_METHOD), 0,
427 DYNAMIC_TYPE_METHOD);
429 #ifndef NO_SHA256 /* 1.2 requires SHA256 */
430 InitSSL_Method(method, MakeTLSv1_2());
432 InitSSL_Method(method, MakeTLSv1_1());
434 method->downgrade = 1;
440 #endif /* NO_CYASSL_CLIENT */
444 #ifndef NO_CYASSL_SERVER
446 CYASSL_METHOD* CyaTLSv1_server_method(void)
448 CYASSL_METHOD* method =
449 (CYASSL_METHOD*) XMALLOC(sizeof(CYASSL_METHOD), 0,
450 DYNAMIC_TYPE_METHOD);
452 InitSSL_Method(method, MakeTLSv1());
453 method->side = SERVER_END;
459 CYASSL_METHOD* CyaTLSv1_1_server_method(void)
461 CYASSL_METHOD* method =
462 (CYASSL_METHOD*) XMALLOC(sizeof(CYASSL_METHOD), 0,
463 DYNAMIC_TYPE_METHOD);
465 InitSSL_Method(method, MakeTLSv1_1());
466 method->side = SERVER_END;
472 #ifndef NO_SHA256 /* can't use without SHA256 */
474 CYASSL_METHOD* CyaTLSv1_2_server_method(void)
476 CYASSL_METHOD* method =
477 (CYASSL_METHOD*) XMALLOC(sizeof(CYASSL_METHOD), 0,
478 DYNAMIC_TYPE_METHOD);
480 InitSSL_Method(method, MakeTLSv1_2());
481 method->side = SERVER_END;
489 CYASSL_METHOD* CyaSSLv23_server_method(void)
491 CYASSL_METHOD* method =
492 (CYASSL_METHOD*) XMALLOC(sizeof(CYASSL_METHOD), 0,
493 DYNAMIC_TYPE_METHOD);
495 #ifndef NO_SHA256 /* 1.2 requires SHA256 */
496 InitSSL_Method(method, MakeTLSv1_2());
498 InitSSL_Method(method, MakeTLSv1_1());
500 method->side = SERVER_END;
501 method->downgrade = 1;
508 #endif /* NO_CYASSL_SERVER */
512 /* catch CyaSSL programming errors */
513 void BuildTlsFinished(CYASSL* ssl, Hashes* hashes, const byte* sender)
519 int DeriveTlsKeys(CYASSL* ssl)
521 return NOT_COMPILED_IN;
525 int MakeTlsMasterSecret(CYASSL* ssl)
527 return NOT_COMPILED_IN;