Webserver+3d print

Dependents:   Nucleo

cyclone_ssl/tls_client.c

Committer:
Sergunb
Date:
2017-02-04
Revision:
0:8918a71cdbe9

File content as of revision 0:8918a71cdbe9:

/**
 * @file tls_client.c
 * @brief Handshake message processing (TLS client)
 *
 * @section License
 *
 * Copyright (C) 2010-2017 Oryx Embedded SARL. All rights reserved.
 *
 * This file is part of CycloneSSL Open.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 *
 * @section Description
 *
 * The TLS protocol provides communications security over the Internet. The
 * protocol allows client/server applications to communicate in a way that
 * is designed to prevent eavesdropping, tampering, or message forgery
 *
 * @author Oryx Embedded SARL (www.oryx-embedded.com)
 * @version 1.7.6
 **/

//Switch to the appropriate trace level
#define TRACE_LEVEL TLS_TRACE_LEVEL

//Dependencies
#include <string.h>
#include "tls.h"
#include "tls_cipher_suites.h"
#include "tls_client.h"
#include "tls_client_misc.h"
#include "tls_common.h"
#include "tls_record.h"
#include "tls_misc.h"
#include "pem.h"
#include "date_time.h"
#include "debug.h"

//Check SSL library configuration
#if (TLS_SUPPORT == ENABLED && TLS_CLIENT_SUPPORT == ENABLED)


/**
 * @brief TLS client handshake
 *
 * TLS handshake protocol is responsible for the authentication
 * and key exchange necessary to establish a secure session
 *
 * @param[in] context Pointer to the TLS context
 * @return Error code
 **/

error_t tlsClientHandshake(TlsContext *context)
{
   error_t error;

   //Initialize status code
   error = NO_ERROR;

   //Wait for the handshake to complete
   do
   {
      //Flush send buffer
      if(context->state != TLS_STATE_CLOSED)
         error = tlsWriteProtocolData(context, NULL, 0, TLS_TYPE_NONE);

      //Check status code
      if(!error)
      {
         //Check whether the handshake is complete
         if(context->state == TLS_STATE_APPLICATION_DATA)
         {
            //At this is point, the handshake is complete and the client
            //starts to exchange application-layer data
            break;
         }

         //The TLS handshake is implemented as a state machine
         //representing the current location in the protocol
         switch(context->state)
         {
         //Default state?
         case TLS_STATE_INIT:
            //The client initiates the TLS handshake by sending a ClientHello
            //message to the server
            context->state = TLS_STATE_CLIENT_HELLO;
            break;
         //Sending ClientHello message?
         case TLS_STATE_CLIENT_HELLO:
            //When a client first connects to a server, it is required to send
            //the ClientHello as its first message
            error = tlsSendClientHello(context);
            break;
         //Sending Certificate message?
         case TLS_STATE_CLIENT_CERTIFICATE:
            //This is the first message the client can send after receiving a
            //ServerHelloDone message. This message is only sent if the server
            //requests a certificate
            error = tlsSendCertificate(context);
            break;
         //Sending ClientKeyExchange message?
         case TLS_STATE_CLIENT_KEY_EXCHANGE:
            //This message is always sent by the client. It must immediately
            //follow the client certificate message, if it is sent. Otherwise,
            //it must be the first message sent by the client after it receives
            //the ServerHelloDone message
            error = tlsSendClientKeyExchange(context);
            break;
         //Sending CertificateVerify message?
         case TLS_STATE_CERTIFICATE_VERIFY:
            //This message is used to provide explicit verification of a client
            //certificate. This message is only sent following a client certificate
            //that has signing capability. When sent, it must immediately follow
            //the clientKeyExchange message
            error = tlsSendCertificateVerify(context);
            break;
         //Sending ChangeCipherSpec message?
         case TLS_STATE_CLIENT_CHANGE_CIPHER_SPEC:
            //The ChangeCipherSpec message is sent by the client and to notify the
            //server that subsequent records will be protected under the newly
            //negotiated CipherSpec and keys
            error = tlsSendChangeCipherSpec(context);
            break;
         //Sending Finished message?
         case TLS_STATE_CLIENT_FINISHED:
            //A Finished message is always sent immediately after a changeCipherSpec
            //message to verify that the key exchange and authentication processes
            //were successful
            error = tlsSendFinished(context);
            break;
         //Waiting for a message from the server?
         case TLS_STATE_SERVER_HELLO:
         case TLS_STATE_SERVER_CERTIFICATE:
         case TLS_STATE_SERVER_KEY_EXCHANGE:
         case TLS_STATE_CERTIFICATE_REQUEST:
         case TLS_STATE_SERVER_HELLO_DONE:
         case TLS_STATE_SERVER_CHANGE_CIPHER_SPEC:
         case TLS_STATE_SERVER_FINISHED:
            //Parse incoming handshake message
            error = tlsParseServerMessage(context);
            break;
         //Sending Alert message?
         case TLS_STATE_CLOSING:
            //Mark the TLS connection as closed
            context->state = TLS_STATE_CLOSED;
            break;
         //TLS connection closed?
         case TLS_STATE_CLOSED:
            //Debug message
            TRACE_WARNING("TLS handshake failure!\r\n");
            //Report an error
            error = ERROR_HANDSHAKE_FAILED;
            break;
         //Invalid state?
         default:
            //Report an error
            error = ERROR_UNEXPECTED_STATE;
            break;
         }
      }

      //Abort TLS handshake if an error was encountered
   } while(!error);

   //Any error to report?
   if(error)
   {
      //Send an alert message to the server, if applicable
      tlsProcessError(context, error);
   }

   //Return status code
   return error;
}


/**
 * @brief Parse incoming handshake message
 * @param[in] context Pointer to the TLS context
 * @return Error code
 **/

error_t tlsParseServerMessage(TlsContext *context)
{
   error_t error;
   size_t length;
   void *message;
   TlsContentType contentType;

   //A message can be fragmented across several records...
   error = tlsReadProtocolData(context, &message, &length, &contentType);

   //Check status code
   if(!error)
   {
      //Handshake message received?
      if(contentType == TLS_TYPE_HANDSHAKE)
      {
         //Check handshake message type
         switch(((TlsHandshake *) message)->msgType)
         {
         //HelloRequest message received?
         case TLS_TYPE_HELLO_REQUEST:
            //The HelloRequest message can be sent at any time but it should be
            //ignored by the client if it arrives in the middle of a handshake
            error = NO_ERROR;
            break;
         //ServerHello message received?
         case TLS_TYPE_SERVER_HELLO:
            //The server will send this message in response to a ClientHello
            //message when it was able to find an acceptable set of algorithms
            error = tlsParseServerHello(context, message, length);
            break;
         //Certificate message received?
         case TLS_TYPE_CERTIFICATE:
            //The server must send a Certificate message whenever the agreed-
            //upon key exchange method uses certificates for authentication. This
            //message will always immediately follow the ServerHello message
            error = tlsParseCertificate(context, message, length);
            break;
         //ServerKeyExchange message received?
         case TLS_TYPE_SERVER_KEY_EXCHANGE:
            //The ServerKeyExchange message is sent by the server only when the
            //server Certificate message (if sent) does not contain enough data
            //to allow the client to exchange a premaster secret
            error = tlsParseServerKeyExchange(context, message, length);
            break;
         //CertificateRequest message received?
         case TLS_TYPE_CERTIFICATE_REQUEST:
            //A non-anonymous server can optionally request a certificate from the
            //client, if appropriate for the selected cipher suite. This message,
            //if sent, will immediately follow the ServerKeyExchange message
            error = tlsParseCertificateRequest(context, message, length);
            break;
         //ServerHelloDone message received?
         case TLS_TYPE_SERVER_HELLO_DONE:
            //The ServerHelloDone message is sent by the server to indicate the
            //end of the ServerHello and associated messages
            error = tlsParseServerHelloDone(context, message, length);
            break;
         //Finished message received?
         case TLS_TYPE_FINISHED:
            //A Finished message is always sent immediately after a changeCipherSpec
            //message to verify that the key exchange and authentication processes
            //were successful
            error = tlsParseFinished(context, message, length);
            break;
         //Invalid handshake message received?
         default:
            //Report an error
            error = ERROR_UNEXPECTED_MESSAGE;
         }
      }
      //ChangeCipherSpec message received?
      else if(contentType == TLS_TYPE_CHANGE_CIPHER_SPEC)
      {
         //The ChangeCipherSpec message is sent by the server and to notify the
         //client that subsequent records will be protected under the newly
         //negotiated CipherSpec and keys
         error = tlsParseChangeCipherSpec(context, message, length);
      }
      //Alert message received?
      else if(contentType == TLS_TYPE_ALERT)
      {
         //Parse Alert message
         error = tlsParseAlert(context, message, length);
      }
      //Application data received?
      else
      {
         //The server cannot transmit application data
         //before the handshake is completed
         error = ERROR_UNEXPECTED_MESSAGE;
      }

      //Advance data pointer
      context->rxBufferPos += length;
      //Number of bytes still pending in the receive buffer
      context->rxBufferLen -= length;
   }

   //Return status code
   return error;
}


/**
 * @brief Send ClientHello message
 *
 * When a client first connects to a server, it is required to send
 * the ClientHello as its first message. The client can also send a
 * ClientHello in response to a HelloRequest or on its own initiative
 * in order to renegotiate the security parameters in an existing
 * connection
 *
 * @param[in] context Pointer to the TLS context
 * @return Error code
 **/

error_t tlsSendClientHello(TlsContext *context)
{
   error_t error;
   size_t length;
   TlsClientHello *message;

   //Point to the buffer where to format the message
   message = (TlsClientHello *) context->txBuffer;

   //Generate the client random value using a cryptographically-safe
   //pseudorandom number generator
   error = tlsGenerateRandomValue(context, &context->clientRandom);

   //Check status code
   if(!error)
   {
      //Format ClientHello message
      error = tlsFormatClientHello(context, message, &length);
   }

   //Check status code
   if(!error)
   {
      //Debug message
      TRACE_INFO("Sending ClientHello message (%" PRIuSIZE " bytes)...\r\n", length);
      TRACE_DEBUG_ARRAY("  ", message, length);

      //Send handshake message
      error = tlsWriteProtocolData(context, message, length, TLS_TYPE_HANDSHAKE);
   }

   //Check status code
   if(error == NO_ERROR || error == ERROR_WOULD_BLOCK || error == ERROR_TIMEOUT)
   {
      //Prepare to receive ServerHello message...
      context->state = TLS_STATE_SERVER_HELLO;
   }

   //Return status code
   return error;
}


/**
 * @brief Send ClientKeyExchange message
 *
 * This message is always sent by the client. It must immediately
 * follow the client Certificate message, if it is sent. Otherwise,
 * it must be the first message sent by the client after it receives
 * the ServerHelloDone message
 *
 * @param[in] context Pointer to the TLS context
 * @return Error code
 **/

error_t tlsSendClientKeyExchange(TlsContext *context)
{
   error_t error;
   size_t length;
   TlsClientKeyExchange *message;

   //Point to the buffer where to format the message
   message = (TlsClientKeyExchange *) context->txBuffer;

   //Format ClientKeyExchange message
   error = tlsFormatClientKeyExchange(context, message, &length);

   //Check status code
   if(!error)
   {
      //Debug message
      TRACE_INFO("Sending ClientKeyExchange message (%" PRIuSIZE " bytes)...\r\n", length);
      TRACE_DEBUG_ARRAY("  ", message, length);

      //Send handshake message
      error = tlsWriteProtocolData(context, message, length, TLS_TYPE_HANDSHAKE);
   }

   //Check status code
   if(error == NO_ERROR || error == ERROR_WOULD_BLOCK || error == ERROR_TIMEOUT)
   {
      //Derive session keys from the premaster secret
      error = tlsGenerateKeys(context);

      //Key material successfully generated?
      if(!error)
      {
         //Prepare to send CertificateVerify message...
         context->state = TLS_STATE_CERTIFICATE_VERIFY;
      }
   }

   //Return status code
   return error;
}


/**
 * @brief Send CertificateVerify message
 *
 * The CertificateVerify message is used to provide explicit verification
 * of a client certificate. This message is only sent following a client
 * certificate that has signing capability
 *
 * @param[in] context Pointer to the TLS context
 * @return Error code
 **/

error_t tlsSendCertificateVerify(TlsContext *context)
{
   error_t error;
   size_t length;
   TlsCertificateVerify *message;

   //Initialize status code
   error = NO_ERROR;

   //The CertificateVerify message is only sent following a client
   //certificate that has signing capability
   if(context->cert != NULL)
   {
      //Check certificate type
      if(context->cert->type == TLS_CERT_RSA_SIGN ||
         context->cert->type == TLS_CERT_DSS_SIGN ||
         context->cert->type == TLS_CERT_ECDSA_SIGN)
      {
         //Point to the buffer where to format the message
         message = (TlsCertificateVerify *) context->txBuffer;

         //Format CertificateVerify message
         error = tlsFormatCertificateVerify(context, message, &length);

         //Check status code
         if(!error)
         {
            //Debug message
            TRACE_INFO("Sending CertificateVerify message (%" PRIuSIZE " bytes)...\r\n", length);
            TRACE_DEBUG_ARRAY("  ", message, length);

            //Send handshake message
            error = tlsWriteProtocolData(context, message, length, TLS_TYPE_HANDSHAKE);
         }
      }
   }

   //Check status code
   if(error == NO_ERROR || error == ERROR_WOULD_BLOCK || error == ERROR_TIMEOUT)
   {
      //Prepare to send ChangeCipherSpec message...
      context->state = TLS_STATE_CLIENT_CHANGE_CIPHER_SPEC;
   }

   //Return status code
   return error;
}


/**
 * @brief Format ClientHello message
 * @param[in] context Pointer to the TLS context
 * @param[out] message Buffer where to format the ClientHello message
 * @param[out] length Length of the resulting ClientHello message
 * @return Error code
 **/

error_t tlsFormatClientHello(TlsContext *context,
   TlsClientHello *message, size_t *length)
{
   uint_t i;
   uint_t n;
   uint8_t *p;
   TlsCipherSuites *cipherSuites;
   TlsCompressionMethods *compressionMethods;
   TlsExtensions *extensionList;

   //This flag tells whether any ECC cipher suite is proposed by the client
   bool_t eccCipherSuite = FALSE;

   //Handshake message type
   message->msgType = TLS_TYPE_CLIENT_HELLO;
   //Version of the protocol being employed by the client
   message->clientVersion = HTONS(TLS_MAX_VERSION);
   //Client random value
   message->random = context->clientRandom;

   //Point to the session ID
   p = message->sessionId;
   //Total length of the message
   *length = sizeof(TlsClientHello);

#if (TLS_SESSION_RESUME_SUPPORT == ENABLED)
   //The SessionID value identifies a session the client wishes
   //to reuse for this connection
   message->sessionIdLength = (uint8_t) context->sessionIdLen;
   memcpy(message->sessionId, context->sessionId, context->sessionIdLen);
#else
   //Session resumption is not supported
   message->sessionIdLength = 0;
#endif

   //Point to the next field
   p += message->sessionIdLength;
   //Adjust the length of the message
   *length += message->sessionIdLength;

   //List of cryptographic algorithms supported by the client
   cipherSuites = (TlsCipherSuites *) p;

   //Debug message
   TRACE_DEBUG("Cipher suites:\r\n");

   //User preferred cipher suite list
   if(context->numCipherSuites > 0)
   {
      //Number of cipher suites in the array
      n = 0;

      //Parse cipher suites
      for(i = 0; i < context->numCipherSuites; i++)
      {
         //Make sure the specified cipher suite is supported
         if(tlsIsCipherSuiteSupported(context->cipherSuites[i]))
         {
            //Copy cipher suite identifier
            cipherSuites->value[n++] = htons(context->cipherSuites[i]);

            //Debug message
            TRACE_DEBUG("  0x%04" PRIX16 " (%s)\r\n", context->cipherSuites[i],
               tlsGetCipherSuiteName(context->cipherSuites[i]));

            //ECC cipher suite?
            if(tlsIsEccCipherSuite(context->cipherSuites[i]))
               eccCipherSuite = TRUE;
         }
      }
   }
   //Default cipher suite list
   else
   {
      //Determine the number of supported cipher suites
      n = tlsGetNumSupportedCipherSuites();

      //Parse cipher suites
      for(i = 0; i < n; i++)
      {
         //Copy cipher suite identifier
         cipherSuites->value[i] = htons(tlsSupportedCipherSuites[i].identifier);

         //Debug message
         TRACE_DEBUG("  0x%04" PRIX16 " (%s)\r\n", tlsSupportedCipherSuites[i].identifier,
            tlsSupportedCipherSuites[i].name);

         //ECC cipher suite?
         if(tlsIsEccCipherSuite(tlsSupportedCipherSuites[i].identifier))
            eccCipherSuite = TRUE;
      }
   }

   //Length of the array, in bytes
   cipherSuites->length = htons(n * 2);
   //Point to the next field
   p += sizeof(TlsCipherSuites) + n * 2;
   //Total length of the message
   *length += sizeof(TlsCipherSuites) + n * 2;

   //List of compression algorithms supported by the client
   compressionMethods = (TlsCompressionMethods *) p;

   //The CRIME exploit takes advantage of TLS compression, so conservative
   //implementations do not enable compression at the TLS level
   compressionMethods->length = 1;
   compressionMethods->value[0] = TLS_COMPRESSION_METHOD_NULL;

   //Point to the next field
   p += sizeof(TlsCompressionMethods) + compressionMethods->length;
   //Total length of the message
   *length += sizeof(TlsCompressionMethods) + compressionMethods->length;

   //Clients may request extended functionality from servers by sending
   //data in the extensions field
   extensionList = (TlsExtensions *) p;
   //Total length of the extension list
   extensionList->length = 0;

   //Point to the first extension of the list
   p += sizeof(TlsExtensions);

#if (TLS_SNI_SUPPORT == ENABLED)
   //In order to provide the server name, clients may include a ServerName extension
   if(context->serverName != NULL)
   {
      TlsExtension *extension;
      TlsServerNameList *serverNameList;
      TlsServerName *serverName;

      //Determine the length of the server name
      n = strlen(context->serverName);

      //Add SNI (Server Name Indication) extension
      extension = (TlsExtension *) p;
      //Type of the extension
      extension->type = HTONS(TLS_EXT_SERVER_NAME);

      //Point to the list of server names
      serverNameList = (TlsServerNameList *) extension->value;

      //Point to the server name
      serverName = (TlsServerName *) serverNameList->value;
      //Fill in the type and the length fields
      serverName->type = TLS_NAME_TYPE_HOSTNAME;
      serverName->length = htons(n);
      //Copy server name
      memcpy(serverName->hostname, context->serverName, n);

      //Compute the length, in byte, of the structure
      n += sizeof(TlsServerName);
      //Fix the length of the list
      serverNameList->length = htons(n);

      //Consider the 2-byte length field that precedes the list
      n += sizeof(TlsServerNameList);
      //Fix the length of the extension
      extension->length = htons(n);

      //Compute the length, in bytes, of the ServerName extension
      n += sizeof(TlsExtension);
      //Fix the length of the extension list
      extensionList->length += n;

      //Point to the next field
      p += n;
      //Total length of the message
      *length += n;
   }
#endif

#if (TLS_ALPN_SUPPORT == ENABLED)
   //The ALPN extension contains the list of protocols advertised by the
   //client, in descending order of preference
   if(context->protocolList != NULL)
   {
      uint_t j;
      TlsExtension *extension;
      TlsProtocolNameList *protocolNameList;
      TlsProtocolName *protocolName;

      //Add ALPN (Application-Layer Protocol Negotiation) extension
      extension = (TlsExtension *) p;
      //Type of the extension
      extension->type = HTONS(TLS_EXT_ALPN);

      //Point to the list of protocol names
      protocolNameList = (TlsProtocolNameList *) extension->value;

      //Move back to the beginning of the list
      i = 0;
      j = 0;
      n = 0;

      //Parse the list of supported protocols
      do
      {
         //Delimiter character found?
         if(context->protocolList[i] == ',' || context->protocolList[i] == '\0')
         {
            //Discard empty tokens
            if((i - j) > 0)
            {
               //Point to the protocol name
               protocolName = (TlsProtocolName *) (protocolNameList->value + n);

               //Fill in the length field
               protocolName->length = i - j;
               //Copy protocol name
               memcpy(protocolName->value, context->protocolList + j, i - j);

               //Adjust the length of the list
               n += sizeof(TlsProtocolName) + i - j;
            }

            //Move to the next token
            j = i + 1;
         }

         //Loop until the NULL character is reached
      } while(context->protocolList[i++] != '\0');

      //Fix the length of the list
      protocolNameList->length = htons(n);

      //Consider the 2-byte length field that precedes the list
      n += sizeof(TlsProtocolNameList);
      //Fix the length of the extension
      extension->length = htons(n);

      //Compute the length, in bytes, of the ALPN extension
      n += sizeof(TlsExtension);
      //Fix the length of the extension list
      extensionList->length += n;

      //Point to the next field
      p += n;
      //Total length of the message
      *length += n;
   }
#endif

#if (TLS_ECDH_ANON_SUPPORT == ENABLED || TLS_ECDHE_RSA_SUPPORT == ENABLED || \
   TLS_ECDHE_ECDSA_SUPPORT == ENABLED || TLS_ECDHE_PSK_SUPPORT == ENABLED)
   //A client that proposes ECC cipher suites in its ClientHello message
   //should send the EllipticCurves extension
   if(eccCipherSuite)
   {
      TlsExtension *extension;
      TlsEllipticCurveList *ellipticCurveList;

      //Add the EllipticCurves extension
      extension = (TlsExtension *) p;
      //Type of the extension
      extension->type = HTONS(TLS_EXT_ELLIPTIC_CURVES);

      //Point to the list of supported elliptic curves
      ellipticCurveList = (TlsEllipticCurveList *) extension->value;
      //Items in the list are ordered according to client's preferences
      n = 0;

#if (TLS_SECP160K1_SUPPORT == ENABLED)
      //Support for secp160k1 elliptic curve
      ellipticCurveList->value[n++] = HTONS(TLS_EC_CURVE_SECP160K1);
#endif
#if (TLS_SECP160R1_SUPPORT == ENABLED)
      //Support for secp160r1 elliptic curve
      ellipticCurveList->value[n++] = HTONS(TLS_EC_CURVE_SECP160R1);
#endif
#if (TLS_SECP160R2_SUPPORT == ENABLED)
      //Support for secp160r2 elliptic curve
      ellipticCurveList->value[n++] = HTONS(TLS_EC_CURVE_SECP160R2);
#endif
#if (TLS_SECP192K1_SUPPORT == ENABLED)
      //Support for secp192k1 elliptic curve
      ellipticCurveList->value[n++] = HTONS(TLS_EC_CURVE_SECP192K1);
#endif
#if (TLS_SECP192R1_SUPPORT == ENABLED)
      //Support for secp192r1 elliptic curve
      ellipticCurveList->value[n++] = HTONS(TLS_EC_CURVE_SECP192R1);
#endif
#if (TLS_SECP224K1_SUPPORT == ENABLED)
      //Support for secp224k1 elliptic curve
      ellipticCurveList->value[n++] = HTONS(TLS_EC_CURVE_SECP224K1);
#endif
#if (TLS_SECP224R1_SUPPORT == ENABLED)
      //Support for secp224r1 elliptic curve
      ellipticCurveList->value[n++] = HTONS(TLS_EC_CURVE_SECP224R1);
#endif
#if (TLS_SECP256K1_SUPPORT == ENABLED)
      //Support for secp256k1 elliptic curve
      ellipticCurveList->value[n++] = HTONS(TLS_EC_CURVE_SECP256K1);
#endif
#if (TLS_SECP256R1_SUPPORT == ENABLED)
      //Support for secp256r1 elliptic curve
      ellipticCurveList->value[n++] = HTONS(TLS_EC_CURVE_SECP256R1);
#endif
#if (TLS_SECP384R1_SUPPORT == ENABLED)
      //Support for secp384r1 elliptic curve
      ellipticCurveList->value[n++] = HTONS(TLS_EC_CURVE_SECP384R1);
#endif
#if (TLS_SECP521R1_SUPPORT == ENABLED)
      //Support for secp521r1 elliptic curve
      ellipticCurveList->value[n++] = HTONS(TLS_EC_CURVE_SECP521R1);
#endif
#if (TLS_BRAINPOOLP256R1_SUPPORT == ENABLED)
      //Support for brainpoolP256r1 elliptic curve
      ellipticCurveList->value[n++] = HTONS(TLS_EC_CURVE_BRAINPOOLP256R1);
#endif
#if (TLS_BRAINPOOLP384R1_SUPPORT == ENABLED)
      //Support for brainpoolP384r1 elliptic curve
      ellipticCurveList->value[n++] = HTONS(TLS_EC_CURVE_BRAINPOOLP384R1);
#endif
#if (TLS_BRAINPOOLP512R1_SUPPORT == ENABLED)
      //Support for brainpoolP512r1 elliptic curve
      ellipticCurveList->value[n++] = HTONS(TLS_EC_CURVE_BRAINPOOLP512R1);
#endif

      //Compute the length, in bytes, of the list
      n *= 2;
      //Fix the length of the list
      ellipticCurveList->length = htons(n);

      //Consider the 2-byte length field that precedes the list
      n += sizeof(TlsEllipticCurveList);
      //Fix the length of the extension
      extension->length = htons(n);

      //Compute the length, in bytes, of the EllipticCurves extension
      n += sizeof(TlsExtension);
      //Fix the length of the extension list
      extensionList->length += n;

      //Point to the next field
      p += n;
      //Total length of the message
      *length += n;
   }

   //A client that proposes ECC cipher suites in its ClientHello message
   //should send the EcPointFormats extension
   if(eccCipherSuite)
   {
      TlsExtension *extension;
      TlsEcPointFormatList *ecPointFormatList;

      //Add the EcPointFormats extension
      extension = (TlsExtension *) p;
      //Type of the extension
      extension->type = HTONS(TLS_EXT_EC_POINT_FORMATS);

      //Point to the list of supported EC point formats
      ecPointFormatList = (TlsEcPointFormatList *) extension->value;
      //Items in the list are ordered according to client's preferences
      n = 0;

      //The client can parse only the uncompressed point format...
      ecPointFormatList->value[n++] = TLS_EC_POINT_FORMAT_UNCOMPRESSED;
      //Fix the length of the list
      ecPointFormatList->length = n;

      //Consider the 2-byte length field that precedes the list
      n += sizeof(TlsEcPointFormatList);
      //Fix the length of the extension
      extension->length = htons(n);

      //Compute the length, in bytes, of the EcPointFormats extension
      n += sizeof(TlsExtension);
      //Fix the length of the extension list
      extensionList->length += n;

      //Point to the next field
      p += n;
      //Total length of the message
      *length += n;
   }
#endif

#if (TLS_MAX_VERSION >= TLS_VERSION_1_2 && TLS_MIN_VERSION <= TLS_VERSION_1_2)
   //Include the SignatureAlgorithms extension only if TLS 1.2 is supported
   {
      TlsExtension *extension;
      TlsSignHashAlgos *supportedSignAlgos;

      //Add the SignatureAlgorithms extension
      extension = (TlsExtension *) p;
      //Type of the extension
      extension->type = HTONS(TLS_EXT_SIGNATURE_ALGORITHMS);

      //Point to the list of the hash/signature algorithm pairs that
      //the server is able to verify
      supportedSignAlgos = (TlsSignHashAlgos *) extension->value;

      //Enumerate the hash/signature algorithm pairs in descending
      //order of preference
      n = 0;

#if (TLS_RSA_SIGN_SUPPORT == ENABLED)
      //MD5 with RSA is always supported
      supportedSignAlgos->value[n].signature = TLS_SIGN_ALGO_RSA;
      supportedSignAlgos->value[n++].hash = TLS_HASH_ALGO_MD5;
      //SHA-1 with RSA is always supported
      supportedSignAlgos->value[n].signature = TLS_SIGN_ALGO_RSA;
      supportedSignAlgos->value[n++].hash = TLS_HASH_ALGO_SHA1;
#if (TLS_SHA224_SUPPORT == ENABLED)
      //SHA-224 with RSA support is optional
      supportedSignAlgos->value[n].signature = TLS_SIGN_ALGO_RSA;
      supportedSignAlgos->value[n++].hash = TLS_HASH_ALGO_SHA224;
#endif
      //SHA-256 with RSA is always supported
      supportedSignAlgos->value[n].signature = TLS_SIGN_ALGO_RSA;
      supportedSignAlgos->value[n++].hash = TLS_HASH_ALGO_SHA256;
#if (TLS_SHA384_SUPPORT == ENABLED)
      //SHA-384 with RSA support is optional
      supportedSignAlgos->value[n].signature = TLS_SIGN_ALGO_RSA;
      supportedSignAlgos->value[n++].hash = TLS_HASH_ALGO_SHA384;
#endif
#if (TLS_SHA512_SUPPORT == ENABLED)
      //SHA-512 with RSA support is optional
      supportedSignAlgos->value[n].signature = TLS_SIGN_ALGO_RSA;
      supportedSignAlgos->value[n++].hash = TLS_HASH_ALGO_SHA512;
#endif
#endif

#if (TLS_DSA_SIGN_SUPPORT == ENABLED)
      //DSA with SHA-1 is always supported
      supportedSignAlgos->value[n].signature = TLS_SIGN_ALGO_DSA;
      supportedSignAlgos->value[n++].hash = TLS_HASH_ALGO_SHA1;
#if (TLS_SHA224_SUPPORT == ENABLED)
      //DSA with SHA-224 support is optional
      supportedSignAlgos->value[n].signature = TLS_SIGN_ALGO_DSA;
      supportedSignAlgos->value[n++].hash = TLS_HASH_ALGO_SHA224;
#endif
      //DSA with SHA-256 is always supported
      supportedSignAlgos->value[n].signature = TLS_SIGN_ALGO_DSA;
      supportedSignAlgos->value[n++].hash = TLS_HASH_ALGO_SHA256;
#endif

#if (TLS_ECDSA_SIGN_SUPPORT == ENABLED)
      //Any ECC cipher suite proposed by the client?
      if(eccCipherSuite)
      {
         //ECDSA with SHA-1 is always supported
         supportedSignAlgos->value[n].signature = TLS_SIGN_ALGO_ECDSA;
         supportedSignAlgos->value[n++].hash = TLS_HASH_ALGO_SHA1;
#if (TLS_SHA224_SUPPORT == ENABLED)
         //ECDSA with SHA-224 support is optional
         supportedSignAlgos->value[n].signature = TLS_SIGN_ALGO_ECDSA;
         supportedSignAlgos->value[n++].hash = TLS_HASH_ALGO_SHA224;
#endif
         //ECDSA with SHA-256 is always supported
         supportedSignAlgos->value[n].signature = TLS_SIGN_ALGO_ECDSA;
         supportedSignAlgos->value[n++].hash = TLS_HASH_ALGO_SHA256;
#if (TLS_SHA384_SUPPORT == ENABLED)
         //ECDSA with SHA-384 support is optional
         supportedSignAlgos->value[n].signature = TLS_SIGN_ALGO_ECDSA;
         supportedSignAlgos->value[n++].hash = TLS_HASH_ALGO_SHA384;
#endif
#if (TLS_SHA512_SUPPORT == ENABLED)
         //ECDSA with SHA-512 support is optional
         supportedSignAlgos->value[n].signature = TLS_SIGN_ALGO_ECDSA;
         supportedSignAlgos->value[n++].hash = TLS_HASH_ALGO_SHA512;
#endif
      }
#endif

      //Compute the length, in bytes, of the list
      n *= sizeof(TlsSignHashAlgo);
      //Fix the length of the list
      supportedSignAlgos->length = htons(n);

      //Consider the 2-byte length field that precedes the list
      n += sizeof(TlsSignHashAlgos);
      //Fix the length of the extension
      extension->length = htons(n);

      //Compute the length, in bytes, of the SignatureAlgorithms extension
      n += sizeof(TlsExtension);
      //Fix the length of the extension list
      extensionList->length += n;

      //Point to the next field
      p += n;
      //Total length of the message
      *length += n;
   }
#endif

   //Check whether the extension list is empty
   if(extensionList->length > 0)
   {
      //Convert the length of the extension list to network byte order
      extensionList->length = htons(extensionList->length);
      //Total length of the message
      *length += sizeof(TlsExtensions);
   }

   //Fix the length field
   STORE24BE(*length - sizeof(TlsHandshake), message->length);

   //Successful processing
   return NO_ERROR;
}


/**
 * @brief Format ClientKeyExchange message
 * @param[in] context Pointer to the TLS context
 * @param[out] message Buffer where to format the ClientKeyExchange message
 * @param[out] length Length of the resulting ClientKeyExchange message
 * @return Error code
 **/

error_t tlsFormatClientKeyExchange(TlsContext *context,
   TlsClientKeyExchange *message, size_t *length)
{
   error_t error;
   size_t n;
   uint8_t *p;

   //Handshake message type
   message->msgType = TLS_TYPE_CLIENT_KEY_EXCHANGE;

   //Point to the body of the handshake message
   p = message->data;
   //Length of the handshake message
   *length = 0;

   //PSK key exchange method?
   if(context->keyExchMethod == TLS_KEY_EXCH_PSK ||
      context->keyExchMethod == TLS_KEY_EXCH_RSA_PSK ||
      context->keyExchMethod == TLS_KEY_EXCH_DHE_PSK ||
      context->keyExchMethod == TLS_KEY_EXCH_ECDHE_PSK)
   {
      //The client indicates which key to use by including a PSK identity
      //in the ClientKeyExchange message
      error = tlsFormatPskIdentity(context, p, &n);
      //Any error to report?
      if(error)
         return error;

      //Advance data pointer
      p += n;
      //Adjust the length of the message
      *length += n;
   }

   //RSA, Diffie-Hellman or ECDH key exchange method?
   if(context->keyExchMethod != TLS_KEY_EXCH_PSK)
   {
      //Format client's key exchange parameters
      error = tlsFormatClientKeyParams(context, p, &n);
      //Any error to report?
      if(error)
         return error;

      //Advance data pointer
      p += n;
      //Adjust the length of the message
      *length += n;
   }

   //PSK key exchange method?
   if(context->keyExchMethod == TLS_KEY_EXCH_PSK ||
      context->keyExchMethod == TLS_KEY_EXCH_RSA_PSK ||
      context->keyExchMethod == TLS_KEY_EXCH_DHE_PSK ||
      context->keyExchMethod == TLS_KEY_EXCH_ECDHE_PSK)
   {
      //Generate premaster secret
      error = tlsGeneratePskPremasterSecret(context);
      //Any error to report?
      if(error)
         return error;
   }

   //Fix the length field
   STORE24BE(*length, message->length);
   //Length of the complete handshake message
   *length += sizeof(TlsHandshake);

   //Successful processing
   return NO_ERROR;
}


/**
 * @brief Format CertificateVerify message
 * @param[in] context Pointer to the TLS context
 * @param[out] message Buffer where to format the CertificateVerify message
 * @param[out] length Length of the resulting CertificateVerify message
 * @return Error code
 **/

error_t tlsFormatCertificateVerify(TlsContext *context,
   TlsCertificateVerify *message, size_t *length)
{
   error_t error;

   //Initialize message length
   *length = 0;

   //Handshake message type
   message->msgType = TLS_TYPE_CERTIFICATE_VERIFY;

#if (TLS_MAX_VERSION >= SSL_VERSION_3_0 && TLS_MIN_VERSION <= TLS_VERSION_1_1)
   //SSL 3.0, TLS 1.0 or TLS 1.1 currently selected?
   if(context->version <= TLS_VERSION_1_1)
   {
      TlsDigitalSignature *signature;

      //Point to the digitally-signed element
      signature = (TlsDigitalSignature *) message->signature;

#if (TLS_RSA_SIGN_SUPPORT == ENABLED)
      //The client's certificate contains a valid RSA public key?
      if(context->cert->type == TLS_CERT_RSA_SIGN)
      {
         RsaPrivateKey privateKey;

         //Initialize RSA private key
         rsaInitPrivateKey(&privateKey);

         //Digest all the handshake messages starting at ClientHello (using MD5)
         error = tlsFinalizeHandshakeHash(context, MD5_HASH_ALGO,
            context->handshakeMd5Context, "", context->verifyData);

         //Check status code
         if(!error)
         {
            //Digest all the handshake messages starting at ClientHello (using SHA-1)
            error = tlsFinalizeHandshakeHash(context, SHA1_HASH_ALGO,
               context->handshakeSha1Context, "", context->verifyData + MD5_DIGEST_SIZE);
         }

         //Check status code
         if(!error)
         {
            //Decode the PEM structure that holds the RSA private key
            error = pemReadRsaPrivateKey(context->cert->privateKey,
               context->cert->privateKeyLength, &privateKey);
         }

         //Check status code
         if(!error)
         {
            //Generate a RSA signature using the client's private key
            error = tlsGenerateRsaSignature(&privateKey,
               context->verifyData, signature->value, length);
         }

         //Release previously allocated resources
         rsaFreePrivateKey(&privateKey);
      }
      else
#endif
#if (TLS_DSA_SIGN_SUPPORT == ENABLED)
      //The client's certificate contains a valid DSA public key?
      if(context->cert->type == TLS_CERT_DSS_SIGN)
      {
         DsaPrivateKey privateKey;

         //Initialize DSA private key
         dsaInitPrivateKey(&privateKey);

         //Digest all the handshake messages starting at ClientHello
         error = tlsFinalizeHandshakeHash(context, SHA1_HASH_ALGO,
            context->handshakeSha1Context, "", context->verifyData);

         //Check status code
         if(!error)
         {
            //Decode the PEM structure that holds the DSA private key
            error = pemReadDsaPrivateKey(context->cert->privateKey,
               context->cert->privateKeyLength, &privateKey);
         }

         //Check status code
         if(!error)
         {
            //Generate a DSA signature using the client's private key
            error = tlsGenerateDsaSignature(context->prngAlgo,
               context->prngContext, &privateKey, context->verifyData,
               SHA1_DIGEST_SIZE, signature->value, length);
         }

         //Release previously allocated resources
         dsaFreePrivateKey(&privateKey);
      }
      else
#endif
#if (TLS_ECDSA_SIGN_SUPPORT == ENABLED)
      //The client's certificate contains a valid ECDSA public key?
      if(context->cert->type == TLS_CERT_ECDSA_SIGN)
      {
         EcDomainParameters params;
         Mpi privateKey;

         //Initialize EC domain parameters
         ecInitDomainParameters(&params);
         //Initialize EC private key
         mpiInit(&privateKey);

         //Digest all the handshake messages starting at ClientHello
         error = tlsFinalizeHandshakeHash(context, SHA1_HASH_ALGO,
            context->handshakeSha1Context, "", context->verifyData);

         //Check status code
         if(!error)
         {
            //Decode the PEM structure that holds the EC domain parameters
            error = pemReadEcParameters(context->cert->privateKey,
               context->cert->privateKeyLength, &params);
         }

         //Check status code
         if(!error)
         {
            //Decode the PEM structure that holds the EC private key
            error = pemReadEcPrivateKey(context->cert->privateKey,
               context->cert->privateKeyLength, &privateKey);
         }

         //Check status code
         if(!error)
         {
            //Generate an ECDSA signature using the client's private key
            error = tlsGenerateEcdsaSignature(&params, context->prngAlgo,
               context->prngContext, &privateKey, context->verifyData,
               SHA1_DIGEST_SIZE, signature->value, length);
         }

         //Release previously allocated resources
         ecFreeDomainParameters(&params);
         mpiFree(&privateKey);
      }
      else
#endif
      //Invalid signature algorithm?
      {
         //Report an error
         error = ERROR_UNSUPPORTED_SIGNATURE_ALGO;
      }

      //Length of the signature
      signature->length = htons(*length);
      //Total length of the digitally-signed element
      *length += sizeof(TlsDigitalSignature);
   }
   else
#endif
#if (TLS_MAX_VERSION >= TLS_VERSION_1_2 && TLS_MIN_VERSION <= TLS_VERSION_1_2)
   //TLS 1.2 currently selected?
   if(context->version == TLS_VERSION_1_2)
   {
      TlsDigitalSignature2 *signature;
      const HashAlgo *hashAlgo;

      //Point to the digitally-signed element
      signature = (TlsDigitalSignature2 *) message->signature;

      //Retrieve the hash algorithm to be used for signing
      hashAlgo = tlsGetHashAlgo(context->signHashAlgo);

      //Digest all the handshake messages starting at ClientHello
      if(hashAlgo == SHA1_HASH_ALGO)
      {
         //Use SHA-1 hash algorithm
         error = tlsFinalizeHandshakeHash(context, SHA1_HASH_ALGO,
            context->handshakeSha1Context, "", context->verifyData);
      }
      else if(hashAlgo == context->prfHashAlgo)
      {
         //Use PRF hash algorithm (SHA-256 or SHA-384)
         error = tlsFinalizeHandshakeHash(context, hashAlgo,
            context->handshakeHashContext, "", context->verifyData);
      }
      else
      {
         //The specified hash algorithm is not supported
         error = ERROR_UNSUPPORTED_SIGNATURE_ALGO;
      }

      //Handshake message hash successfully computed?
      if(!error)
      {
#if (TLS_RSA_SIGN_SUPPORT == ENABLED)
         //The client's certificate contains a valid RSA public key?
         if(context->cert->type == TLS_CERT_RSA_SIGN)
         {
            RsaPrivateKey privateKey;

            //Initialize RSA private key
            rsaInitPrivateKey(&privateKey);

            //Set the relevant signature algorithm
            signature->algorithm.signature = TLS_SIGN_ALGO_RSA;
            signature->algorithm.hash = context->signHashAlgo;

            //Decode the PEM structure that holds the RSA private key
            error = pemReadRsaPrivateKey(context->cert->privateKey,
               context->cert->privateKeyLength, &privateKey);

            //Check status code
            if(!error)
            {
               //Use the signature algorithm defined in PKCS #1 v1.5
               error = rsassaPkcs1v15Sign(&privateKey, hashAlgo,
                  context->verifyData, signature->value, length);
            }

            //Release previously allocated resources
            rsaFreePrivateKey(&privateKey);
         }
         else
#endif
#if (TLS_DSA_SIGN_SUPPORT == ENABLED)
         //The client's certificate contains a valid DSA public key?
         if(context->cert->type == TLS_CERT_DSS_SIGN)
         {
            DsaPrivateKey privateKey;

            //Initialize DSA private key
            dsaInitPrivateKey(&privateKey);

            //Set the relevant signature algorithm
            signature->algorithm.signature = TLS_SIGN_ALGO_DSA;
            signature->algorithm.hash = context->signHashAlgo;

            //Decode the PEM structure that holds the DSA private key
            error = pemReadDsaPrivateKey(context->cert->privateKey,
               context->cert->privateKeyLength, &privateKey);

            //Check status code
            if(!error)
            {
               //Generate a DSA signature using the client's private key
               error = tlsGenerateDsaSignature(context->prngAlgo,
                  context->prngContext, &privateKey, context->verifyData,
                  hashAlgo->digestSize, signature->value, length);
            }

            //Release previously allocated resources
            dsaFreePrivateKey(&privateKey);
         }
         else
#endif
#if (TLS_ECDSA_SIGN_SUPPORT == ENABLED)
         //The client's certificate contains a valid ECDSA public key?
         if(context->cert->type == TLS_CERT_ECDSA_SIGN)
         {
            EcDomainParameters params;
            Mpi privateKey;

            //Initialize EC domain parameters
            ecInitDomainParameters(&params);
            //Initialize EC private key
            mpiInit(&privateKey);

            //Set the relevant signature algorithm
            signature->algorithm.signature = TLS_SIGN_ALGO_ECDSA;
            signature->algorithm.hash = context->signHashAlgo;

            //Decode the PEM structure that holds the EC domain parameters
            error = pemReadEcParameters(context->cert->privateKey,
               context->cert->privateKeyLength, &params);

            //Check status code
            if(!error)
            {
               //Decode the PEM structure that holds the EC private key
               error = pemReadEcPrivateKey(context->cert->privateKey,
                  context->cert->privateKeyLength, &privateKey);
            }

            //Check status code
            if(!error)
            {
               //Generate an ECDSA signature using the client's private key
               error = tlsGenerateEcdsaSignature(&params, context->prngAlgo,
                  context->prngContext, &privateKey, context->verifyData,
                  hashAlgo->digestSize, signature->value, length);
            }

            //Release previously allocated resources
            ecFreeDomainParameters(&params);
            mpiFree(&privateKey);
         }
         else
#endif
         //Invalid signature algorithm?
         {
            //Report an error
            error = ERROR_UNSUPPORTED_SIGNATURE_ALGO;
         }
      }

      //Length of the signature
      signature->length = htons(*length);
      //Length of the digitally-signed element
      *length += sizeof(TlsDigitalSignature2);
   }
   else
#endif
   {
      //The negotiated TLS version is not valid
      error = ERROR_INVALID_VERSION;
   }

   //Fix the length field
   STORE24BE(*length, message->length);
   //Length of the complete handshake message
   *length += sizeof(TlsHandshake);

   //Return status code
   return error;
}


/**
 * @brief Parse ServerHello message
 *
 * The server will send this message in response to a ClientHello
 * message when it was able to find an acceptable set of algorithms.
 * If it cannot find such a match, it will respond with a handshake
 * failure alert
 *
 * @param[in] context Pointer to the TLS context
 * @param[in] message Incoming ServerHello message to parse
 * @param[in] length Message length
 * @return Error code
 **/

error_t tlsParseServerHello(TlsContext *context, const TlsServerHello *message, size_t length)
{
   error_t error;
   size_t n;
   const uint8_t *p;
   TlsCipherSuite cipherSuite;
   TlsCompressionMethod compressionMethod;

   //Debug message
   TRACE_INFO("ServerHello message received (%" PRIuSIZE " bytes)...\r\n", length);
   TRACE_DEBUG_ARRAY("  ", message, length);

   //Check the length of the ServerHello message
   if(length < sizeof(TlsServerHello))
      return ERROR_DECODING_FAILED;

   //Check current state
   if(context->state != TLS_STATE_SERVER_HELLO)
      return ERROR_UNEXPECTED_MESSAGE;

   //Point to the session ID
   p = (uint8_t *) message + sizeof(TlsServerHello);
   //Remaining bytes to process
   n = length - sizeof(TlsServerHello);

   //Check the length of the session ID
   if(message->sessionIdLength > n)
      return ERROR_DECODING_FAILED;
   if(message->sessionIdLength > 32)
      return ERROR_ILLEGAL_PARAMETER;

   //Point to the next field
   p += message->sessionIdLength;
   //Remaining bytes to process
   n -= message->sessionIdLength;

   //Malformed ServerHello message?
   if(n < (sizeof(TlsCipherSuite) + sizeof(TlsCompressionMethod)))
      return ERROR_DECODING_FAILED;

   //Get the negotiated cipher suite
   cipherSuite = LOAD16BE(p);
   //Point to the next field
   p += sizeof(TlsCipherSuite);
   //Remaining bytes to process
   n -= sizeof(TlsCipherSuite);

   //Get the negotiated compression method
   compressionMethod = *p;
   //Point to the next field
   p += sizeof(TlsCompressionMethod);
   //Remaining bytes to process
   n -= sizeof(TlsCompressionMethod);

   //Server version
   TRACE_INFO("  serverVersion = 0x%04" PRIX16 " (%s)\r\n", ntohs(message->serverVersion),
      tlsGetVersionName(ntohs(message->serverVersion)));
   //Server random value
   TRACE_INFO("  random\r\n");
   TRACE_INFO_ARRAY("    ", &message->random, sizeof(TlsRandom));
   //Session identifier
   TRACE_INFO("  sessionId\r\n");
   TRACE_INFO_ARRAY("    ", message->sessionId, message->sessionIdLength);
   //Cipher suite identifier
   TRACE_INFO("  cipherSuite = 0x%04" PRIX16 " (%s)\r\n",
      cipherSuite, tlsGetCipherSuiteName(cipherSuite));
   //Compression method
   TRACE_INFO("  compressionMethod = 0x%02" PRIX8 "\r\n", compressionMethod);

#if (TLS_SESSION_RESUME_SUPPORT == ENABLED)
   //Check whether the session ID matches the value that was supplied by the client
   if(message->sessionIdLength > 0 && message->sessionIdLength == context->sessionIdLen &&
      !memcmp(message->sessionId, context->sessionId, context->sessionIdLen))
   {
      //For resumed sessions, the selected cipher suite and compression
      //method shall be the same as the session being resumed
      if(cipherSuite != context->cipherSuite ||
         compressionMethod != context->compressionMethod)
      {
         //The session ID is no more valid
         context->sessionIdLen = 0;
         //When renegotiating, if the server tries to use another
         //version or compression method than previously, abort
         return ERROR_HANDSHAKE_FAILED;
      }

      //Perform abbreviated handshake
      context->resume = TRUE;
   }
   else
#endif
   {
      //Perform a full handshake
      context->resume = FALSE;
   }

   //Save server random value
   context->serverRandom = message->random;

   //Save session identifier
   memcpy(context->sessionId, message->sessionId, message->sessionIdLength);
   context->sessionIdLen = message->sessionIdLength;

   //Set the TLS version to use
   error = tlsSetVersion(context, ntohs(message->serverVersion));
   //The specified TLS version is not supported?
   if(error)
      return error;

   //Set cipher suite
   error = tlsSetCipherSuite(context, cipherSuite);
   //The specified cipher suite is not supported?
   if(error)
      return error;

   //Set compression method
   error = tlsSetCompressionMethod(context, compressionMethod);
   //The specified compression method is not supported?
   if(error)
      return error;

   //Initialize handshake message hashing
   error = tlsInitHandshakeHash(context);
   //Any error to report?
   if(error)
      return error;

   //Update the hash value with the incoming handshake message
   tlsUpdateHandshakeHash(context, message, length);

#if (TLS_SESSION_RESUME_SUPPORT == ENABLED)
   //Use abbreviated handshake?
   if(context->resume)
   {
      //Derive session keys from the master secret
      error = tlsGenerateKeys(context);
      //Unable to generate key material?
      if(error)
         return error;

      //At this point, both client and server must send ChangeCipherSpec
      //messages and proceed directly to Finished messages
      context->state = TLS_STATE_SERVER_CHANGE_CIPHER_SPEC;
   }
   else
#endif
   {
      //Perform a full handshake
      if(context->keyExchMethod == TLS_KEY_EXCH_PSK ||
         context->keyExchMethod == TLS_KEY_EXCH_DH_ANON ||
         context->keyExchMethod == TLS_KEY_EXCH_DHE_PSK ||
         context->keyExchMethod == TLS_KEY_EXCH_ECDH_ANON ||
         context->keyExchMethod == TLS_KEY_EXCH_ECDHE_PSK)
      {
         //The Certificate message is omitted from the server's response
         context->state = TLS_STATE_SERVER_KEY_EXCHANGE;
      }
      else
      {
         //The server is required to send a Certificate message
         context->state = TLS_STATE_SERVER_CERTIFICATE;
      }
   }

   //Successful processing
   return NO_ERROR;
}


/**
 * @brief Parse ServerKeyExchange message
 *
 * The ServerKeyExchange message is sent by the server only when the
 * server Certificate message does not contain enough data to allow
 * the client to exchange a premaster secret
 *
 * @param[in] context Pointer to the TLS context
 * @param[in] message Incoming ServerKeyExchange message to parse
 * @param[in] length Message length
 * @return Error code
 **/

error_t tlsParseServerKeyExchange(TlsContext *context, const TlsServerKeyExchange *message, size_t length)
{
   error_t error;
   size_t n;
   size_t paramsLen;
   const uint8_t *p;
   const uint8_t *params;

   //Debug message
   TRACE_INFO("ServerKeyExchange message received (%" PRIuSIZE " bytes)...\r\n", length);
   TRACE_DEBUG_ARRAY("  ", message, length);

   //Check the length of the ServerKeyExchange message
   if(length < sizeof(TlsServerKeyExchange))
      return ERROR_DECODING_FAILED;

   //Check current state
   if(context->state != TLS_STATE_SERVER_KEY_EXCHANGE)
      return ERROR_UNEXPECTED_MESSAGE;

   //Update the hash value with the incoming handshake message
   tlsUpdateHandshakeHash(context, message, length);

   //Point to the body of the handshake message
   p = message->data;
   //Remaining bytes to process
   length -= sizeof(TlsServerKeyExchange);

   //PSK key exchange method?
   if(context->keyExchMethod == TLS_KEY_EXCH_PSK ||
      context->keyExchMethod == TLS_KEY_EXCH_RSA_PSK ||
      context->keyExchMethod == TLS_KEY_EXCH_DHE_PSK ||
      context->keyExchMethod == TLS_KEY_EXCH_ECDHE_PSK)
   {
      //To help the client in selecting which identity to use, the server
      //can provide a PSK identity hint in the ServerKeyExchange message
      error = tlsParsePskIdentityHint(context, p, length, &n);
      //Any error to report?
      if(error)
         return error;

      //Point to the next field
      p += n;
      //Remaining bytes to process
      length -= n;
   }

   //Diffie-Hellman or ECDH key exchange method?
   if(context->keyExchMethod == TLS_KEY_EXCH_DH_ANON ||
      context->keyExchMethod == TLS_KEY_EXCH_DHE_RSA ||
      context->keyExchMethod == TLS_KEY_EXCH_DHE_DSS ||
      context->keyExchMethod == TLS_KEY_EXCH_DHE_PSK ||
      context->keyExchMethod == TLS_KEY_EXCH_ECDH_ANON ||
      context->keyExchMethod == TLS_KEY_EXCH_ECDHE_RSA ||
      context->keyExchMethod == TLS_KEY_EXCH_ECDHE_ECDSA ||
      context->keyExchMethod == TLS_KEY_EXCH_ECDHE_PSK)
   {
      //Point to the server's key exchange parameters
      params = p;

      //Parse server's key exchange parameters
      error = tlsParseServerKeyParams(context, p, length, &paramsLen);
      //Any error to report?
      if(error)
         return error;

      //Point to the next field
      p += paramsLen;
      //Remaining bytes to process
      length -= paramsLen;
   }

   //Non-anonymous Diffie-Hellman and ECDH key exchange method?
   if(context->keyExchMethod == TLS_KEY_EXCH_DHE_RSA ||
      context->keyExchMethod == TLS_KEY_EXCH_DHE_DSS ||
      context->keyExchMethod == TLS_KEY_EXCH_ECDHE_RSA ||
      context->keyExchMethod == TLS_KEY_EXCH_ECDHE_ECDSA)
   {
      //For non-anonymous Diffie-Hellman and ECDH key exchanges, the signature
      //over the server's key exchange parameters shall be verified
      error = tlsVerifyServerKeySignature(context, p, length, params, paramsLen, &n);
      //Any error to report?
      if(error)
         return error;

      //Point to the next field
      p += n;
      //Remaining bytes to process
      length -= n;
   }

   //If the amount of data in the message does not precisely match the format
   //of the ServerKeyExchange message, then send a fatal alert
   if(length != 0)
      return ERROR_DECODING_FAILED;

   //Anomynous server?
   if(context->keyExchMethod == TLS_KEY_EXCH_PSK ||
      context->keyExchMethod == TLS_KEY_EXCH_DH_ANON ||
      context->keyExchMethod == TLS_KEY_EXCH_DHE_PSK ||
      context->keyExchMethod == TLS_KEY_EXCH_ECDH_ANON ||
      context->keyExchMethod == TLS_KEY_EXCH_ECDHE_PSK)
   {
      //An anonymous server cannot request client authentication
      context->state = TLS_STATE_SERVER_HELLO_DONE;
   }
   else
   {
      //A non-anonymous server can optionally request a certificate from
      //the client, if appropriate for the selected cipher suite
      context->state = TLS_STATE_CERTIFICATE_REQUEST;
   }

   //Successful processing
   return NO_ERROR;
}


/**
 * @brief Parse CertificateRequest message
 *
 * A server can optionally request a certificate from the client, if
 * appropriate for the selected cipher suite. This message will
 * immediately follow the ServerKeyExchange message
 *
 * @param[in] context Pointer to the TLS context
 * @param[in] message Incoming CertificateRequest message to parse
 * @param[in] length Message length
 * @return Error code
 **/

error_t tlsParseCertificateRequest(TlsContext *context, const TlsCertificateRequest *message, size_t length)
{
   uint_t i;
   size_t n;
   uint8_t *p;
   bool_t acceptable;
   TlsSignHashAlgos *supportedSignAlgos;
   TlsCertAuthorities *certAuthorities;

   //Debug message
   TRACE_INFO("CertificateRequest message received (%" PRIuSIZE " bytes)...\r\n", length);
   TRACE_DEBUG_ARRAY("  ", message, length);

   //Check the length of the ServerKeyExchange message
   if(length < sizeof(TlsCertificateRequest))
      return ERROR_DECODING_FAILED;

   //Check key exchange method
   if(context->keyExchMethod == TLS_KEY_EXCH_PSK ||
      context->keyExchMethod == TLS_KEY_EXCH_DH_ANON ||
      context->keyExchMethod == TLS_KEY_EXCH_DHE_PSK ||
      context->keyExchMethod == TLS_KEY_EXCH_ECDH_ANON ||
      context->keyExchMethod == TLS_KEY_EXCH_ECDHE_PSK)
   {
      //It is a fatal handshake failure alert for an anonymous
      //server to request client authentication
      return ERROR_HANDSHAKE_FAILED;
   }
   else if(context->keyExchMethod == TLS_KEY_EXCH_RSA_PSK)
   {
      //If no PSK identity hint is provided by the server, the
      //ServerKeyExchange message is omitted...
      if(context->state != TLS_STATE_SERVER_KEY_EXCHANGE &&
         context->state != TLS_STATE_CERTIFICATE_REQUEST)
      {
         //Handshake failure
         return ERROR_UNEXPECTED_MESSAGE;
      }
   }
   else
   {
      //Check current state
      if(context->state != TLS_STATE_CERTIFICATE_REQUEST)
         return ERROR_UNEXPECTED_MESSAGE;
   }

   //Update the hash value with the incoming handshake message
   tlsUpdateHandshakeHash(context, message, length);

   //The server requests a certificate from the client, so that
   //the connection can be mutually authenticated
   context->clientCertRequested = TRUE;

   //Point to the beginning of the message
   p = (uint8_t *) message;
   //Remaining bytes to process
   length -= sizeof(TlsCertificateRequest);

   //Retrieve the size of the list of supported certificate types
   n = message->certificateTypesLength;
   //Make sure the length field is valid
   if(n > length)
      return ERROR_DECODING_FAILED;

   //Point to the next field
   p += sizeof(TlsCertificateRequest) + n;
   //Remaining bytes to process
   length -= n;

#if (TLS_MAX_VERSION >= TLS_VERSION_1_2 && TLS_MIN_VERSION <= TLS_VERSION_1_2)
   //TLS 1.2 currently selected?
   if(context->version == TLS_VERSION_1_2)
   {
      //Malformed CertificateRequest message?
      if(length < sizeof(TlsSignHashAlgos))
         return ERROR_DECODING_FAILED;

      //Point to the list of the hash/signature algorithm pairs that
      //the server is able to verify
      supportedSignAlgos = (TlsSignHashAlgos *) p;
      //Remaining bytes to process
      length -= sizeof(TlsSignHashAlgos);

      //Get the size of the list
      n = ntohs(supportedSignAlgos->length);
      //Make sure the length field is valid
      if(n > length)
         return ERROR_DECODING_FAILED;

      //Point to the next field
      p += sizeof(TlsSignHashAlgos) + n;
      //Remaining bytes to process
      length -= n;
   }
   //SSL 3.0, TLS 1.0 or TLS 1.1 currently selected?
   else
#endif
   {
      //Implementations prior to TLS 1.2 do not include a
      //list of supported hash/signature algorithm pairs
      supportedSignAlgos = NULL;
   }

   //Malformed CertificateRequest message?
   if(length < sizeof(TlsCertAuthorities))
      return ERROR_DECODING_FAILED;

   //Point to the list of the distinguished names of acceptable
   //certificate authorities
   certAuthorities = (TlsCertAuthorities *) p;
   //Remaining bytes to process
   length -= sizeof(TlsCertAuthorities);

   //Get the size of the list
   n = ntohs(certAuthorities->length);
   //Make sure the length field is valid
   if(n > length)
      return ERROR_DECODING_FAILED;

   //No suitable certificate has been found for the moment
   context->cert = NULL;

   //Loop through the list of available certificates
   for(i = 0; i < context->numCerts; i++)
   {
      //Check whether the current certificate is suitable
      acceptable = tlsIsCertificateAcceptable(&context->certs[i],
         message->certificateTypes, message->certificateTypesLength,
         supportedSignAlgos, NULL, certAuthorities);

#if (TLS_MAX_VERSION >= TLS_VERSION_1_2 && TLS_MIN_VERSION <= TLS_VERSION_1_2)
      //TLS 1.2 requires additional examinations
      if(acceptable && context->version == TLS_VERSION_1_2)
      {
         //The hash and signature algorithms used in the signature of the CertificateVerify
         //message must be one of those present in the SupportedSignatureAlgorithms field
         if(tlsSelectSignHashAlgo(context, context->certs[i].signAlgo, supportedSignAlgos))
            acceptable = FALSE;
      }
#endif

      //If all the requirements were met, the certificate can be
      //used to authenticate the client
      if(acceptable)
      {
         context->cert = &context->certs[i];
         break;
      }
   }

   //Prepare to receive ServerHelloDone message...
   context->state = TLS_STATE_SERVER_HELLO_DONE;
   //Successful processing
   return NO_ERROR;
}


/**
 * @brief Parse ServerHelloDone message
 *
 * The ServerHelloDone message is sent by the server to indicate the
 * end of the ServerHello and associated messages. After sending this
 * message, the server will wait for a client response
 *
 * @param[in] context Pointer to the TLS context
 * @param[in] message Incoming ServerHelloDone message to parse
 * @param[in] length Message length
 * @return Error code
 **/

error_t tlsParseServerHelloDone(TlsContext *context, const TlsServerHelloDone *message, size_t length)
{
   //Debug message
   TRACE_INFO("ServerHelloDone message received (%" PRIuSIZE " bytes)...\r\n", length);
   TRACE_DEBUG_ARRAY("  ", message, length);

   //Check the length of the ServerHelloDone message
   if(length != sizeof(TlsServerHelloDone))
      return ERROR_DECODING_FAILED;

   //Check key exchange method
   if(context->keyExchMethod == TLS_KEY_EXCH_RSA ||
      context->keyExchMethod == TLS_KEY_EXCH_DHE_RSA ||
      context->keyExchMethod == TLS_KEY_EXCH_DHE_DSS ||
      context->keyExchMethod == TLS_KEY_EXCH_ECDHE_RSA ||
      context->keyExchMethod == TLS_KEY_EXCH_ECDHE_ECDSA)
   {
      //The server may omit the CertificateRequest message and go
      //directly to the ServerHelloDone message
      if(context->state != TLS_STATE_CERTIFICATE_REQUEST &&
         context->state != TLS_STATE_SERVER_HELLO_DONE)
      {
         //Handshake failure
         return ERROR_UNEXPECTED_MESSAGE;
      }
   }
   else if(context->keyExchMethod == TLS_KEY_EXCH_PSK)
   {
      //If no PSK identity hint is provided by the server, the
      //ServerKeyExchange message is omitted
      if(context->state != TLS_STATE_SERVER_KEY_EXCHANGE &&
         context->state != TLS_STATE_SERVER_HELLO_DONE)
      {
         //Handshake failure
         return ERROR_UNEXPECTED_MESSAGE;
      }
   }
   else if(context->keyExchMethod == TLS_KEY_EXCH_RSA_PSK)
   {
      //The server may omit the ServerKeyExchange message and/or
      //the CertificateRequest message
      if(context->state != TLS_STATE_SERVER_KEY_EXCHANGE &&
         context->state != TLS_STATE_CERTIFICATE_REQUEST &&
         context->state != TLS_STATE_SERVER_HELLO_DONE)
      {
         //Handshake failure
         return ERROR_UNEXPECTED_MESSAGE;
      }
   }
   else
   {
      //Check current state
      if(context->state != TLS_STATE_SERVER_HELLO_DONE)
         return ERROR_UNEXPECTED_MESSAGE;
   }

   //Update the hash value with the incoming handshake message
   tlsUpdateHandshakeHash(context, message, length);

   //Prepare to send client Certificate message...
   context->state = TLS_STATE_CLIENT_CERTIFICATE;
   //Successful processing
   return NO_ERROR;
}

#endif