gnutls_cipher.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation
00003  *
00004  * Author: Nikos Mavrogiannopoulos
00005  *
00006  * This file is part of GNUTLS.
00007  *
00008  * The GNUTLS library is free software; you can redistribute it and/or
00009  * modify it under the terms of the GNU Lesser General Public License
00010  * as published by the Free Software Foundation; either version 2.1 of
00011  * the License, or (at your option) any later version.
00012  *
00013  * This library is distributed in the hope that it will be useful, but
00014  * WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00016  * Lesser General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU Lesser General Public
00019  * License along with this library; if not, write to the Free Software
00020  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
00021  * USA
00022  *
00023  */
00024 
00025 /* Some high level functions to be used in the record encryption are
00026  * included here.
00027  */
00028 
00029 #include "gnutls_int.h"
00030 #include "gnutls_errors.h"
00031 #include "gnutls_cipher.h"
00032 #include "gnutls_algorithms.h"
00033 #include "gnutls_hash_int.h"
00034 #include "gnutls_cipher_int.h"
00035 #include "debug.h"
00036 #include "gnutls_num.h"
00037 #include "gnutls_datum.h"
00038 #include "gnutls_kx.h"
00039 #include "gnutls_record.h"
00040 #include "gnutls_constate.h"
00041 #include <gc.h>
00042 
00043 /* returns ciphertext which contains the headers too. This also
00044  * calculates the size in the header field.
00045  *
00046  * If random pad != 0 then the random pad data will be appended.
00047  */
00048 int
00049 MHD_gtls_encrypt (MHD_gtls_session_t session, const opaque * headers,
00050                   size_t headers_size, const opaque * data,
00051                   size_t data_size, opaque * ciphertext,
00052                   size_t ciphertext_size, content_type_t type, int random_pad)
00053 {
00054   MHD_gnutls_datum_t plain;
00055   MHD_gnutls_datum_t comp;
00056   int ret;
00057   int free_comp = 1;
00058 
00059   plain.data = (opaque *) data;
00060   plain.size = data_size;
00061 
00062   comp = plain;
00063   free_comp = 0;
00064   ret = MHD_gtls_compressed2ciphertext (session, &ciphertext[headers_size],
00065                                         ciphertext_size - headers_size,
00066                                         comp, type, random_pad);
00067 
00068   if (free_comp)
00069     MHD__gnutls_free_datum (&comp);
00070 
00071   if (ret < 0)
00072     {
00073       MHD_gnutls_assert ();
00074       return ret;
00075     }
00076 
00077 
00078   /* copy the headers */
00079   memcpy (ciphertext, headers, headers_size);
00080   MHD_gtls_write_uint16 (ret, &ciphertext[3]);
00081 
00082   return ret + headers_size;
00083 }
00084 
00085 /* Decrypts the given data.
00086  * Returns the decrypted data length.
00087  */
00088 int
00089 MHD_gtls_decrypt (MHD_gtls_session_t session, opaque * ciphertext,
00090                   size_t ciphertext_size, uint8_t * data,
00091                   size_t max_data_size, content_type_t type)
00092 {
00093   MHD_gnutls_datum_t gcipher;
00094 
00095   if (ciphertext_size == 0)
00096     return 0;
00097 
00098   gcipher.size = ciphertext_size;
00099   gcipher.data = ciphertext;
00100 
00101   return
00102     MHD_gtls_ciphertext2compressed (session, data, max_data_size,
00103                                     gcipher, type);
00104 }
00105 
00106 inline static mac_hd_t
00107 mac_init (enum MHD_GNUTLS_HashAlgorithm mac, opaque * secret, int secret_size,
00108           int ver)
00109 {
00110   mac_hd_t td;
00111 
00112   if (mac == MHD_GNUTLS_MAC_NULL)
00113     return GNUTLS_MAC_FAILED;
00114 
00115   if (ver == MHD_GNUTLS_PROTOCOL_SSL3)
00116     {                           /* SSL 3.0 */
00117       td = MHD_gnutls_mac_init_ssl3 (mac, secret, secret_size);
00118     }
00119   else
00120     {                           /* TLS 1.x */
00121       td = MHD_gtls_MHD_hmac_init (mac, secret, secret_size);
00122     }
00123 
00124   return td;
00125 }
00126 
00127 inline static void
00128 mac_deinit (mac_hd_t td, opaque * res, int ver)
00129 {
00130   if (ver == MHD_GNUTLS_PROTOCOL_SSL3)
00131     {                           /* SSL 3.0 */
00132       MHD_gnutls_mac_deinit_ssl3 (td, res);
00133     }
00134   else
00135     {
00136       MHD_gnutls_MHD_hmac_deinit (td, res);
00137     }
00138 }
00139 
00140 inline static int
00141 calc_enc_length (MHD_gtls_session_t session, int data_size,
00142                  int hash_size, uint8_t * pad, int random_pad,
00143                  cipher_type_t block_algo, uint16_t blocksize)
00144 {
00145   uint8_t rnd;
00146   int length;
00147 
00148   *pad = 0;
00149 
00150   switch (block_algo)
00151     {
00152     case CIPHER_STREAM:
00153       length = data_size + hash_size;
00154 
00155       break;
00156     case CIPHER_BLOCK:
00157       if (MHD_gc_nonce ((char *) &rnd, 1) != GC_OK)
00158         {
00159           MHD_gnutls_assert ();
00160           return GNUTLS_E_RANDOM_FAILED;
00161         }
00162 
00163       /* make rnd a multiple of blocksize */
00164       if (session->security_parameters.version == MHD_GNUTLS_PROTOCOL_SSL3 ||
00165           random_pad == 0)
00166         {
00167           rnd = 0;
00168         }
00169       else
00170         {
00171           rnd = (rnd / blocksize) * blocksize;
00172           /* added to avoid the case of pad calculated 0
00173            * seen below for pad calculation.
00174            */
00175           if (rnd > blocksize)
00176             rnd -= blocksize;
00177         }
00178 
00179       length = data_size + hash_size;
00180 
00181       *pad = (uint8_t) (blocksize - (length % blocksize)) + rnd;
00182 
00183       length += *pad;
00184       if (session->security_parameters.version >= MHD_GNUTLS_PROTOCOL_TLS1_1)
00185         length += blocksize;    /* for the IV */
00186 
00187       break;
00188     default:
00189       MHD_gnutls_assert ();
00190       return GNUTLS_E_INTERNAL_ERROR;
00191     }
00192 
00193   return length;
00194 }
00195 
00196 /* This is the actual encryption
00197  * Encrypts the given compressed datum, and puts the result to cipher_data,
00198  * which has cipher_size size.
00199  * return the actual encrypted data length.
00200  */
00201 int
00202 MHD_gtls_compressed2ciphertext (MHD_gtls_session_t session,
00203                                 opaque * cipher_data, int cipher_size,
00204                                 MHD_gnutls_datum_t compressed,
00205                                 content_type_t _type, int random_pad)
00206 {
00207   uint8_t MAC[MAX_HASH_SIZE];
00208   uint16_t c_length;
00209   uint8_t pad;
00210   int length, ret;
00211   mac_hd_t td;
00212   uint8_t type = _type;
00213   uint8_t major, minor;
00214   int hash_size =
00215     MHD_gnutls_hash_get_algo_len (session->security_parameters.
00216                                   write_mac_algorithm);
00217   enum MHD_GNUTLS_Protocol ver;
00218   int blocksize =
00219     MHD_gtls_cipher_get_block_size (session->security_parameters.
00220                                     write_bulk_cipher_algorithm);
00221   cipher_type_t block_algo =
00222     MHD_gtls_cipher_is_block (session->security_parameters.
00223                               write_bulk_cipher_algorithm);
00224   opaque *data_ptr;
00225 
00226 
00227   ver = MHD__gnutls_protocol_get_version (session);
00228   minor = MHD_gtls_version_get_minor (ver);
00229   major = MHD_gtls_version_get_major (ver);
00230 
00231 
00232   /* Initialize MAC */
00233   td = mac_init (session->security_parameters.write_mac_algorithm,
00234                  session->connection_state.write_mac_secret.data,
00235                  session->connection_state.write_mac_secret.size, ver);
00236 
00237   if (td == GNUTLS_MAC_FAILED
00238       && session->security_parameters.write_mac_algorithm !=
00239       MHD_GNUTLS_MAC_NULL)
00240     {
00241       MHD_gnutls_assert ();
00242       return GNUTLS_E_INTERNAL_ERROR;
00243     }
00244 
00245   c_length = MHD_gtls_conv_uint16 (compressed.size);
00246 
00247   if (td != GNUTLS_MAC_FAILED)
00248     {                           /* actually when the algorithm in not the NULL one */
00249       MHD_gnutls_hash (td,
00250                        UINT64DATA (session->connection_state.
00251                                    write_sequence_number), 8);
00252 
00253       MHD_gnutls_hash (td, &type, 1);
00254       if (ver >= MHD_GNUTLS_PROTOCOL_TLS1_0)
00255         {                       /* TLS 1.0 or higher */
00256           MHD_gnutls_hash (td, &major, 1);
00257           MHD_gnutls_hash (td, &minor, 1);
00258         }
00259       MHD_gnutls_hash (td, &c_length, 2);
00260       MHD_gnutls_hash (td, compressed.data, compressed.size);
00261       mac_deinit (td, MAC, ver);
00262     }
00263 
00264 
00265   /* Calculate the encrypted length (padding etc.)
00266    */
00267   length =
00268     calc_enc_length (session, compressed.size, hash_size, &pad,
00269                      random_pad, block_algo, blocksize);
00270   if (length < 0)
00271     {
00272       MHD_gnutls_assert ();
00273       return length;
00274     }
00275 
00276   /* copy the encrypted data to cipher_data.
00277    */
00278   if (cipher_size < length)
00279     {
00280       MHD_gnutls_assert ();
00281       return GNUTLS_E_MEMORY_ERROR;
00282     }
00283 
00284   data_ptr = cipher_data;
00285   if (block_algo == CIPHER_BLOCK &&
00286       session->security_parameters.version >= MHD_GNUTLS_PROTOCOL_TLS1_1)
00287     {
00288       /* copy the random IV.
00289        */
00290       if (MHD_gc_nonce ((char *) data_ptr, blocksize) != GC_OK)
00291         {
00292           MHD_gnutls_assert ();
00293           return GNUTLS_E_RANDOM_FAILED;
00294         }
00295       data_ptr += blocksize;
00296     }
00297 
00298   memcpy (data_ptr, compressed.data, compressed.size);
00299   data_ptr += compressed.size;
00300 
00301   if (hash_size > 0)
00302     {
00303       memcpy (data_ptr, MAC, hash_size);
00304       data_ptr += hash_size;
00305     }
00306   if (block_algo == CIPHER_BLOCK && pad > 0)
00307     {
00308       memset (data_ptr, pad - 1, pad);
00309     }
00310 
00311 
00312   /* Actual encryption (inplace).
00313    */
00314   ret =
00315     MHD_gtls_cipher_encrypt (session->connection_state.write_cipher_state,
00316                              cipher_data, length);
00317   if (ret < 0)
00318     {
00319       MHD_gnutls_assert ();
00320       return ret;
00321     }
00322 
00323   return length;
00324 }
00325 
00326 /* Deciphers the ciphertext packet, and puts the result to compress_data, of compress_size.
00327  * Returns the actual compressed packet size.
00328  */
00329 int
00330 MHD_gtls_ciphertext2compressed (MHD_gtls_session_t session,
00331                                 opaque * compress_data,
00332                                 int compress_size,
00333                                 MHD_gnutls_datum_t ciphertext, uint8_t type)
00334 {
00335   uint8_t MAC[MAX_HASH_SIZE];
00336   uint16_t c_length;
00337   uint8_t pad;
00338   int length;
00339   mac_hd_t td;
00340   uint16_t blocksize;
00341   int ret, i, pad_failed = 0;
00342   uint8_t major, minor;
00343   enum MHD_GNUTLS_Protocol ver;
00344   int hash_size =
00345     MHD_gnutls_hash_get_algo_len (session->security_parameters.
00346                                   read_mac_algorithm);
00347 
00348   ver = MHD__gnutls_protocol_get_version (session);
00349   minor = MHD_gtls_version_get_minor (ver);
00350   major = MHD_gtls_version_get_major (ver);
00351 
00352   blocksize =
00353     MHD_gtls_cipher_get_block_size (session->security_parameters.
00354                                     read_bulk_cipher_algorithm);
00355 
00356   /* initialize MAC
00357    */
00358   td = mac_init (session->security_parameters.read_mac_algorithm,
00359                  session->connection_state.read_mac_secret.data,
00360                  session->connection_state.read_mac_secret.size, ver);
00361 
00362   if (td == GNUTLS_MAC_FAILED
00363       && session->security_parameters.read_mac_algorithm !=
00364       MHD_GNUTLS_MAC_NULL)
00365     {
00366       MHD_gnutls_assert ();
00367       return GNUTLS_E_INTERNAL_ERROR;
00368     }
00369 
00370 
00371   /* actual decryption (inplace)
00372    */
00373   switch (MHD_gtls_cipher_is_block
00374           (session->security_parameters.read_bulk_cipher_algorithm))
00375     {
00376     case CIPHER_STREAM:
00377       if ((ret =
00378            MHD_gtls_cipher_decrypt (session->connection_state.
00379                                     read_cipher_state, ciphertext.data,
00380                                     ciphertext.size)) < 0)
00381         {
00382           MHD_gnutls_assert ();
00383           return ret;
00384         }
00385 
00386       length = ciphertext.size - hash_size;
00387 
00388       break;
00389     case CIPHER_BLOCK:
00390       if ((ciphertext.size < blocksize) || (ciphertext.size % blocksize != 0))
00391         {
00392           MHD_gnutls_assert ();
00393           return GNUTLS_E_DECRYPTION_FAILED;
00394         }
00395 
00396       if ((ret =
00397            MHD_gtls_cipher_decrypt (session->connection_state.
00398                                     read_cipher_state, ciphertext.data,
00399                                     ciphertext.size)) < 0)
00400         {
00401           MHD_gnutls_assert ();
00402           return ret;
00403         }
00404 
00405       /* ignore the IV in TLS 1.1.
00406        */
00407       if (session->security_parameters.version >= MHD_GNUTLS_PROTOCOL_TLS1_1)
00408         {
00409           ciphertext.size -= blocksize;
00410           ciphertext.data += blocksize;
00411 
00412           if (ciphertext.size == 0)
00413             {
00414               MHD_gnutls_assert ();
00415               return GNUTLS_E_DECRYPTION_FAILED;
00416             }
00417         }
00418 
00419       pad = ciphertext.data[ciphertext.size - 1] + 1;   /* pad */
00420 
00421       length = ciphertext.size - hash_size - pad;
00422 
00423       if (pad > ciphertext.size - hash_size)
00424         {
00425           MHD_gnutls_assert ();
00426           /* We do not fail here. We check below for the
00427            * the pad_failed. If zero means success.
00428            */
00429           pad_failed = GNUTLS_E_DECRYPTION_FAILED;
00430         }
00431 
00432       /* Check the pading bytes (TLS 1.x)
00433        */
00434       if (ver >= MHD_GNUTLS_PROTOCOL_TLS1_0 && pad_failed == 0)
00435         for (i = 2; i < pad; i++)
00436           {
00437             if (ciphertext.data[ciphertext.size - i] !=
00438                 ciphertext.data[ciphertext.size - 1])
00439               pad_failed = GNUTLS_E_DECRYPTION_FAILED;
00440           }
00441       break;
00442     default:
00443       MHD_gnutls_assert ();
00444       return GNUTLS_E_INTERNAL_ERROR;
00445     }
00446 
00447   if (length < 0)
00448     length = 0;
00449   c_length = MHD_gtls_conv_uint16 ((uint16_t) length);
00450 
00451   /* Pass the type, version, length and compressed through
00452    * MAC.
00453    */
00454   if (td != GNUTLS_MAC_FAILED)
00455     {
00456       MHD_gnutls_hash (td,
00457                        UINT64DATA (session->connection_state.
00458                                    read_sequence_number), 8);
00459 
00460       MHD_gnutls_hash (td, &type, 1);
00461       if (ver >= MHD_GNUTLS_PROTOCOL_TLS1_0)
00462         {                       /* TLS 1.x */
00463           MHD_gnutls_hash (td, &major, 1);
00464           MHD_gnutls_hash (td, &minor, 1);
00465         }
00466       MHD_gnutls_hash (td, &c_length, 2);
00467 
00468       if (length > 0)
00469         MHD_gnutls_hash (td, ciphertext.data, length);
00470 
00471       mac_deinit (td, MAC, ver);
00472     }
00473 
00474   /* This one was introduced to avoid a timing attack against the TLS
00475    * 1.0 protocol.
00476    */
00477   if (pad_failed != 0)
00478     return pad_failed;
00479 
00480   /* HMAC was not the same.
00481    */
00482   if ( (td != GNUTLS_MAC_FAILED) &&
00483        (memcmp (MAC, &ciphertext.data[length], hash_size) != 0) )
00484     {
00485       MHD_gnutls_assert ();
00486       return GNUTLS_E_DECRYPTION_FAILED;
00487     }
00488 
00489   /* copy the decrypted stuff to compress_data.
00490    */
00491   if (compress_size < length)
00492     {
00493       MHD_gnutls_assert ();
00494       return GNUTLS_E_DECOMPRESSION_FAILED;
00495     }
00496   memcpy (compress_data, ciphertext.data, length);
00497 
00498   return length;
00499 }

Generated by  doxygen 1.6.2