cyassl re-port with cellular comms, PSK test

Dependencies:   VodafoneUSBModem_bleedingedge2 mbed-rtos mbed-src

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers tls.c Source File

tls.c

00001 /* tls.c
00002  *
00003  * Copyright (C) 2006-2012 Sawtooth Consulting Ltd.
00004  *
00005  * This file is part of CyaSSL.
00006  *
00007  * CyaSSL is free software; you can redistribute it and/or modify
00008  * it under the terms of the GNU General Public License as published by
00009  * the Free Software Foundation; either version 2 of the License, or
00010  * (at your option) any later version.
00011  *
00012  * CyaSSL is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
00020  */
00021 
00022 #ifdef HAVE_CONFIG_H
00023     #include <config.h>
00024 #endif
00025 
00026 #include <cyassl/ssl.h>
00027 #include <cyassl/internal.h>
00028 #include <cyassl/error.h>
00029 #include <cyassl/ctaocrypt/hmac.h>
00030 
00031 
00032 
00033 #ifndef NO_TLS
00034 
00035 
00036 #ifndef min
00037 
00038     static INLINE word32 min(word32 a, word32 b)
00039     {
00040         return a > b ? b : a;
00041     }
00042 
00043 #endif /* min */
00044 
00045 
00046 #ifdef CYASSL_SHA384
00047     #define PHASH_MAX_DIGEST_SIZE SHA384_DIGEST_SIZE
00048 #else
00049     #define PHASH_MAX_DIGEST_SIZE SHA256_DIGEST_SIZE
00050 #endif
00051 
00052 /* compute p_hash for MD5, SHA-1, SHA-256, or SHA-384 for TLSv1 PRF */
00053 static void p_hash(byte* result, word32 resLen, const byte* secret,
00054                    word32 secLen, const byte* seed, word32 seedLen, int hash)
00055 {
00056     word32   len = SHA_DIGEST_SIZE;
00057     word32   times;
00058     word32   lastLen;
00059     word32   lastTime;
00060     word32   i;
00061     word32   idx = 0;
00062     byte     previous[PHASH_MAX_DIGEST_SIZE];  /* max size */
00063     byte     current[PHASH_MAX_DIGEST_SIZE];   /* max size */
00064 
00065     Hmac hmac;
00066 
00067     switch (hash) {
00068         #ifndef NO_MD5
00069         case md5_mac:
00070         {
00071             len = MD5_DIGEST_SIZE;
00072             hash = MD5;
00073         }
00074         break;
00075         #endif
00076         #ifndef NO_SHA256
00077         case sha256_mac:
00078         {
00079             len = SHA256_DIGEST_SIZE;
00080             hash = SHA256;
00081         }
00082         break;
00083         #endif
00084         #ifdef CYASSL_SHA384
00085         case sha384_mac:
00086         {
00087             len = SHA384_DIGEST_SIZE;
00088             hash = SHA384;
00089         }
00090         break;
00091         #endif
00092         case sha_mac:
00093         default:
00094         {
00095             len = SHA_DIGEST_SIZE;
00096             hash = SHA;
00097         }
00098         break;
00099     }
00100 
00101     times = resLen / len;
00102     lastLen = resLen % len;
00103     if (lastLen) times += 1;
00104     lastTime = times - 1;
00105 
00106     HmacSetKey(&hmac, hash, secret, secLen);
00107     HmacUpdate(&hmac, seed, seedLen);       /* A0 = seed */
00108     HmacFinal(&hmac, previous);             /* A1 */
00109 
00110     for (i = 0; i < times; i++) {
00111         HmacUpdate(&hmac, previous, len);
00112         HmacUpdate(&hmac, seed, seedLen);
00113         HmacFinal(&hmac, current);
00114 
00115         if ( (i == lastTime) && lastLen)
00116             XMEMCPY(&result[idx], current, min(lastLen, sizeof(current)));
00117         else {
00118             XMEMCPY(&result[idx], current, len);
00119             idx += len;
00120             HmacUpdate(&hmac, previous, len);
00121             HmacFinal(&hmac, previous);
00122         }
00123     }
00124 }
00125 
00126 
00127 
00128 #ifndef NO_MD5
00129 
00130 /* calculate XOR for TLSv1 PRF */
00131 static INLINE void get_xor(byte *digest, word32 digLen, byte* md5, byte* sha)
00132 {
00133     word32 i;
00134 
00135     for (i = 0; i < digLen; i++) 
00136         digest[i] = md5[i] ^ sha[i];
00137 }
00138 
00139 
00140 /* compute TLSv1 PRF (pseudo random function using HMAC) */
00141 static void doPRF(byte* digest, word32 digLen, const byte* secret,word32 secLen,
00142             const byte* label, word32 labLen, const byte* seed, word32 seedLen)
00143 {
00144     word32 half = (secLen + 1) / 2;
00145 
00146     byte md5_half[MAX_PRF_HALF];        /* half is real size */
00147     byte sha_half[MAX_PRF_HALF];        /* half is real size */
00148     byte labelSeed[MAX_PRF_LABSEED];    /* labLen + seedLen is real size */
00149     byte md5_result[MAX_PRF_DIG];       /* digLen is real size */
00150     byte sha_result[MAX_PRF_DIG];       /* digLen is real size */
00151 
00152     if (half > MAX_PRF_HALF)
00153         return;
00154     if (labLen + seedLen > MAX_PRF_LABSEED)
00155         return;
00156     if (digLen > MAX_PRF_DIG)
00157         return;
00158     
00159     XMEMCPY(md5_half, secret, half);
00160     XMEMCPY(sha_half, secret + half - secLen % 2, half);
00161 
00162     XMEMCPY(labelSeed, label, labLen);
00163     XMEMCPY(labelSeed + labLen, seed, seedLen);
00164 
00165     p_hash(md5_result, digLen, md5_half, half, labelSeed, labLen + seedLen,
00166            md5_mac);
00167     p_hash(sha_result, digLen, sha_half, half, labelSeed, labLen + seedLen,
00168            sha_mac);
00169     get_xor(digest, digLen, md5_result, sha_result);
00170 }
00171 
00172 #endif
00173 
00174 
00175 /* Wrapper to call straight thru to p_hash in TSL 1.2 cases to remove stack
00176    use */
00177 static void PRF(byte* digest, word32 digLen, const byte* secret, word32 secLen,
00178             const byte* label, word32 labLen, const byte* seed, word32 seedLen,
00179             int useAtLeastSha256, int hash_type)
00180 {
00181     if (useAtLeastSha256) {
00182         byte labelSeed[MAX_PRF_LABSEED];    /* labLen + seedLen is real size */
00183 
00184         if (labLen + seedLen > MAX_PRF_LABSEED)
00185             return;
00186 
00187         XMEMCPY(labelSeed, label, labLen);
00188         XMEMCPY(labelSeed + labLen, seed, seedLen);
00189 
00190         /* If a cipher suite wants an algorithm better than sha256, it
00191          * should use better. */
00192         if (hash_type < sha256_mac)
00193             hash_type = sha256_mac;
00194         p_hash(digest, digLen, secret, secLen, labelSeed, labLen + seedLen,
00195                hash_type);
00196     }
00197 #ifndef NO_MD5
00198     else
00199         doPRF(digest, digLen, secret, secLen, label, labLen, seed, seedLen);
00200 #endif
00201 }
00202 
00203 
00204 #ifdef CYASSL_SHA384
00205     #define HSHASH_SZ SHA384_DIGEST_SIZE
00206 #else
00207     #define HSHASH_SZ FINISHED_SZ
00208 #endif
00209 
00210 
00211 void BuildTlsFinished(CYASSL* ssl, Hashes* hashes, const byte* sender)
00212 {
00213     const byte* side;
00214     byte        handshake_hash[HSHASH_SZ];
00215     word32      hashSz = FINISHED_SZ;
00216 
00217 #ifndef NO_MD5
00218     Md5Final(&ssl->hashMd5, handshake_hash);
00219     ShaFinal(&ssl->hashSha, &handshake_hash[MD5_DIGEST_SIZE]);
00220 #endif
00221     
00222     if (IsAtLeastTLSv1_2(ssl)) {
00223 #ifndef NO_SHA256
00224         if (ssl->specs.mac_algorithm <= sha256_mac) {
00225             Sha256Final(&ssl->hashSha256, handshake_hash);
00226             hashSz = SHA256_DIGEST_SIZE;
00227         }
00228 #endif
00229 #ifdef CYASSL_SHA384
00230         if (ssl->specs.mac_algorithm == sha384_mac) {
00231             Sha384Final(&ssl->hashSha384, handshake_hash);
00232             hashSz = SHA384_DIGEST_SIZE;
00233         }
00234 #endif
00235     }
00236    
00237     if ( XSTRNCMP((const char*)sender, (const char*)client, SIZEOF_SENDER) == 0)
00238         side = tls_client;
00239     else
00240         side = tls_server;
00241 
00242 #ifndef NO_MD5
00243     PRF(hashes->md5, TLS_FINISHED_SZ, ssl->arrays->masterSecret, SECRET_LEN,
00244         side, FINISHED_LABEL_SZ, handshake_hash, hashSz, IsAtLeastTLSv1_2(ssl),
00245         ssl->specs.mac_algorithm);
00246 #else
00247     PRF(hashes->hash, TLS_FINISHED_SZ, ssl->arrays->masterSecret, SECRET_LEN,
00248         side, FINISHED_LABEL_SZ, handshake_hash, hashSz, IsAtLeastTLSv1_2(ssl),
00249         ssl->specs.mac_algorithm);
00250 #endif
00251 }
00252 
00253 
00254 #ifndef NO_OLD_TLS
00255 
00256 ProtocolVersion MakeTLSv1(void)
00257 {
00258     ProtocolVersion pv;
00259     pv.major = SSLv3_MAJOR;
00260     pv.minor = TLSv1_MINOR;
00261 
00262     return pv;
00263 }
00264 
00265 
00266 ProtocolVersion MakeTLSv1_1(void)
00267 {
00268     ProtocolVersion pv;
00269     pv.major = SSLv3_MAJOR;
00270     pv.minor = TLSv1_1_MINOR;
00271 
00272     return pv;
00273 }
00274 
00275 #endif
00276 
00277 
00278 ProtocolVersion MakeTLSv1_2(void)
00279 {
00280     ProtocolVersion pv;
00281     pv.major = SSLv3_MAJOR;
00282     pv.minor = TLSv1_2_MINOR;
00283 
00284     return pv;
00285 }
00286 
00287 
00288 static const byte master_label[MASTER_LABEL_SZ + 1] = "master secret";
00289 static const byte key_label   [KEY_LABEL_SZ + 1]    = "key expansion";
00290 
00291 
00292 int DeriveTlsKeys(CYASSL* ssl)
00293 {
00294     int length = 2 * ssl->specs.hash_size + 
00295                  2 * ssl->specs.key_size  +
00296                  2 * ssl->specs.iv_size;
00297     byte         seed[SEED_LEN];
00298     byte         key_data[MAX_PRF_DIG];
00299 
00300     XMEMCPY(seed, ssl->arrays->serverRandom, RAN_LEN);
00301     XMEMCPY(&seed[RAN_LEN], ssl->arrays->clientRandom, RAN_LEN);
00302 
00303     PRF(key_data, length, ssl->arrays->masterSecret, SECRET_LEN, key_label,
00304         KEY_LABEL_SZ, seed, SEED_LEN, IsAtLeastTLSv1_2(ssl),
00305         ssl->specs.mac_algorithm);
00306 
00307     return StoreKeys(ssl, key_data);
00308 }
00309 
00310 
00311 int MakeTlsMasterSecret(CYASSL* ssl)
00312 {
00313     byte seed[SEED_LEN];
00314     
00315     XMEMCPY(seed, ssl->arrays->clientRandom, RAN_LEN);
00316     XMEMCPY(&seed[RAN_LEN], ssl->arrays->serverRandom, RAN_LEN);
00317 
00318     PRF(ssl->arrays->masterSecret, SECRET_LEN,
00319         ssl->arrays->preMasterSecret, ssl->arrays->preMasterSz,
00320         master_label, MASTER_LABEL_SZ, 
00321         seed, SEED_LEN, IsAtLeastTLSv1_2(ssl), ssl->specs.mac_algorithm);
00322 
00323 #ifdef SHOW_SECRETS
00324     {
00325         int i;
00326         printf("master secret: ");
00327         for (i = 0; i < SECRET_LEN; i++)
00328             printf("%02x", ssl->arrays->masterSecret[i]);
00329         printf("\n");
00330     }
00331 #endif
00332 
00333     return DeriveTlsKeys(ssl);
00334 }
00335 
00336 
00337 /*** next for static INLINE s copied from cyassl_int.c ***/
00338 
00339 /* convert 16 bit integer to opaque */
00340 INLINE static void c16toa(word16 u16, byte* c)
00341 {
00342     c[0] = (u16 >> 8) & 0xff;
00343     c[1] =  u16 & 0xff;
00344 }
00345 
00346 
00347 /* convert 32 bit integer to opaque */
00348 static INLINE void c32toa(word32 u32, byte* c)
00349 {
00350     c[0] = (u32 >> 24) & 0xff;
00351     c[1] = (u32 >> 16) & 0xff;
00352     c[2] = (u32 >>  8) & 0xff;
00353     c[3] =  u32 & 0xff;
00354 }
00355 
00356 
00357 static INLINE word32 GetSEQIncrement(CYASSL* ssl, int verify)
00358 {
00359 #ifdef CYASSL_DTLS
00360     if (ssl->options.dtls) {
00361         if (verify)
00362             return ssl->keys.dtls_peer_sequence_number; /* explicit from peer */
00363         else
00364             return ssl->keys.dtls_sequence_number - 1; /* already incremented */
00365     }
00366 #endif
00367     if (verify)
00368         return ssl->keys.peer_sequence_number++; 
00369     else
00370         return ssl->keys.sequence_number++; 
00371 }
00372 
00373 
00374 #ifdef CYASSL_DTLS
00375 
00376 static INLINE word32 GetEpoch(CYASSL* ssl, int verify)
00377 {
00378     if (verify)
00379         return ssl->keys.dtls_peer_epoch; 
00380     else
00381         return ssl->keys.dtls_epoch; 
00382 }
00383 
00384 #endif /* CYASSL_DTLS */
00385 
00386 
00387 static INLINE const byte* GetMacSecret(CYASSL* ssl, int verify)
00388 {
00389     if ( (ssl->options.side == CLIENT_END && !verify) ||
00390          (ssl->options.side == SERVER_END &&  verify) )
00391         return ssl->keys.client_write_MAC_secret;
00392     else
00393         return ssl->keys.server_write_MAC_secret;
00394 }
00395 
00396 /*** end copy ***/
00397 
00398 
00399 /* TLS type HMAC */
00400 void TLS_hmac(CYASSL* ssl, byte* digest, const byte* in, word32 sz,
00401               int content, int verify)
00402 {
00403     Hmac hmac;
00404     byte seq[SEQ_SZ];
00405     byte length[LENGTH_SZ];
00406     byte inner[ENUM_LEN + VERSION_SZ + LENGTH_SZ]; /* type + version +len */
00407     int  type;
00408 
00409     XMEMSET(seq, 0, SEQ_SZ);
00410     c16toa((word16)sz, length);
00411 #ifdef CYASSL_DTLS
00412     if (ssl->options.dtls)
00413         c16toa((word16)GetEpoch(ssl, verify), seq);
00414 #endif
00415     c32toa(GetSEQIncrement(ssl, verify), &seq[sizeof(word32)]);
00416     
00417     switch (ssl->specs.mac_algorithm) {
00418         #ifndef NO_MD5
00419         case md5_mac:
00420         {
00421             type = MD5;
00422         }
00423         break;
00424         #endif
00425         #ifndef NO_SHA256
00426         case sha256_mac:
00427         {
00428             type = SHA256;
00429         }
00430         break;
00431         #endif
00432         case sha_mac:
00433         default:
00434         {
00435             type = SHA;
00436         }
00437         break;
00438     }
00439     HmacSetKey(&hmac, type, GetMacSecret(ssl, verify), ssl->specs.hash_size);
00440     
00441     HmacUpdate(&hmac, seq, SEQ_SZ);                               /* seq_num */
00442     inner[0] = (byte)content;                                     /* type */
00443     inner[ENUM_LEN] = ssl->version.major;
00444     inner[ENUM_LEN + ENUM_LEN] = ssl->version.minor;              /* version */
00445     XMEMCPY(&inner[ENUM_LEN + VERSION_SZ], length, LENGTH_SZ);     /* length */
00446     HmacUpdate(&hmac, inner, sizeof(inner));
00447     HmacUpdate(&hmac, in, sz);                                /* content */
00448     HmacFinal(&hmac, digest);
00449 }
00450 
00451 
00452 #ifndef NO_CYASSL_CLIENT
00453 
00454 #ifndef NO_OLD_TLS
00455 
00456     CYASSL_METHOD* CyaTLSv1_client_method(void)
00457     {
00458         CYASSL_METHOD* method =
00459                              (CYASSL_METHOD*) XMALLOC(sizeof(CYASSL_METHOD), 0,
00460                                                       DYNAMIC_TYPE_METHOD);
00461         if (method)
00462             InitSSL_Method(method, MakeTLSv1());
00463         return method;
00464     }
00465 
00466 
00467     CYASSL_METHOD* CyaTLSv1_1_client_method(void)
00468     {
00469         CYASSL_METHOD* method =
00470                               (CYASSL_METHOD*) XMALLOC(sizeof(CYASSL_METHOD), 0,
00471                                                        DYNAMIC_TYPE_METHOD);
00472         if (method)
00473             InitSSL_Method(method, MakeTLSv1_1());
00474         return method;
00475     }
00476 
00477 #endif /* !NO_OLD_TLS */
00478 
00479 #ifndef NO_SHA256   /* can't use without SHA256 */
00480 
00481     CYASSL_METHOD* CyaTLSv1_2_client_method(void)
00482     {
00483         CYASSL_METHOD* method =
00484                               (CYASSL_METHOD*) XMALLOC(sizeof(CYASSL_METHOD), 0,
00485                                                        DYNAMIC_TYPE_METHOD);
00486         if (method)
00487             InitSSL_Method(method, MakeTLSv1_2());
00488         return method;
00489     }
00490 
00491 #endif
00492 
00493 
00494     CYASSL_METHOD* CyaSSLv23_client_method(void)
00495     {
00496         CYASSL_METHOD* method =
00497                               (CYASSL_METHOD*) XMALLOC(sizeof(CYASSL_METHOD), 0,
00498                                                        DYNAMIC_TYPE_METHOD);
00499         if (method) {
00500 #ifndef NO_SHA256         /* 1.2 requires SHA256 */
00501             InitSSL_Method(method, MakeTLSv1_2());
00502 #else
00503             InitSSL_Method(method, MakeTLSv1_1());
00504 #endif
00505 #ifndef NO_OLD_TLS
00506             method->downgrade = 1;
00507 #endif 
00508         }
00509         return method;
00510     }
00511 
00512 
00513 #endif /* NO_CYASSL_CLIENT */
00514 
00515 
00516 
00517 #ifndef NO_CYASSL_SERVER
00518 
00519 #ifndef NO_OLD_TLS
00520 
00521     CYASSL_METHOD* CyaTLSv1_server_method(void)
00522     {
00523         CYASSL_METHOD* method =
00524                               (CYASSL_METHOD*) XMALLOC(sizeof(CYASSL_METHOD), 0,
00525                                                        DYNAMIC_TYPE_METHOD);
00526         if (method) {
00527             InitSSL_Method(method, MakeTLSv1());
00528             method->side = SERVER_END;
00529         }
00530         return method;
00531     }
00532 
00533 
00534     CYASSL_METHOD* CyaTLSv1_1_server_method(void)
00535     {
00536         CYASSL_METHOD* method =
00537                               (CYASSL_METHOD*) XMALLOC(sizeof(CYASSL_METHOD), 0,
00538                                                        DYNAMIC_TYPE_METHOD);
00539         if (method) {
00540             InitSSL_Method(method, MakeTLSv1_1());
00541             method->side = SERVER_END;
00542         }
00543         return method;
00544     }
00545 
00546 #endif /* !NO_OLD_TLS */
00547 
00548 #ifndef NO_SHA256   /* can't use without SHA256 */
00549 
00550     CYASSL_METHOD* CyaTLSv1_2_server_method(void)
00551     {
00552         CYASSL_METHOD* method =
00553                               (CYASSL_METHOD*) XMALLOC(sizeof(CYASSL_METHOD), 0,
00554                                                        DYNAMIC_TYPE_METHOD);
00555         if (method) {
00556             InitSSL_Method(method, MakeTLSv1_2());
00557             method->side = SERVER_END;
00558         }
00559         return method;
00560     }
00561 
00562 #endif
00563 
00564 
00565     CYASSL_METHOD* CyaSSLv23_server_method(void)
00566     {
00567         CYASSL_METHOD* method =
00568                               (CYASSL_METHOD*) XMALLOC(sizeof(CYASSL_METHOD), 0,
00569                                                        DYNAMIC_TYPE_METHOD);
00570         if (method) {
00571 #ifndef NO_SHA256         /* 1.2 requires SHA256 */
00572             InitSSL_Method(method, MakeTLSv1_2());
00573 #else
00574             InitSSL_Method(method, MakeTLSv1_1());
00575 #endif
00576             method->side      = SERVER_END;
00577 #ifndef NO_OLD_TLS
00578             method->downgrade = 1;
00579 #endif /* !NO_OLD_TLS */
00580         }
00581         return method;
00582     }
00583 
00584 
00585 
00586 #endif /* NO_CYASSL_SERVER */
00587 
00588 #else /* NO_TLS */
00589 
00590 /* catch CyaSSL programming errors */
00591 void BuildTlsFinished(CYASSL* ssl, Hashes* hashes, const byte* sender)
00592 {
00593    
00594 }
00595 
00596 
00597 int DeriveTlsKeys(CYASSL* ssl)
00598 {
00599     return NOT_COMPILED_IN;
00600 }
00601 
00602 
00603 int MakeTlsMasterSecret(CYASSL* ssl)
00604 { 
00605     return NOT_COMPILED_IN;
00606 }
00607 
00608 #endif /* NO_TLS */
00609