]> git.sur5r.net Git - freertos/blob - FreeRTOS-Plus/Source/CyaSSL/src/tls.c
f5ef46007c518b57e2955613bb18c038a41dab96
[freertos] / FreeRTOS-Plus / Source / CyaSSL / src / tls.c
1 /* tls.c
2  *
3  * Copyright (C) 2006-2012 Sawtooth Consulting Ltd.
4  *
5  * This file is part of CyaSSL.
6  *
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.
11  *
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.
16  *
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
20  */
21
22 #ifdef HAVE_CONFIG_H
23     #include <config.h>
24 #endif
25
26 #include <cyassl/ssl.h>
27 #include <cyassl/internal.h>
28 #include <cyassl/error.h>
29 #include <cyassl/ctaocrypt/hmac.h>
30
31
32
33 #ifndef NO_TLS
34
35
36 #ifndef min
37
38     static INLINE word32 min(word32 a, word32 b)
39     {
40         return a > b ? b : a;
41     }
42
43 #endif /* min */
44
45
46 /* calculate XOR for TLSv1 PRF */
47 static INLINE void get_xor(byte *digest, word32 digLen, byte* md5, byte* sha)
48 {
49     word32 i;
50
51     for (i = 0; i < digLen; i++) 
52         digest[i] = md5[i] ^ sha[i];
53 }
54
55
56 #ifdef CYASSL_SHA384
57     #define PHASH_MAX_DIGEST_SIZE SHA384_DIGEST_SIZE
58 #else
59     #define PHASH_MAX_DIGEST_SIZE SHA256_DIGEST_SIZE
60 #endif
61
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)
65 {
66     word32   len = MD5_DIGEST_SIZE;
67     word32   times;
68     word32   lastLen;
69     word32   lastTime;
70     word32   i;
71     word32   idx = 0;
72     byte     previous[PHASH_MAX_DIGEST_SIZE];  /* max size */
73     byte     current[PHASH_MAX_DIGEST_SIZE];   /* max size */
74
75     Hmac hmac;
76
77     if (hash == md5_mac) {
78         hash = MD5;
79     }
80     else if (hash == sha_mac) {
81         len = SHA_DIGEST_SIZE;
82         hash = SHA;
83     } else if (hash == sha256_mac) {
84         len = SHA256_DIGEST_SIZE;
85         hash = SHA256;
86     }
87 #ifdef CYASSL_SHA384
88     else if (hash == sha384_mac)
89     {
90         len = SHA384_DIGEST_SIZE;
91         hash = SHA384;
92     }
93 #endif
94
95     times = resLen / len;
96     lastLen = resLen % len;
97     if (lastLen) times += 1;
98     lastTime = times - 1;
99
100     HmacSetKey(&hmac, hash, secret, secLen);
101     HmacUpdate(&hmac, seed, seedLen);       /* A0 = seed */
102     HmacFinal(&hmac, previous);             /* A1 */
103
104     for (i = 0; i < times; i++) {
105         HmacUpdate(&hmac, previous, len);
106         HmacUpdate(&hmac, seed, seedLen);
107         HmacFinal(&hmac, current);
108
109         if ( (i == lastTime) && lastLen)
110             XMEMCPY(&result[idx], current, min(lastLen, sizeof(current)));
111         else {
112             XMEMCPY(&result[idx], current, len);
113             idx += len;
114             HmacUpdate(&hmac, previous, len);
115             HmacFinal(&hmac, previous);
116         }
117     }
118 }
119
120
121
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)
126 {
127     word32 half = (secLen + 1) / 2;
128
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 */
134
135     if (half > MAX_PRF_HALF)
136         return;
137     if (labLen + seedLen > MAX_PRF_LABSEED)
138         return;
139     if (digLen > MAX_PRF_DIG)
140         return;
141     
142     XMEMCPY(md5_half, secret, half);
143     XMEMCPY(sha_half, secret + half - secLen % 2, half);
144
145     XMEMCPY(labelSeed, label, labLen);
146     XMEMCPY(labelSeed + labLen, seed, seedLen);
147
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,
154                hash_type);
155         return;
156     }
157
158     p_hash(md5_result, digLen, md5_half, half, labelSeed, labLen + seedLen,
159            md5_mac);
160     p_hash(sha_result, digLen, sha_half, half, labelSeed, labLen + seedLen,
161            sha_mac);
162     get_xor(digest, digLen, md5_result, sha_result);
163 }
164
165
166 #ifdef CYASSL_SHA384
167     #define HSHASH_SZ SHA384_DIGEST_SIZE
168 #else
169     #define HSHASH_SZ FINISHED_SZ
170 #endif
171
172
173 void BuildTlsFinished(CYASSL* ssl, Hashes* hashes, const byte* sender)
174 {
175     const byte* side;
176     byte        handshake_hash[HSHASH_SZ];
177     word32      hashSz = FINISHED_SZ;
178
179     Md5Final(&ssl->hashMd5, handshake_hash);
180     ShaFinal(&ssl->hashSha, &handshake_hash[MD5_DIGEST_SIZE]);
181     if (IsAtLeastTLSv1_2(ssl)) {
182 #ifndef NO_SHA256
183         if (ssl->specs.mac_algorithm <= sha256_mac) {
184             Sha256Final(&ssl->hashSha256, handshake_hash);
185             hashSz = SHA256_DIGEST_SIZE;
186         }
187 #endif
188 #ifdef CYASSL_SHA384
189         if (ssl->specs.mac_algorithm == sha384_mac) {
190             Sha384Final(&ssl->hashSha384, handshake_hash);
191             hashSz = SHA384_DIGEST_SIZE;
192         }
193 #endif
194     }
195    
196     if ( XSTRNCMP((const char*)sender, (const char*)client, SIZEOF_SENDER) == 0)
197         side = tls_client;
198     else
199         side = tls_server;
200
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);
204 }
205
206
207 ProtocolVersion MakeTLSv1(void)
208 {
209     ProtocolVersion pv;
210     pv.major = SSLv3_MAJOR;
211     pv.minor = TLSv1_MINOR;
212
213     return pv;
214 }
215
216
217 ProtocolVersion MakeTLSv1_1(void)
218 {
219     ProtocolVersion pv;
220     pv.major = SSLv3_MAJOR;
221     pv.minor = TLSv1_1_MINOR;
222
223     return pv;
224 }
225
226
227 ProtocolVersion MakeTLSv1_2(void)
228 {
229     ProtocolVersion pv;
230     pv.major = SSLv3_MAJOR;
231     pv.minor = TLSv1_2_MINOR;
232
233     return pv;
234 }
235
236
237 static const byte master_label[MASTER_LABEL_SZ + 1] = "master secret";
238 static const byte key_label   [KEY_LABEL_SZ + 1]    = "key expansion";
239
240
241 int DeriveTlsKeys(CYASSL* ssl)
242 {
243     int length = 2 * ssl->specs.hash_size + 
244                  2 * ssl->specs.key_size  +
245                  2 * ssl->specs.iv_size;
246     byte         seed[SEED_LEN];
247     byte         key_data[MAX_PRF_DIG];
248
249     XMEMCPY(seed, ssl->arrays.serverRandom, RAN_LEN);
250     XMEMCPY(&seed[RAN_LEN], ssl->arrays.clientRandom, RAN_LEN);
251
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);
255
256     return StoreKeys(ssl, key_data);
257 }
258
259
260 int MakeTlsMasterSecret(CYASSL* ssl)
261 {
262     byte seed[SEED_LEN];
263     
264     XMEMCPY(seed, ssl->arrays.clientRandom, RAN_LEN);
265     XMEMCPY(&seed[RAN_LEN], ssl->arrays.serverRandom, RAN_LEN);
266
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);
271
272 #ifdef SHOW_SECRETS
273     {
274         int i;
275         printf("master secret: ");
276         for (i = 0; i < SECRET_LEN; i++)
277             printf("%02x", ssl->arrays.masterSecret[i]);
278         printf("\n");
279     }
280 #endif
281
282     return DeriveTlsKeys(ssl);
283 }
284
285
286 /*** next for static INLINE s copied from cyassl_int.c ***/
287
288 /* convert 16 bit integer to opaque */
289 INLINE static void c16toa(word16 u16, byte* c)
290 {
291     c[0] = (u16 >> 8) & 0xff;
292     c[1] =  u16 & 0xff;
293 }
294
295
296 /* convert 32 bit integer to opaque */
297 static INLINE void c32toa(word32 u32, byte* c)
298 {
299     c[0] = (u32 >> 24) & 0xff;
300     c[1] = (u32 >> 16) & 0xff;
301     c[2] = (u32 >>  8) & 0xff;
302     c[3] =  u32 & 0xff;
303 }
304
305
306 static INLINE word32 GetSEQIncrement(CYASSL* ssl, int verify)
307 {
308 #ifdef CYASSL_DTLS
309     if (ssl->options.dtls) {
310         if (verify)
311             return ssl->keys.dtls_peer_sequence_number; /* explicit from peer */
312         else
313             return ssl->keys.dtls_sequence_number - 1; /* already incremented */
314     }
315 #endif
316     if (verify)
317         return ssl->keys.peer_sequence_number++; 
318     else
319         return ssl->keys.sequence_number++; 
320 }
321
322
323 #ifdef CYASSL_DTLS
324
325 static INLINE word32 GetEpoch(CYASSL* ssl, int verify)
326 {
327     if (verify)
328         return ssl->keys.dtls_peer_epoch; 
329     else
330         return ssl->keys.dtls_epoch; 
331 }
332
333 #endif /* CYASSL_DTLS */
334
335
336 static INLINE const byte* GetMacSecret(CYASSL* ssl, int verify)
337 {
338     if ( (ssl->options.side == CLIENT_END && !verify) ||
339          (ssl->options.side == SERVER_END &&  verify) )
340         return ssl->keys.client_write_MAC_secret;
341     else
342         return ssl->keys.server_write_MAC_secret;
343 }
344
345 /*** end copy ***/
346
347
348 /* TLS type HMAC */
349 void TLS_hmac(CYASSL* ssl, byte* digest, const byte* in, word32 sz,
350               int content, int verify)
351 {
352     Hmac hmac;
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 */
356     int  type;
357
358     c16toa((word16)sz, length);
359 #ifdef CYASSL_DTLS
360     if (ssl->options.dtls)
361         c16toa(GetEpoch(ssl, verify), seq);
362 #endif
363     c32toa(GetSEQIncrement(ssl, verify), &seq[sizeof(word32)]);
364     
365     if (ssl->specs.mac_algorithm == md5_mac)
366         type = MD5;
367     else if (ssl->specs.mac_algorithm == sha_mac)
368         type = SHA;
369     else
370         type = SHA256;
371     HmacSetKey(&hmac, type, GetMacSecret(ssl, verify), ssl->specs.hash_size);
372     
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);
381 }
382
383
384 #ifndef NO_CYASSL_CLIENT
385
386     CYASSL_METHOD* CyaTLSv1_client_method(void)
387     {
388         CYASSL_METHOD* method =
389                              (CYASSL_METHOD*) XMALLOC(sizeof(CYASSL_METHOD), 0,
390                                                       DYNAMIC_TYPE_METHOD);
391         if (method)
392             InitSSL_Method(method, MakeTLSv1());
393         return method;
394     }
395
396
397     CYASSL_METHOD* CyaTLSv1_1_client_method(void)
398     {
399         CYASSL_METHOD* method =
400                               (CYASSL_METHOD*) XMALLOC(sizeof(CYASSL_METHOD), 0,
401                                                        DYNAMIC_TYPE_METHOD);
402         if (method)
403             InitSSL_Method(method, MakeTLSv1_1());
404         return method;
405     }
406
407
408 #ifndef NO_SHA256   /* can't use without SHA256 */
409
410     CYASSL_METHOD* CyaTLSv1_2_client_method(void)
411     {
412         CYASSL_METHOD* method =
413                               (CYASSL_METHOD*) XMALLOC(sizeof(CYASSL_METHOD), 0,
414                                                        DYNAMIC_TYPE_METHOD);
415         if (method)
416             InitSSL_Method(method, MakeTLSv1_2());
417         return method;
418     }
419
420 #endif
421
422
423     CYASSL_METHOD* CyaSSLv23_client_method(void)
424     {
425         CYASSL_METHOD* method =
426                               (CYASSL_METHOD*) XMALLOC(sizeof(CYASSL_METHOD), 0,
427                                                        DYNAMIC_TYPE_METHOD);
428         if (method) {
429 #ifndef NO_SHA256         /* 1.2 requires SHA256 */
430             InitSSL_Method(method, MakeTLSv1_2());
431 #else
432             InitSSL_Method(method, MakeTLSv1_1());
433 #endif
434             method->downgrade = 1;
435         }
436         return method;
437     }
438
439
440 #endif /* NO_CYASSL_CLIENT */
441
442
443
444 #ifndef NO_CYASSL_SERVER
445
446     CYASSL_METHOD* CyaTLSv1_server_method(void)
447     {
448         CYASSL_METHOD* method =
449                               (CYASSL_METHOD*) XMALLOC(sizeof(CYASSL_METHOD), 0,
450                                                        DYNAMIC_TYPE_METHOD);
451         if (method) {
452             InitSSL_Method(method, MakeTLSv1());
453             method->side = SERVER_END;
454         }
455         return method;
456     }
457
458
459     CYASSL_METHOD* CyaTLSv1_1_server_method(void)
460     {
461         CYASSL_METHOD* method =
462                               (CYASSL_METHOD*) XMALLOC(sizeof(CYASSL_METHOD), 0,
463                                                        DYNAMIC_TYPE_METHOD);
464         if (method) {
465             InitSSL_Method(method, MakeTLSv1_1());
466             method->side = SERVER_END;
467         }
468         return method;
469     }
470
471
472 #ifndef NO_SHA256   /* can't use without SHA256 */
473
474     CYASSL_METHOD* CyaTLSv1_2_server_method(void)
475     {
476         CYASSL_METHOD* method =
477                               (CYASSL_METHOD*) XMALLOC(sizeof(CYASSL_METHOD), 0,
478                                                        DYNAMIC_TYPE_METHOD);
479         if (method) {
480             InitSSL_Method(method, MakeTLSv1_2());
481             method->side = SERVER_END;
482         }
483         return method;
484     }
485
486 #endif
487
488
489     CYASSL_METHOD* CyaSSLv23_server_method(void)
490     {
491         CYASSL_METHOD* method =
492                               (CYASSL_METHOD*) XMALLOC(sizeof(CYASSL_METHOD), 0,
493                                                        DYNAMIC_TYPE_METHOD);
494         if (method) {
495 #ifndef NO_SHA256         /* 1.2 requires SHA256 */
496             InitSSL_Method(method, MakeTLSv1_2());
497 #else
498             InitSSL_Method(method, MakeTLSv1_1());
499 #endif
500             method->side      = SERVER_END;
501             method->downgrade = 1;
502         }
503         return method;
504     }
505
506
507
508 #endif /* NO_CYASSL_SERVER */
509
510 #else /* NO_TLS */
511
512 /* catch CyaSSL programming errors */
513 void BuildTlsFinished(CYASSL* ssl, Hashes* hashes, const byte* sender)
514 {
515    
516 }
517
518
519 int DeriveTlsKeys(CYASSL* ssl)
520 {
521     return NOT_COMPILED_IN;
522 }
523
524
525 int MakeTlsMasterSecret(CYASSL* ssl)
526
527     return NOT_COMPILED_IN;
528 }
529
530 #endif /* NO_TLS */
531