Webserver+3d print

Dependents:   Nucleo

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers tls_record.c Source File

tls_record.c

Go to the documentation of this file.
00001 /**
00002  * @file tls_record.c
00003  * @brief TLS record protocol
00004  *
00005  * @section License
00006  *
00007  * Copyright (C) 2010-2017 Oryx Embedded SARL. All rights reserved.
00008  *
00009  * This file is part of CycloneSSL Open.
00010  *
00011  * This program is free software; you can redistribute it and/or
00012  * modify it under the terms of the GNU General Public License
00013  * as published by the Free Software Foundation; either version 2
00014  * of the License, or (at your option) any later version.
00015  *
00016  * This program is distributed in the hope that it will be useful,
00017  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  * GNU General Public License for more details.
00020  *
00021  * You should have received a copy of the GNU General Public License
00022  * along with this program; if not, write to the Free Software Foundation,
00023  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
00024  *
00025  * @author Oryx Embedded SARL (www.oryx-embedded.com)
00026  * @version 1.7.6
00027  **/
00028 
00029 //Switch to the appropriate trace level
00030 #define TRACE_LEVEL TLS_TRACE_LEVEL
00031 
00032 //Dependencies
00033 #include <string.h>
00034 #include "tls.h"
00035 #include "tls_common.h"
00036 #include "tls_record.h"
00037 #include "tls_misc.h"
00038 #include "ssl_common.h"
00039 #include "cipher_mode_cbc.h"
00040 #include "cipher_mode_ccm.h"
00041 #include "cipher_mode_gcm.h"
00042 #include "chacha20_poly1305.h"
00043 #include "debug.h"
00044 
00045 //Check SSL library configuration
00046 #if (TLS_SUPPORT == ENABLED)
00047 
00048 
00049 /**
00050  * @brief Write protocol data
00051  * @param[in] context Pointer to the TLS context
00052  * @param[in] data Pointer to the data buffer
00053  * @param[in] length Number of data bytes to be written
00054  * @param[in] contentType Higher level protocol
00055  * @return Error code
00056  **/
00057 
00058 error_t tlsWriteProtocolData(TlsContext *context,
00059    const void *data, size_t length, TlsContentType contentType)
00060 {
00061    error_t error;
00062    size_t n;
00063    uint8_t *p;
00064 
00065    //Initialize status code
00066    error = NO_ERROR;
00067 
00068    //Fragmentation process
00069    while(!error)
00070    {
00071       if(context->txBufferLen == 0)
00072       {
00073          //Check the length of the data
00074          if(length > context->txRecordMaxLen)
00075          {
00076             //Report an error
00077             error = ERROR_MESSAGE_TOO_LONG;
00078          }
00079          else if(length > 0)
00080          {
00081             //The hash value is updated for each handshake message,
00082             //except for HelloRequest messages
00083             if(contentType == TLS_TYPE_HANDSHAKE)
00084                tlsUpdateHandshakeHash(context, data, length);
00085 
00086             //Make room for the encryption overhead
00087             memmove(context->txBuffer + context->txBufferSize - length, data, length);
00088 
00089             //Save record type
00090             context->txBufferType = contentType;
00091             //Set the length of the buffer
00092             context->txBufferLen = length;
00093             //Point to the beginning of the buffer
00094             context->txBufferPos = 0;
00095          }
00096          else
00097          {
00098             //We are done
00099             break;
00100          }
00101       }
00102       else if(context->txBufferPos < context->txBufferLen)
00103       {
00104          //Number of bytes left to send
00105          n = context->txBufferLen - context->txBufferPos;
00106          //Point to the current fragment
00107          p = context->txBuffer + context->txBufferSize - n;
00108          //The record length must not exceed 16384 bytes
00109          n = MIN(n, TLS_MAX_RECORD_LENGTH);
00110 
00111          //Send TLS record
00112          error = tlsWriteRecord(context, p, n, context->txBufferType);
00113 
00114          //Check status code
00115          if(!error)
00116          {
00117             //Advance data pointer
00118             context->txBufferPos += n;
00119          }
00120       }
00121       else
00122       {
00123          //Prepare to send new protocol data
00124          context->txBufferLen = 0;
00125          context->txBufferPos = 0;
00126 
00127          //We are done
00128          break;
00129       }
00130    }
00131 
00132    //Return status code
00133    return error;
00134 }
00135 
00136 
00137 /**
00138  * @brief Read protocol data
00139  * @param[in] context Pointer to the TLS context
00140  * @param[out] data Pointer to the received data
00141  * @param[out] length Number of data bytes that were received
00142  * @param[out] contentType Higher level protocol
00143  * @return Error code
00144  **/
00145 
00146 error_t tlsReadProtocolData(TlsContext *context,
00147    void **data, size_t *length, TlsContentType *contentType)
00148 {
00149    error_t error;
00150    size_t n;
00151    TlsContentType type;
00152    TlsHandshake *message;
00153 
00154    //Initialize status code
00155    error = NO_ERROR;
00156 
00157    //Fragment reassembly process
00158    do
00159    {
00160       //Empty receive buffer?
00161       if(context->rxBufferLen == 0)
00162       {
00163          //Read a TLS record
00164          error = tlsReadRecord(context, context->rxBuffer,
00165             context->rxBufferSize, &n, &type);
00166 
00167          //Check status code
00168          if(!error)
00169          {
00170             //Save record type
00171             context->rxBufferType = type;
00172             //Number of bytes available for reading
00173             context->rxBufferLen = n;
00174             //Rewind to the beginning of the buffer
00175             context->rxBufferPos = 0;
00176          }
00177       }
00178       //Imcomplete message received?
00179       else if(error == ERROR_MORE_DATA_REQUIRED)
00180       {
00181          //Make room at the end of the buffer
00182          if(context->rxBufferPos > 0)
00183          {
00184             //Move unread data to the beginning of the buffer
00185             memmove(context->rxBuffer, context->rxBuffer +
00186                context->rxBufferPos, context->rxBufferLen);
00187 
00188             //Rewind to the beginning of the buffer
00189             context->rxBufferPos = 0;
00190          }
00191 
00192          //Read a TLS record
00193          error = tlsReadRecord(context, context->rxBuffer + context->rxBufferLen,
00194             context->rxBufferSize - context->rxBufferLen, &n, &type);
00195 
00196          //Check status code
00197          if(!error)
00198          {
00199             //Fragmented records with mixed types cannot be interleaved
00200             if(type != context->rxBufferType)
00201                error = ERROR_UNEXPECTED_MESSAGE;
00202          }
00203 
00204          //Check status code
00205          if(!error)
00206          {
00207             //Number of bytes available for reading
00208             context->rxBufferLen += n;
00209          }
00210       }
00211 
00212       //Check status code
00213       if(!error)
00214       {
00215          //Handshake message received?
00216          if(context->rxBufferType == TLS_TYPE_HANDSHAKE)
00217          {
00218             //A message may be fragmented across several records
00219             if(context->rxBufferLen < sizeof(TlsHandshake))
00220             {
00221                //Read an additional record
00222                error = ERROR_MORE_DATA_REQUIRED;
00223             }
00224             else
00225             {
00226                //Point to the handshake message
00227                message = (TlsHandshake *) (context->rxBuffer + context->rxBufferPos);
00228                //Retrieve the length of the handshake message
00229                n = sizeof(TlsHandshake) + LOAD24BE(message->length);
00230 
00231                //A message may be fragmented across several records
00232                if(context->rxBufferLen < n)
00233                {
00234                   //Read an additional record
00235                   error = ERROR_MORE_DATA_REQUIRED;
00236                }
00237                else
00238                {
00239                   //Pass the handshake message to the higher layer
00240                   error = NO_ERROR;
00241                }
00242             }
00243          }
00244          //ChangeCipherSpec message received?
00245          else if(context->rxBufferType == TLS_TYPE_CHANGE_CIPHER_SPEC)
00246          {
00247             //A message may be fragmented across several records
00248             if(context->rxBufferLen < sizeof(TlsChangeCipherSpec))
00249             {
00250                //Read an additional record
00251                error = ERROR_MORE_DATA_REQUIRED;
00252             }
00253             else
00254             {
00255                //Length of the ChangeCipherSpec message
00256                n = sizeof(TlsChangeCipherSpec);
00257                //Pass the ChangeCipherSpec message to the higher layer
00258                error = NO_ERROR;
00259             }
00260          }
00261          //Alert message received?
00262          else if(context->rxBufferType == TLS_TYPE_ALERT)
00263          {
00264             //A message may be fragmented across several records
00265             if(context->rxBufferLen < sizeof(TlsAlert))
00266             {
00267                //Read an additional record
00268                error = ERROR_MORE_DATA_REQUIRED;
00269             }
00270             else
00271             {
00272                //Length of the Alert message
00273                n = sizeof(TlsAlert);
00274                //Pass the Alert message to the higher layer
00275                error = NO_ERROR;
00276             }
00277          }
00278          //Application data received?
00279          else if(context->rxBufferType == TLS_TYPE_APPLICATION_DATA)
00280          {
00281             //Length of the application data
00282             n = context->rxBufferLen;
00283             //Pass the application data to the higher layer
00284             error = NO_ERROR;
00285          }
00286          //Unknown content type?
00287          else
00288          {
00289             //Report an error
00290             error = ERROR_UNEXPECTED_MESSAGE;
00291          }
00292       }
00293 
00294       //Read as many records as necessary to reassemble the data
00295    } while(error == ERROR_MORE_DATA_REQUIRED);
00296 
00297    //Successful processing?
00298    if(!error)
00299    {
00300       //Pointer to the received data
00301       *data = context->rxBuffer + context->rxBufferPos;
00302       //Length, in byte, of the data
00303       *length = n;
00304       //Protocol type
00305       *contentType = context->rxBufferType;
00306    }
00307 
00308    //Return status code
00309    return error;
00310 }
00311 
00312 
00313 /**
00314  * @brief Send a TLS record
00315  * @param[in] context Pointer to the TLS context
00316  * @param[in] data Pointer to the record data
00317  * @param[in] length Length of the record data
00318  * @param[in] contentType Record type
00319  * @return Error code
00320  **/
00321 
00322 error_t tlsWriteRecord(TlsContext *context, const uint8_t *data,
00323    size_t length, TlsContentType contentType)
00324 {
00325    error_t error;
00326    size_t n;
00327    TlsRecord *record;
00328 
00329    //Point to the TLS record
00330    record = (TlsRecord *) context->txBuffer;
00331 
00332    //Initialize status code
00333    error = NO_ERROR;
00334 
00335    //Send process
00336    while(!error)
00337    {
00338       //Send as much data as possible
00339       if(context->txRecordLen == 0)
00340       {
00341          //Format TLS record
00342          record->type = contentType;
00343          record->version = htons(context->version);
00344          record->length = htons(length);
00345 
00346          //Copy record data
00347          memmove(record->data, data, length);
00348 
00349          //Debug message
00350          TRACE_DEBUG("Sending TLS record (%" PRIuSIZE " bytes)...\r\n", length);
00351          TRACE_DEBUG_ARRAY("  ", record, length + sizeof(TlsRecord));
00352 
00353          //Protect record payload?
00354          if(context->changeCipherSpecSent)
00355          {
00356             //Encrypt TLS record
00357             error = tlsEncryptRecord(context, record);
00358          }
00359 
00360          //Check status code
00361          if(!error)
00362          {
00363             //Actual length of the record data
00364             context->txRecordLen = sizeof(TlsRecord) + ntohs(record->length);
00365             //Point to the beginning of the record
00366             context->txRecordPos = 0;
00367          }
00368       }
00369       else if(context->txRecordPos < context->txRecordLen)
00370       {
00371          //Total number of bytes that have been written
00372          n = 0;
00373 
00374          //Send more data
00375          error = context->sendCallback(context->handle,
00376             context->txBuffer + context->txRecordPos,
00377             context->txRecordLen - context->txRecordPos, &n, 0);
00378 
00379          //Check status code
00380          if(error == NO_ERROR || error == ERROR_WOULD_BLOCK || error == ERROR_TIMEOUT)
00381          {
00382             //Advance data pointer
00383             context->txRecordPos += n;
00384          }
00385          else
00386          {
00387             //The write operation has failed
00388             error = ERROR_WRITE_FAILED;
00389          }
00390       }
00391       else
00392       {
00393          //Prepare to send the next TLS record
00394          context->txRecordLen = 0;
00395          context->txRecordPos = 0;
00396 
00397          //We are done
00398          break;
00399       }
00400    }
00401 
00402    //Return status code
00403    return error;
00404 }
00405 
00406 
00407 /**
00408  * @brief Receive a TLS record
00409  * @param[in] context Pointer to the TLS context
00410  * @param[out] data Buffer where to store the record data
00411  * @param[in] size Maximum acceptable size for the incoming record
00412  * @param[out] length Length of the record data
00413  * @param[out] contentType Record type
00414  * @return Error code
00415  **/
00416 
00417 error_t tlsReadRecord(TlsContext *context, uint8_t *data,
00418    size_t size, size_t *length, TlsContentType *contentType)
00419 {
00420    error_t error;
00421    size_t n;
00422    TlsRecord *record;
00423 
00424    //Point to the buffer where to store the incoming TLS record
00425    record = (TlsRecord *) data;
00426 
00427    //Initialize status code
00428    error = NO_ERROR;
00429 
00430    //Receive process
00431    while(!error)
00432    {
00433       //Read as much data as possible
00434       if(context->rxRecordPos < sizeof(TlsRecord))
00435       {
00436          //Make sure that the buffer is large enough to hold the record header
00437          if(size >= sizeof(TlsRecord))
00438          {
00439             //Total number of bytes that have been received
00440             n = 0;
00441 
00442             //Read TLS record header
00443             error = context->receiveCallback(context->handle,
00444                data + context->rxRecordPos,
00445                sizeof(TlsRecord) - context->rxRecordPos, &n, 0);
00446 
00447             //Check status code
00448             if(error == NO_ERROR || error == ERROR_WOULD_BLOCK || error == ERROR_TIMEOUT)
00449             {
00450                //Advance data pointer
00451                context->rxRecordPos += n;
00452 
00453                //TLS record header successfully received?
00454                if(context->rxRecordPos >= sizeof(TlsRecord))
00455                {
00456                   //Debug message
00457                   TRACE_DEBUG("Record header received:\r\n");
00458                   TRACE_DEBUG_ARRAY("  ", record, sizeof(record));
00459 
00460                   //Retrieve the length of the TLS record
00461                   context->rxRecordLen = sizeof(TlsRecord) + ntohs(record->length);
00462                }
00463             }
00464             else
00465             {
00466                //The read operation has failed
00467                error = ERROR_READ_FAILED;
00468             }
00469          }
00470          else
00471          {
00472             //Report an error
00473             error = ERROR_RECORD_OVERFLOW;
00474          }
00475       }
00476       else if(context->rxRecordPos < context->rxRecordLen)
00477       {
00478          //Make sure that the buffer is large enough to hold the entire record
00479          if(size >= context->rxRecordLen)
00480          {
00481             //Total number of bytes that have been received
00482             n = 0;
00483 
00484             //Read TLS record contents
00485             error = context->receiveCallback(context->handle,
00486                data + context->rxRecordPos,
00487                context->rxRecordLen - context->rxRecordPos, &n, 0);
00488 
00489             //Check status code
00490             if(error == NO_ERROR || error == ERROR_WOULD_BLOCK || error == ERROR_TIMEOUT)
00491             {
00492                //Advance data pointer
00493                context->rxRecordPos += n;
00494             }
00495             else
00496             {
00497                //The read operation has failed
00498                error = ERROR_READ_FAILED;
00499             }
00500          }
00501          else
00502          {
00503             //Report an error
00504             error = ERROR_RECORD_OVERFLOW;
00505          }
00506       }
00507       else
00508       {
00509          //Check current state
00510          if(context->state > TLS_STATE_SERVER_HELLO)
00511          {
00512             //Once the server has sent the ServerHello message, enforce
00513             //incoming record versions
00514             if(ntohs(record->version) != context->version)
00515                error = ERROR_VERSION_NOT_SUPPORTED;
00516          }
00517 
00518          //Check status code
00519          if(!error)
00520          {
00521             //Record payload is protected?
00522             if(context->changeCipherSpecReceived)
00523             {
00524                //Decrypt TLS record
00525                error = tlsDecryptRecord(context, record);
00526             }
00527          }
00528 
00529          //Check status code
00530          if(!error)
00531          {
00532             //Actual length of the record data
00533             *length = ntohs(record->length);
00534             //Record type
00535             *contentType = (TlsContentType) record->type;
00536 
00537             //Debug message
00538             TRACE_DEBUG("TLS record received (%" PRIuSIZE " bytes)...\r\n", *length);
00539             TRACE_DEBUG_ARRAY("  ", record, *length + sizeof(TlsRecord));
00540 
00541             //Discard record header
00542             memmove(data, record->data, *length);
00543 
00544             //Prepare to receive the next TLS record
00545             context->rxRecordLen = 0;
00546             context->rxRecordPos = 0;
00547 
00548             //We are done
00549             break;
00550          }
00551       }
00552    }
00553 
00554    //Return status code
00555    return error;
00556 }
00557 
00558 
00559 /**
00560  * @brief Encrypt an outgoing TLS record
00561  * @param[in] context Pointer to the TLS context
00562  * @param[in,out] record TLS record to be encrypted
00563  * @return Error code
00564  **/
00565 
00566 error_t tlsEncryptRecord(TlsContext *context, TlsRecord *record)
00567 {
00568    error_t error;
00569    size_t length;
00570 
00571    //Convert the length field to host byte order
00572    length = ntohs(record->length);
00573 
00574    //Message authentication is required?
00575    if(context->hashAlgo != NULL)
00576    {
00577 #if (TLS_MAX_VERSION >= SSL_VERSION_3_0 && TLS_MIN_VERSION <= SSL_VERSION_3_0)
00578       //Check whether SSL 3.0 is currently used
00579       if(context->version == SSL_VERSION_3_0)
00580       {
00581          //SSL 3.0 uses an older obsolete version of the HMAC construction
00582          error = sslComputeMac(context, context->writeMacKey,
00583             context->writeSeqNum, record, record->data, length, record->data + length);
00584          //Any error to report?
00585          if(error)
00586             return error;
00587       }
00588       else
00589 #endif
00590 #if (TLS_MAX_VERSION >= TLS_VERSION_1_0 && TLS_MIN_VERSION <= TLS_VERSION_1_2)
00591       //Check whether TLS 1.0, TLS 1.1 or TLS 1.2 is currently used
00592       if(context->version >= TLS_VERSION_1_0)
00593       {
00594          //TLS uses a HMAC construction
00595          hmacInit(&context->hmacContext, context->hashAlgo,
00596             context->writeMacKey, context->macKeyLen);
00597 
00598          //Compute MAC over the sequence number and the record contents
00599          hmacUpdate(&context->hmacContext, context->writeSeqNum, sizeof(TlsSequenceNumber));
00600          hmacUpdate(&context->hmacContext, record, length + sizeof(TlsRecord));
00601 
00602          //Append the resulting MAC to the message
00603          hmacFinal(&context->hmacContext, record->data + length);
00604       }
00605       else
00606 #endif
00607       //The negotiated TLS version is not valid...
00608       {
00609          //Report an error
00610          return ERROR_INVALID_VERSION;
00611       }
00612 
00613       //Debug message
00614       TRACE_DEBUG("Write sequence number:\r\n");
00615       TRACE_DEBUG_ARRAY("  ", context->writeSeqNum, sizeof(TlsSequenceNumber));
00616       TRACE_DEBUG("Computed MAC:\r\n");
00617       TRACE_DEBUG_ARRAY("  ", record->data + length, context->hashAlgo->digestSize);
00618 
00619       //Adjust the length of the message
00620       length += context->hashAlgo->digestSize;
00621       //Fix length field
00622       record->length = htons(length);
00623 
00624       //Increment sequence number
00625       tlsIncSequenceNumber(context->writeSeqNum);
00626    }
00627 
00628    //Encryption is required?
00629    if(context->cipherMode != CIPHER_MODE_NULL)
00630    {
00631       //Debug message
00632       TRACE_DEBUG("Record to be encrypted (%" PRIuSIZE " bytes):\r\n", length);
00633       TRACE_DEBUG_ARRAY("  ", record, length + sizeof(TlsRecord));
00634 
00635 #if (TLS_STREAM_CIPHER_SUPPORT == ENABLED)
00636       //Stream cipher?
00637       if(context->cipherMode == CIPHER_MODE_STREAM)
00638       {
00639          //Encrypt record contents
00640          context->cipherAlgo->encryptStream(context->writeCipherContext,
00641             record->data, record->data, length);
00642       }
00643       else
00644 #endif
00645 #if (TLS_CBC_CIPHER_SUPPORT == ENABLED)
00646       //CBC block cipher?
00647       if(context->cipherMode == CIPHER_MODE_CBC)
00648       {
00649          size_t i;
00650          size_t paddingLength;
00651 
00652 #if (TLS_MAX_VERSION >= TLS_VERSION_1_1 && TLS_MIN_VERSION <= TLS_VERSION_1_2)
00653          //TLS 1.1 and 1.2 use an explicit IV
00654          if(context->version >= TLS_VERSION_1_1)
00655          {
00656             //Make room for the IV at the beginning of the data
00657             memmove(record->data + context->recordIvLen, record->data, length);
00658 
00659             //The initialization vector should be chosen at random
00660             error = context->prngAlgo->read(context->prngContext,
00661                record->data, context->recordIvLen);
00662             //Any error to report?
00663             if(error)
00664                return error;
00665 
00666             //Adjust the length of the message
00667             length += context->recordIvLen;
00668          }
00669 #endif
00670          //Get the actual amount of bytes in the last block
00671          paddingLength = (length + 1) % context->cipherAlgo->blockSize;
00672 
00673          //Padding is added to force the length of the plaintext to be
00674          //an integral multiple of the cipher's block length
00675          if(paddingLength > 0)
00676             paddingLength = context->cipherAlgo->blockSize - paddingLength;
00677 
00678          //Write padding bytes
00679          for(i = 0; i <= paddingLength; i++)
00680             record->data[length + i] = (uint8_t) paddingLength;
00681 
00682          //Compute the length of the resulting message
00683          length += paddingLength + 1;
00684          //Fix length field
00685          record->length = htons(length);
00686 
00687          //Debug message
00688          TRACE_DEBUG("Record with padding (%" PRIuSIZE " bytes):\r\n", length);
00689          TRACE_DEBUG_ARRAY("  ", record, length + sizeof(TlsRecord));
00690 
00691          //CBC encryption
00692          error = cbcEncrypt(context->cipherAlgo, context->writeCipherContext,
00693             context->writeIv, record->data, record->data, length);
00694          //Any error to report?
00695          if(error)
00696             return error;
00697       }
00698       else
00699 #endif
00700 #if (TLS_CCM_CIPHER_SUPPORT == ENABLED || TLS_CCM_8_CIPHER_SUPPORT == ENABLED || \
00701    TLS_GCM_CIPHER_SUPPORT == ENABLED)
00702       //CCM or GCM AEAD cipher?
00703       if(context->cipherMode == CIPHER_MODE_CCM ||
00704          context->cipherMode == CIPHER_MODE_GCM)
00705       {
00706          uint8_t *data;
00707          uint8_t *tag;
00708          size_t nonceLength;
00709          uint8_t nonce[12];
00710          uint8_t a[13];
00711 
00712          //Determine the total length of the nonce
00713          nonceLength = context->fixedIvLen + context->recordIvLen;
00714          //The salt is the implicit part of the nonce and is not sent in the packet
00715          memcpy(nonce, context->writeIv, context->fixedIvLen);
00716 
00717          //The explicit part of the nonce is chosen by the sender
00718          error = context->prngAlgo->read(context->prngContext,
00719             nonce + context->fixedIvLen, context->recordIvLen);
00720          //Any error to report?
00721          if(error)
00722             return error;
00723 
00724          //Make room for the explicit nonce at the beginning of the record
00725          memmove(record->data + context->recordIvLen, record->data, length);
00726          //The explicit part of the nonce is carried in each TLS record
00727          memcpy(record->data, nonce + context->fixedIvLen, context->recordIvLen);
00728 
00729          //Additional data to be authenticated
00730          memcpy(a, context->writeSeqNum, sizeof(TlsSequenceNumber));
00731          memcpy(a + sizeof(TlsSequenceNumber), record, sizeof(TlsRecord));
00732 
00733          //Point to the plaintext
00734          data = record->data + context->recordIvLen;
00735          //Point to the buffer where to store the authentication tag
00736          tag = data + length;
00737 
00738 #if (TLS_CCM_CIPHER_SUPPORT == ENABLED || TLS_CCM_8_CIPHER_SUPPORT == ENABLED)
00739          //CCM AEAD cipher?
00740          if(context->cipherMode == CIPHER_MODE_CCM)
00741          {
00742             //Authenticated encryption using CCM
00743             error = ccmEncrypt(context->cipherAlgo, context->writeCipherContext,
00744                nonce, nonceLength, a, 13, data, data, length, tag, context->authTagLen);
00745          }
00746          else
00747 #endif
00748 #if (TLS_GCM_CIPHER_SUPPORT == ENABLED)
00749          //GCM AEAD cipher?
00750          if(context->cipherMode == CIPHER_MODE_GCM)
00751          {
00752             //Authenticated encryption using GCM
00753             error = gcmEncrypt(context->writeGcmContext, nonce, nonceLength,
00754                a, 13, data, data, length, tag, context->authTagLen);
00755          }
00756          else
00757 #endif
00758          //Invalid cipher mode?
00759          {
00760             //The specified cipher mode is not supported
00761             error = ERROR_UNSUPPORTED_CIPHER_MODE;
00762          }
00763 
00764          //Failed to encrypt data?
00765          if(error)
00766             return error;
00767 
00768          //Compute the length of the resulting message
00769          length += context->recordIvLen + context->authTagLen;
00770          //Fix length field
00771          record->length = htons(length);
00772 
00773          //Increment sequence number
00774          tlsIncSequenceNumber(context->writeSeqNum);
00775       }
00776       else
00777 #endif
00778 #if (TLS_CHACHA20_POLY1305_SUPPORT == ENABLED)
00779       //ChaCha20Poly1305 AEAD cipher?
00780       if(context->cipherMode == CIPHER_MODE_CHACHA20_POLY1305)
00781       {
00782          size_t i;
00783          uint8_t *tag;
00784          uint8_t nonce[12];
00785          uint8_t a[13];
00786 
00787          //The 64-bit record sequence number is serialized as an 8-byte,
00788          //big-endian value and padded on the left with four 0x00 bytes
00789          memcpy(nonce + 4, context->writeSeqNum, 8);
00790          memset(nonce, 0, 4);
00791 
00792          //The padded sequence number is XORed with the write IV to form
00793          //the 96-bit nonce
00794          for(i = 0; i < context->fixedIvLen; i++)
00795             nonce[i] ^= context->writeIv[i];
00796 
00797          //Additional data to be authenticated
00798          memcpy(a, context->writeSeqNum, sizeof(TlsSequenceNumber));
00799          memcpy(a + sizeof(TlsSequenceNumber), record, sizeof(TlsRecord));
00800 
00801          //Point to the buffer where to store the authentication tag
00802          tag = record->data + length;
00803 
00804          //Authenticated encryption using ChaCha20Poly1305
00805          error = chacha20Poly1305Encrypt(context->writeEncKey, context->encKeyLen,
00806             nonce, 12, a, 13, record->data, record->data, length, tag, context->authTagLen);
00807          //Failed to encrypt data?
00808          if(error)
00809             return error;
00810 
00811          //Compute the length of the resulting message
00812          length += context->authTagLen;
00813          //Fix length field
00814          record->length = htons(length);
00815 
00816          //Increment sequence number
00817          tlsIncSequenceNumber(context->writeSeqNum);
00818       }
00819       else
00820 #endif
00821       //Invalid cipher mode?
00822       {
00823          //The specified cipher mode is not supported
00824          return ERROR_UNSUPPORTED_CIPHER_MODE;
00825       }
00826 
00827       //Debug message
00828       TRACE_DEBUG("Encrypted record (%" PRIuSIZE " bytes):\r\n", length);
00829       TRACE_DEBUG_ARRAY("  ", record, length + sizeof(TlsRecord));
00830    }
00831 
00832    //Successful encryption
00833    return NO_ERROR;
00834 }
00835 
00836 
00837 /**
00838  * @brief Decrypt an incoming TLS record
00839  * @param[in] context Pointer to the TLS context
00840  * @param[in,out] record TLS record to be decrypted
00841  * @return Error code
00842  **/
00843 
00844 error_t tlsDecryptRecord(TlsContext *context, TlsRecord *record)
00845 {
00846    error_t error;
00847    size_t length;
00848 
00849    //Convert the length field to host byte order
00850    length = ntohs(record->length);
00851 
00852    //Decrypt record if necessary
00853    if(context->cipherMode != CIPHER_MODE_NULL)
00854    {
00855       //Debug message
00856       TRACE_DEBUG("Record to be decrypted (%" PRIuSIZE " bytes):\r\n", length);
00857       TRACE_DEBUG_ARRAY("  ", record, length + sizeof(TlsRecord));
00858 
00859 #if (TLS_STREAM_CIPHER_SUPPORT == ENABLED)
00860       //Stream cipher?
00861       if(context->cipherMode == CIPHER_MODE_STREAM)
00862       {
00863          //Decrypt record contents
00864          context->cipherAlgo->decryptStream(context->readCipherContext,
00865             record->data, record->data, length);
00866       }
00867       else
00868 #endif
00869 #if (TLS_CBC_CIPHER_SUPPORT == ENABLED)
00870       //CBC block cipher?
00871       if(context->cipherMode == CIPHER_MODE_CBC)
00872       {
00873          size_t i;
00874          size_t paddingLength;
00875 
00876          //The length of the data must be a multiple of the block size
00877          if((length % context->cipherAlgo->blockSize) != 0)
00878             return ERROR_DECODING_FAILED;
00879 
00880          //CBC decryption
00881          error = cbcDecrypt(context->cipherAlgo, context->readCipherContext,
00882             context->readIv, record->data, record->data, length);
00883          //Any error to report?
00884          if(error)
00885             return error;
00886 
00887          //Debug message
00888          TRACE_DEBUG("Record with padding (%" PRIuSIZE " bytes):\r\n", length);
00889          TRACE_DEBUG_ARRAY("  ", record, length + sizeof(TlsRecord));
00890 
00891 #if (TLS_MAX_VERSION >= TLS_VERSION_1_1 && TLS_MIN_VERSION <= TLS_VERSION_1_2)
00892          //TLS 1.1 and 1.2 use an explicit IV
00893          if(context->version >= TLS_VERSION_1_1)
00894          {
00895             //Make sure the message length is acceptable
00896             if(length < context->recordIvLen)
00897                return ERROR_DECODING_FAILED;
00898 
00899             //Adjust the length of the message
00900             length -= context->recordIvLen;
00901             //Discard the first cipher block (corresponding to the explicit IV)
00902             memmove(record->data, record->data + context->recordIvLen, length);
00903          }
00904 #endif
00905          //Make sure the message length is acceptable
00906          if(length < context->cipherAlgo->blockSize)
00907             return ERROR_DECODING_FAILED;
00908 
00909          //Compute the length of the padding string
00910          paddingLength = record->data[length - 1];
00911          //Erroneous padding length?
00912          if(paddingLength >= length)
00913             return ERROR_BAD_RECORD_MAC;
00914 
00915          //The receiver must check the padding
00916          for(i = 0; i <= paddingLength; i++)
00917          {
00918             //Each byte in the padding data must be filled
00919             //with the padding length value
00920             if(record->data[length - 1 - i] != paddingLength)
00921                return ERROR_BAD_RECORD_MAC;
00922          }
00923 
00924          //Remove padding bytes
00925          length -= paddingLength + 1;
00926          //Fix the length field of the TLS record
00927          record->length = htons(length);
00928       }
00929       else
00930 #endif
00931 #if (TLS_CCM_CIPHER_SUPPORT == ENABLED || TLS_CCM_8_CIPHER_SUPPORT == ENABLED || \
00932    TLS_GCM_CIPHER_SUPPORT == ENABLED)
00933       //CCM or GCM AEAD cipher?
00934       if(context->cipherMode == CIPHER_MODE_CCM ||
00935          context->cipherMode == CIPHER_MODE_GCM)
00936       {
00937          uint8_t *ciphertext;
00938          uint8_t *tag;
00939          size_t nonceLength;
00940          uint8_t nonce[12];
00941          uint8_t a[13];
00942 
00943          //Make sure the message length is acceptable
00944          if(length < (context->recordIvLen + context->authTagLen))
00945             return ERROR_DECODING_FAILED;
00946 
00947          //Determine the total length of the nonce
00948          nonceLength = context->fixedIvLen + context->recordIvLen;
00949          //The salt is the implicit part of the nonce and is not sent in the packet
00950          memcpy(nonce, context->readIv, context->fixedIvLen);
00951          //The explicit part of the nonce is chosen by the sender
00952          memcpy(nonce + context->fixedIvLen, record->data, context->recordIvLen);
00953 
00954          //Calculate the length of the ciphertext
00955          length -= context->recordIvLen + context->authTagLen;
00956          //Fix the length field of the TLS record
00957          record->length = htons(length);
00958 
00959          //Additional data to be authenticated
00960          memcpy(a, context->readSeqNum, sizeof(TlsSequenceNumber));
00961          memcpy(a + sizeof(TlsSequenceNumber), record, sizeof(TlsRecord));
00962 
00963          //Point to the ciphertext
00964          ciphertext = record->data + context->recordIvLen;
00965          //Point to the authentication tag
00966          tag = ciphertext + length;
00967 
00968 #if (TLS_CCM_CIPHER_SUPPORT == ENABLED || TLS_CCM_8_CIPHER_SUPPORT == ENABLED)
00969          //CCM AEAD cipher?
00970          if(context->cipherMode == CIPHER_MODE_CCM)
00971          {
00972             //Authenticated decryption using CCM
00973             error = ccmDecrypt(context->cipherAlgo, context->readCipherContext,
00974                nonce, nonceLength, a, 13, ciphertext, ciphertext, length, tag, context->authTagLen);
00975          }
00976          else
00977 #endif
00978 #if (TLS_GCM_CIPHER_SUPPORT == ENABLED)
00979          //GCM AEAD cipher?
00980          if(context->cipherMode == CIPHER_MODE_GCM)
00981          {
00982             //Authenticated decryption using GCM
00983             error = gcmDecrypt(context->readGcmContext, nonce, nonceLength,
00984                a, 13, ciphertext, ciphertext, length, tag, context->authTagLen);
00985          }
00986          else
00987 #endif
00988          //Invalid cipher mode?
00989          {
00990             //The specified cipher mode is not supported
00991             error = ERROR_UNSUPPORTED_CIPHER_MODE;
00992          }
00993 
00994          //Wrong authentication tag?
00995          if(error)
00996             return ERROR_BAD_RECORD_MAC;
00997 
00998          //Discard the explicit part of the nonce
00999          memmove(record->data, record->data + context->recordIvLen, length);
01000 
01001          //Increment sequence number
01002          tlsIncSequenceNumber(context->readSeqNum);
01003       }
01004       else
01005 #endif
01006 #if (TLS_CHACHA20_POLY1305_SUPPORT == ENABLED)
01007       //ChaCha20Poly1305 AEAD cipher?
01008       if(context->cipherMode == CIPHER_MODE_CHACHA20_POLY1305)
01009       {
01010          size_t i;
01011          uint8_t *tag;
01012          uint8_t nonce[12];
01013          uint8_t a[13];
01014 
01015          //Make sure the message length is acceptable
01016          if(length < context->authTagLen)
01017             return ERROR_DECODING_FAILED;
01018 
01019          //The 64-bit record sequence number is serialized as an 8-byte,
01020          //big-endian value and padded on the left with four 0x00 bytes
01021          memcpy(nonce + 4, context->readSeqNum, 8);
01022          memset(nonce, 0, 4);
01023 
01024          //The padded sequence number is XORed with the read IV to form
01025          //the 96-bit nonce
01026          for(i = 0; i < context->fixedIvLen; i++)
01027             nonce[i] ^= context->readIv[i];
01028 
01029          //Calculate the length of the ciphertext
01030          length -= context->authTagLen;
01031          //Fix the length field of the TLS record
01032          record->length = htons(length);
01033 
01034          //Additional data to be authenticated
01035          memcpy(a, context->readSeqNum, sizeof(TlsSequenceNumber));
01036          memcpy(a + sizeof(TlsSequenceNumber), record, sizeof(TlsRecord));
01037 
01038          //Point to the authentication tag
01039          tag = record->data + length;
01040 
01041          //Authenticated decryption using ChaCha20Poly1305
01042          error = chacha20Poly1305Decrypt(context->readEncKey, context->encKeyLen,
01043             nonce, 12, a, 13, record->data, record->data, length, tag, context->authTagLen);
01044          //Wrong authentication tag?
01045          if(error)
01046             return ERROR_BAD_RECORD_MAC;
01047 
01048          //Increment sequence number
01049          tlsIncSequenceNumber(context->readSeqNum);
01050       }
01051       else
01052 #endif
01053       //Invalid cipher mode?
01054       {
01055          //The specified cipher mode is not supported
01056          return ERROR_UNSUPPORTED_CIPHER_MODE;
01057       }
01058 
01059       //Debug message
01060       TRACE_DEBUG("Decrypted record (%" PRIuSIZE " bytes):\r\n", length);
01061       TRACE_DEBUG_ARRAY("  ", record, length + sizeof(TlsRecord));
01062    }
01063 
01064    //Check message authentication code if necessary
01065    if(context->hashAlgo != NULL)
01066    {
01067       //Make sure the message length is acceptable
01068       if(length < context->hashAlgo->digestSize)
01069          return ERROR_DECODING_FAILED;
01070 
01071       //Adjust the length of the message
01072       length -= context->hashAlgo->digestSize;
01073       //Fix the length field of the TLS record
01074       record->length = htons(length);
01075 
01076 #if (TLS_MAX_VERSION >= SSL_VERSION_3_0 && TLS_MIN_VERSION <= SSL_VERSION_3_0)
01077       //Check whether SSL 3.0 is currently used
01078       if(context->version == SSL_VERSION_3_0)
01079       {
01080          //SSL 3.0 uses an older obsolete version of the HMAC construction
01081          error = sslComputeMac(context, context->readMacKey, context->readSeqNum,
01082             record, record->data, length, context->hmacContext.digest);
01083          //Any error to report?
01084          if(error)
01085             return error;
01086       }
01087       else
01088 #endif
01089 #if (TLS_MAX_VERSION >= TLS_VERSION_1_0 && TLS_MIN_VERSION <= TLS_VERSION_1_2)
01090       //Check whether TLS 1.0, TLS 1.1 or TLS 1.2 is currently used
01091       if(context->version >= TLS_VERSION_1_0)
01092       {
01093          //TLS uses a HMAC construction
01094          hmacInit(&context->hmacContext, context->hashAlgo,
01095             context->readMacKey, context->macKeyLen);
01096 
01097          //Compute MAC over the sequence number and the record contents
01098          hmacUpdate(&context->hmacContext, context->readSeqNum, sizeof(TlsSequenceNumber));
01099          hmacUpdate(&context->hmacContext, record, sizeof(TlsRecord));
01100          hmacUpdate(&context->hmacContext, record->data, length);
01101          hmacFinal(&context->hmacContext, NULL);
01102       }
01103       else
01104 #endif
01105       //The negotiated TLS version is not valid...
01106       {
01107          //Report an error
01108          return ERROR_INVALID_VERSION;
01109       }
01110 
01111       //Debug message
01112       TRACE_DEBUG("Read sequence number:\r\n");
01113       TRACE_DEBUG_ARRAY("  ", context->readSeqNum, sizeof(TlsSequenceNumber));
01114       TRACE_DEBUG("Computed MAC:\r\n");
01115       TRACE_DEBUG_ARRAY("  ", context->hmacContext.digest, context->hashAlgo->digestSize);
01116 
01117       //Check the message authentication code
01118       if(memcmp(record->data + length, context->hmacContext.digest, context->hashAlgo->digestSize))
01119          return ERROR_BAD_RECORD_MAC;
01120 
01121       //Increment sequence number
01122       tlsIncSequenceNumber(context->readSeqNum);
01123    }
01124 
01125    //Successful decryption
01126    return NO_ERROR;
01127 }
01128 
01129 
01130 /**
01131  * @brief Increment sequence number
01132  * @param[in] seqNum Sequence number to increment
01133  **/
01134 
01135 void tlsIncSequenceNumber(TlsSequenceNumber seqNum)
01136 {
01137    int_t i;
01138 
01139    //Sequence numbers are stored MSB first
01140    for(i = 7; i >= 0; i--)
01141    {
01142       //Increment the current byte
01143       seqNum[i]++;
01144       //Propagate the carry if necessary
01145       if(seqNum[i] != 0)
01146          break;
01147    }
01148 }
01149 
01150 #endif
01151