Example #1
0
TlsContext *tlsInit(void)
{
   TlsContext *context;

   //Allocate a memory buffer to hold the TLS context
   context = osAllocMem(sizeof(TlsContext));
   //Failed to allocate memory
   if(!context) return NULL;

   //Clear TLS context
   memset(context, 0, sizeof(TlsContext));

   //Reference to the underlying socket
#if (TLS_BSD_SOCKET_SUPPORT == ENABLED)
   context->socket = -1;
#else
   context->socket = NULL;
#endif

   //Default operation mode
   context->entity = TLS_CONNECTION_END_CLIENT;
   //Default TLS version
   context->version = TLS_MIN_VERSION;
   //Default client authentication mode
   context->clientAuthMode = TLS_CLIENT_AUTH_NONE;

   //Initialize Diffie-Hellman context
   dhInit(&context->dhContext);
   //Initialize ECDH context
   ecdhInit(&context->ecdhContext);
   //Initialize peer's RSA public key
   rsaInitPublicKey(&context->peerRsaPublicKey);
   //Initialize peer's DSA public key
   dsaInitPublicKey(&context->peerDsaPublicKey);
   //Initialize peer's EC domain parameters
   ecInitDomainParameters(&context->peerEcParams);
   //Initialize peer's EC public key
   ecInit(&context->peerEcPublicKey);

   //Allocate send and receive buffers
   context->txBuffer = osAllocMem(TLS_TX_BUFFER_SIZE);
   context->rxBuffer = osAllocMem(TLS_RX_BUFFER_SIZE);
   //Failed to allocate memory?
   if(!context->txBuffer || !context->rxBuffer)
   {
      //Free previously allocated memory
      osFreeMem(context->txBuffer);
      osFreeMem(context->rxBuffer);
      osFreeMem(context);
      //Report an error
      return NULL;
   }

   //Clear send and receive buffers
   memset(context->txBuffer, 0, TLS_TX_BUFFER_SIZE);
   memset(context->rxBuffer, 0, TLS_RX_BUFFER_SIZE);

   //Return a handle to the freshly created TLS context
   return context;
}
Example #2
0
error_t udpDiscardStart(void)
{
   error_t error;
   DiscardServiceContext *context;
   OsTask *task;

   //Debug message
   TRACE_INFO("Starting UDP discard service...\r\n");

   //Allocate a memory block to hold the context
   context = osAllocMem(sizeof(DiscardServiceContext));
   //Failed to allocate memory?
   if(!context) return ERROR_OUT_OF_MEMORY;

   //Start of exception handling block
   do
   {
      //Open a UDP socket
      context->socket = socketOpen(SOCKET_TYPE_DGRAM, SOCKET_IP_PROTO_UDP);

      //Failed to open socket?
      if(!context->socket)
      {
         //Report an error
         error = ERROR_OPEN_FAILED;
         //Exit immediately
         break;
      }

      //The server listens for incoming datagrams on port 9
      error = socketBind(context->socket, &IP_ADDR_ANY, DISCARD_PORT);
      //Unable to bind the socket to the desired port?
      if(error) break;

      //Create a task to handle incoming datagrams
      task = osCreateTask("UDP Discard", udpDiscardTask,
         context, DISCARD_SERVICE_STACK_SIZE, DISCARD_SERVICE_PRIORITY);

      //Unable to create the task?
      if(task == OS_INVALID_HANDLE)
      {
         //Report an error to the calling function
         error = ERROR_OUT_OF_RESOURCES;
         break;
      }

      //End of exception handling block
   } while(0);

   //Any error to report?
   if(error)
   {
      //Clean up side effects...
      socketClose(context->socket);
      osFreeMem(context);
   }

   //Return status code
   return error;
}
Example #3
0
error_t tlsSetServerName(TlsContext *context, const char_t *serverName)
{
   size_t i;
   size_t length;

   //Invalid parameters?
   if(context == NULL || serverName == NULL)
      return ERROR_INVALID_PARAMETER;

   //Retrieve the length of the server name
   length = strlen(serverName);

   //Allocate a memory block to hold the hostname
   context->serverName = osAllocMem(length + 1);
   //Failed to allocate memory?
   if(!context->serverName) return ERROR_OUT_OF_MEMORY;

   //Convert the hostname into lowercase
   for(i = 0; i < length; i++)
      context->serverName[i] = tolower((uint8_t) serverName[i]);

   //Properly terminate the string with a NULL character
   context->serverName[length] = '\0';

   //Successful processing
   return NO_ERROR;
}
Example #4
0
/**************************************************************************************
 * Function:    AllocateBuffers
 *
 * Description: allocate all the memory needed for the MP3 decoder
 *
 * Inputs:      none
 *
 * Outputs:     none
 *
 * Return:      pointer to MP3DecInfo structure (initialized with pointers to all 
 *                the internal buffers needed for decoding, all other members of 
 *                MP3DecInfo structure set to 0)
 *
 * Notes:       if one or more mallocs fail, function frees any buffers already
 *                allocated before returning
 **************************************************************************************/
MP3DecInfo *AllocateBuffers(void)
{
	MP3DecInfo *mp3DecInfo;
	FrameHeader *fh;
	SideInfo *si;
	ScaleFactorInfo *sfi;
	HuffmanInfo *hi;
	DequantInfo *di;
	IMDCTInfo *mi;
	SubbandInfo *sbi;

	mp3DecInfo = (MP3DecInfo *)osAllocMem(sizeof(MP3DecInfo));
	if (!mp3DecInfo)
		return 0;
	ClearBuffer(mp3DecInfo, sizeof(MP3DecInfo));
	
	fh =  (FrameHeader *)     osAllocMem(sizeof(FrameHeader));
	si =  (SideInfo *)        osAllocMem(sizeof(SideInfo));
	sfi = (ScaleFactorInfo *) osAllocMem(sizeof(ScaleFactorInfo));
	hi =  (HuffmanInfo *)     osAllocMem(sizeof(HuffmanInfo));
	di =  (DequantInfo *)     osAllocMem(sizeof(DequantInfo));
	mi =  (IMDCTInfo *)       osAllocMem(sizeof(IMDCTInfo));
	sbi = (SubbandInfo *)     osAllocMem(sizeof(SubbandInfo));

	mp3DecInfo->FrameHeaderPS =     (void *)fh;
	mp3DecInfo->SideInfoPS =        (void *)si;
	mp3DecInfo->ScaleFactorInfoPS = (void *)sfi;
	mp3DecInfo->HuffmanInfoPS =     (void *)hi;
	mp3DecInfo->DequantInfoPS =     (void *)di;
	mp3DecInfo->IMDCTInfoPS =       (void *)mi;
	mp3DecInfo->SubbandInfoPS =     (void *)sbi;

	if (!fh || !si || !sfi || !hi || !di || !mi || !sbi) {
		FreeBuffers(mp3DecInfo);	/* safe to call - only frees memory that was successfully allocated */
		return 0;
	}

	/* important to do this - DSP primitives assume a bunch of state variables are 0 on first use */
	ClearBuffer(fh,  sizeof(FrameHeader));
	ClearBuffer(si,  sizeof(SideInfo));
	ClearBuffer(sfi, sizeof(ScaleFactorInfo));
	ClearBuffer(hi,  sizeof(HuffmanInfo));
	ClearBuffer(di,  sizeof(DequantInfo));
	ClearBuffer(mi,  sizeof(IMDCTInfo));
	ClearBuffer(sbi, sizeof(SubbandInfo));

	return mp3DecInfo;
}
error_t tlsParseChangeCipherSpec(TlsContext *context, const TlsChangeCipherSpec *message, size_t length)
{
   error_t error;

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

   //Check the length of the ChangeCipherSpec message
   if(length < sizeof(TlsChangeCipherSpec))
      return ERROR_DECODING_FAILED;

   //TLS operates as a client or a server?
   if(context->entity == TLS_CONNECTION_END_CLIENT)
   {
      //Check current state
      if(context->state != TLS_STATE_SERVER_CHANGE_CIPHER_SPEC)
         return ERROR_UNEXPECTED_MESSAGE;
   }
   else
   {
      //Check current state
      if(context->state != TLS_STATE_CLIENT_CHANGE_CIPHER_SPEC)
         return ERROR_UNEXPECTED_MESSAGE;
   }

   //Allocate a memory buffer to hold the decryption context
   context->readCipherContext = osAllocMem(context->cipherAlgo->contextSize);
   //Failed to allocate memory?
   if(!context->readCipherContext) return ERROR_OUT_OF_MEMORY;

   //Configure the decryption engine with the read key
   error = context->cipherAlgo->init(context->readCipherContext,
      context->readEncKey, context->encKeyLength);
   //Any error to report?
   if(error) return error;

   //Inform the record layer that subsequent records will be protected
   //under the newly negotiated encryption algorithm
   context->changeCipherSpecReceived = TRUE;

   //Prepare to receive a Finished message from the peer...
   context->state = (context->entity == TLS_CONNECTION_END_CLIENT) ?
      TLS_STATE_SERVER_FINISHED : TLS_STATE_CLIENT_FINISHED;

   //Successful processing
   return NO_ERROR;
}
error_t tlsSendChangeCipherSpec(TlsContext *context)
{
   error_t error;
   size_t length;
   TlsChangeCipherSpec *message;

   //Point to the ChangeCipherSpec message
   message = (TlsChangeCipherSpec *) (context->txBuffer + sizeof(TlsRecord));
   //Write the type field
   message->type = 1;

   //The message consists of a single byte
   length = sizeof(TlsChangeCipherSpec);

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

   //Send ChangeCipherSpec message
   error = tlsWriteProtocolData(context, length, TLS_TYPE_CHANGE_CIPHER_SPEC);
   //Failed to send TLS record?
   if(error) return error;

   //Allocate a memory buffer to hold the encryption context
   context->writeCipherContext = osAllocMem(context->cipherAlgo->contextSize);
   //Failed to allocate memory?
   if(!context->writeCipherContext) return ERROR_OUT_OF_MEMORY;

   //Configure the encryption engine with the write key
   error = context->cipherAlgo->init(context->writeCipherContext,
      context->writeEncKey, context->encKeyLength);
   //Initialization failed?
   if(error) return error;

   //Inform the record layer that subsequent records will be protected
   //under the newly negotiated encryption algorithm
   context->changeCipherSpecSent = TRUE;

   //Prepare to send a Finished message to the peer...
   context->state = (context->entity == TLS_CONNECTION_END_CLIENT) ?
      TLS_STATE_CLIENT_FINISHED : TLS_STATE_SERVER_FINISHED;

   //Successful processing
   return NO_ERROR;
}
Example #7
0
error_t whirlpoolCompute(const void *data, size_t length, uint8_t *digest)
{
   //Allocate a memory buffer to hold the Whirlpool context
   WhirlpoolContext *context = osAllocMem(sizeof(WhirlpoolContext));
   //Failed to allocate memory?
   if(!context) return ERROR_OUT_OF_MEMORY;

   //Initialize the Whirlpool context
   whirlpoolInit(context);
   //Digest the message
   whirlpoolUpdate(context, data, length);
   //Finalize the Whirlpool message digest
   whirlpoolFinal(context, digest);

   //Free previously allocated memory
   osFreeMem(context);
   //Successful processing
   return NO_ERROR;
}
Example #8
0
error_t sha512_224Compute(const void *data, size_t length, uint8_t *digest)
{
   //Allocate a memory buffer to hold the SHA-512/224 context
   Sha512_224Context *context = osAllocMem(sizeof(Sha512_224Context));
   //Failed to allocate memory?
   if(!context) return ERROR_OUT_OF_MEMORY;

   //Initialize the SHA-512/224 context
   sha512_224Init(context);
   //Digest the message
   sha512_224Update(context, data, length);
   //Finalize the SHA-512/224 message digest
   sha512_224Final(context, digest);

   //Free previously allocated memory
   osFreeMem(context);
   //Successful processing
   return NO_ERROR;
}
bool_t httpCheckPassword(HttpConnection *connection,
   const char_t *password, HttpAuthMode mode)
{
   //This flag tells whether the password is valid
   bool_t status = FALSE;

   //Debug message
   TRACE_DEBUG("Password verification...\r\n");

#if (HTTP_SERVER_BASIC_AUTH_SUPPORT == ENABLED)
   //Basic authentication scheme?
   if(mode == HTTP_AUTH_MODE_BASIC)
   {
      //Point to the authentication credentials
      HttpAuthorizationHeader *auth = &connection->request.auth;

      //Make sure authentication credentials have been found
      if(auth->found && auth->mode == HTTP_AUTH_MODE_BASIC)
      {
         //Sanity check
         if(auth->password != NULL)
         {
            //Check whether the password is valid
            if(!strcmp(password, auth->password))
               status = TRUE;
         }
      }
   }
#endif
#if (HTTP_SERVER_DIGEST_AUTH_SUPPORT == ENABLED)
   //Digest authentication scheme?
   if(mode == HTTP_AUTH_MODE_DIGEST)
   {
      //Point to the authentication credentials
      HttpAuthorizationHeader *auth = &connection->request.auth;

      //Make sure authentication credentials have been found
      if(auth->found && auth->mode == HTTP_AUTH_MODE_DIGEST)
      {
         //Sanity check
         if(auth->realm != NULL && auth->realm != NULL &&
            auth->nonce != NULL && auth->qop != NULL &&
            auth->nc != NULL && auth->cnonce != NULL &&
            auth->response != NULL)
         {
            error_t error;
            Md5Context *md5Context;
            char_t ha1[2 * MD5_DIGEST_SIZE + 1];
            char_t ha2[2 * MD5_DIGEST_SIZE + 1];

            //Allocate a memory buffer to hold the MD5 context
            md5Context = osAllocMem(sizeof(Md5Context));

            //MD5 context successfully allocated?
            if(md5Context != NULL)
            {
               //Compute HA1 = MD5(username : realm : password)
               md5Init(md5Context);
               md5Update(md5Context, auth->user, strlen(auth->user));
               md5Update(md5Context, ":", 1);
               md5Update(md5Context, auth->realm, strlen(auth->realm));
               md5Update(md5Context, ":", 1);
               md5Update(md5Context, password, strlen(password));
               md5Final(md5Context, NULL);

               //Convert MD5 hash to hex string
               httpConvertArrayToHexString(md5Context->digest, MD5_DIGEST_SIZE, ha1);
               //Debug message
               TRACE_DEBUG("  HA1: %s\r\n", ha1);

               //Compute HA2 = MD5(method : uri)
               md5Init(md5Context);
               md5Update(md5Context, connection->request.method, strlen(connection->request.method));
               md5Update(md5Context, ":", 1);
               md5Update(md5Context, auth->uri, strlen(auth->uri));
               md5Final(md5Context, NULL);

               //Convert MD5 hash to hex string
               httpConvertArrayToHexString(md5Context->digest, MD5_DIGEST_SIZE, ha2);
               //Debug message
               TRACE_DEBUG("  HA2: %s\r\n", ha2);

               //Compute MD5(HA1 : nonce : nc : cnonce : qop : HA1)
               md5Init(md5Context);
               md5Update(md5Context, ha1, strlen(ha1));
               md5Update(md5Context, ":", 1);
               md5Update(md5Context, auth->nonce, strlen(auth->nonce));
               md5Update(md5Context, ":", 1);
               md5Update(md5Context, auth->nc, strlen(auth->nc));
               md5Update(md5Context, ":", 1);
               md5Update(md5Context, auth->cnonce, strlen(auth->cnonce));
               md5Update(md5Context, ":", 1);
               md5Update(md5Context, auth->qop, strlen(auth->qop));
               md5Update(md5Context, ":", 1);
               md5Update(md5Context, ha2, strlen(ha2));
               md5Final(md5Context, NULL);

               //Convert MD5 hash to hex string
               httpConvertArrayToHexString(md5Context->digest, MD5_DIGEST_SIZE, ha1);
               //Debug message
               TRACE_DEBUG("  response: %s\r\n", ha1);

               //Release MD5 context
               osFreeMem(md5Context);

               //Check response
               if(!strcasecmp(auth->response, ha1))
               {
                  //Perform nonce verification
                  error = httpVerifyNonce(connection->serverContext, auth->nonce, auth->nc);

                  //Valid nonce?
                  if(!error)
                  {
                     //Access to the resource is granted
                     status = TRUE;
                  }
                  else
                  {
                     //The client may wish to simply retry the request with a
                     //new encrypted response, without re-prompting the user
                     //for a new username and password
                     connection->response.auth.stale = TRUE;
                  }
               }
            }
         }
      }
   }
#endif

   //Return TRUE is the password is valid, else FALSE
   return status;
}
Example #10
0
error_t ssiProcessIncludeCommand(HttpConnection *connection,
   const char_t *tag, size_t length, const char_t *uri, uint_t level)
{
   error_t error;
   char_t *separator;
   char_t *attribute;
   char_t *value;
   char_t *path;
   char_t *p;

   //Discard invalid SSI directives
   if(length < 7 || length >= HTTP_SERVER_BUFFER_SIZE)
      return ERROR_INVALID_TAG;

   //Skip the SSI include command (7 bytes)
   memcpy(connection->buffer, tag + 7, length - 7);
   //Ensure the resulting string is NULL-terminated
   connection->buffer[length - 7] = '\0';

   //Check whether a separator is present
   separator = strchr(connection->buffer, '=');
   //Separator not found?
   if(!separator)
      return ERROR_INVALID_TAG;

   //Split the tag
   *separator = '\0';

   //Get attribute name and value
   attribute = strTrimWhitespace(connection->buffer);
   value = strTrimWhitespace(separator + 1);

   //Remove leading simple or double quote
   if(value[0] == '\'' || value[0] == '\"')
      value++;

   //Get the length of the attribute value
   length = strlen(value);

   //Remove trailing simple or double quote
   if(length > 0)
   {
      if(value[length - 1] == '\'' || value[length - 1] == '\"')
         value[length - 1] = '\0';
   }

   //Check the length of the filename
   if(strlen(value) > HTTP_SERVER_URI_MAX_LEN)
      return ERROR_INVALID_TAG;

   //The file parameter defines the included file as relative to the document path
   if(!strcasecmp(attribute, "file"))
   {
      //Allocate a buffer to hold the path to the file to be included
      path = osAllocMem(strlen(uri) + strlen(value) + 1);
      //Failed to allocate memory?
      if(!path) return ERROR_OUT_OF_MEMORY;

      //Copy the path identifying the script file being processed
      strcpy(path, uri);
      //Search for the last slash character
      p = strrchr(path, '/');

      //Remove the filename from the path if applicable
      if(p)
         strcpy(p + 1, value);
      else
         strcpy(path, value);
   }
   //The virtual parameter defines the included file as relative to the document root
   else if(!strcasecmp(attribute, "virtual"))
   {
      //Copy the absolute path
      path = strDuplicate(value);
      //Failed to duplicate the string?
      if(!path) return ERROR_OUT_OF_MEMORY;
   }
   //Unknown parameter...
   else
   {
      //Report an error
      return ERROR_INVALID_TAG;
   }

   //Use server-side scripting to dynamically generate HTML code?
   if(httpCompExtension(value, ".stm") ||
      httpCompExtension(value, ".shtm") ||
      httpCompExtension(value, ".shtml"))
   {
      //SSI processing (Server Side Includes)
      error = ssiExecuteScript(connection, path, level + 1);
   }
   else
   {
#if (HTTP_SERVER_FS_SUPPORT == ENABLED)
      FsFile *file;

      //Retrieve the full pathname
      httpGetAbsolutePath(connection, path,
         connection->buffer, HTTP_SERVER_BUFFER_SIZE);

      //Open the file for reading
      file = fsOpenFile(connection->buffer, FS_FILE_MODE_READ);

      //Successful operation?
      if(file)
      {
         //Send the contents of the requested file
         while(1)
         {
            //Read data from the specified file
            error = fsReadFile(file, connection->buffer, HTTP_SERVER_BUFFER_SIZE, &length);
            //End of input stream?
            if(error) break;

            //Send data to the client
            error = httpWriteStream(connection, connection->buffer, length);
            //Any error to report?
            if(error) break;
         }

         //Close the file
         fsCloseFile(file);

         //Successful file transfer?
         if(error == ERROR_END_OF_STREAM)
            error = NO_ERROR;
      }
      else
      {
         //The specified URI cannot be found
         error = ERROR_NOT_FOUND;
      }
#else
      uint8_t *data;

      //Retrieve the full pathname
      httpGetAbsolutePath(connection, path,
         connection->buffer, HTTP_SERVER_BUFFER_SIZE);

      //Get the resource data associated with the file
      error = resGetData(connection->buffer, &data, &length);

      //Send the contents of the requested file
      if(!error)
         error = httpWriteStream(connection, data, length);
#endif
   }

   //Cannot found the specified resource?
   if(error == ERROR_NOT_FOUND)
      error = ERROR_INVALID_TAG;

   //Release previously allocated memory
   osFreeMem(path);
   //return status code
   return error;
}
Example #11
0
OsTask *osCreateTask(const char_t *name, OsTaskCode taskCode,
   void *params, size_t stackSize, int_t priority)
{
   OS_ERR err;
   CPU_INT32U i;
   CPU_STK stackLimit;
   OS_TCB *task;
   CPU_STK *stack;

   //The watermark limit is used to monitor and ensure that the stack does not overflow
   stackLimit = stackSize / 10;

   //Enter critical section
   osSuspendAllTasks();

   //Loop through TCB table
   for(i = 0; i < OS_PORT_MAX_TASKS; i++)
   {
      //Check whether the current entry is free
      if(tcbTable[i] == NULL)
         break;
   }

   //Any entry available in the table?
   if(i < OS_PORT_MAX_TASKS)
   {
      //Allocate a memory block to hold the task's control block
      task = osAllocMem(sizeof(OS_TCB));

      //Successful memory allocation?
      if(task != NULL)
      {
         //Allocate a memory block to hold the task's stack
         stack = osAllocMem(stackSize * sizeof(CPU_STK));

         //Successful memory allocation?
         if(stack != NULL)
         {
            //Create a new task
            OSTaskCreate(task, (CPU_CHAR *) name, taskCode, params,
               priority, stack, stackLimit, stackSize, 0, 1, NULL,
               OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR, &err);

            //Check the return value
            if(err == OS_ERR_NONE)
            {
               //Save TCB base address
               tcbTable[i] = task;
               //Save stack base address
               stkTable[i] = stack;
            }
            else
            {
               //Clean up side effects
               osFreeMem(task);
               osFreeMem(stack);
            }
         }
         else
         {
            //Memory allocation failed
            err = OS_ERR_MEM_FULL;
            //Clean up side effects
            osFreeMem(task);
         }
      }
      else
      {
         //Memory allocation failed
         err = OS_ERR_MEM_FULL;
      }
   }
   else
   {
      //No entry available in the table
      err = OS_ERR_MEM_FULL;
   }

   //Leave critical section
   osResumeAllTasks();

   //Check whether the task was successfully created
   if(err == OS_ERR_NONE)
      return task;
   else
      return NULL;
}
Example #12
0
error_t rsaesPkcs1v15Decrypt(const RsaPrivateKey *key, const uint8_t *ciphertext,
   size_t ciphertextLength, uint8_t *message, size_t messageSize, size_t *messageLength)
{
   error_t error;
   uint_t i;
   uint_t k;
   uint8_t *em;
   Mpi c;
   Mpi m;

   //Check parameters
   if(key == NULL || ciphertext == NULL)
      return ERROR_INVALID_PARAMETER;
   if(message == NULL || messageLength == NULL)
      return ERROR_INVALID_PARAMETER;

   //Debug message
   TRACE_DEBUG("RSA PKCS #1 v1.5 decryption...\r\n");
   TRACE_DEBUG("  Modulus:\r\n");
   TRACE_DEBUG_MPI("    ", &key->n);
   TRACE_DEBUG("  Public exponent:\r\n");
   TRACE_DEBUG_MPI("    ", &key->e);
   TRACE_DEBUG("  Private exponent:\r\n");
   TRACE_DEBUG_MPI("    ", &key->d);
   TRACE_DEBUG("  Prime 1:\r\n");
   TRACE_DEBUG_MPI("    ", &key->p);
   TRACE_DEBUG("  Prime 2:\r\n");
   TRACE_DEBUG_MPI("    ", &key->q);
   TRACE_DEBUG("  Prime exponent 1:\r\n");
   TRACE_DEBUG_MPI("    ", &key->dp);
   TRACE_DEBUG("  Prime exponent 2:\r\n");
   TRACE_DEBUG_MPI("    ", &key->dq);
   TRACE_DEBUG("  Coefficient:\r\n");
   TRACE_DEBUG_MPI("    ", &key->qinv);
   TRACE_DEBUG("  Ciphertext:\r\n");
   TRACE_DEBUG_ARRAY("    ", ciphertext, ciphertextLength);

   //Initialize multiple-precision integers
   mpiInit(&c);
   mpiInit(&m);

   //Get the length in octets of the modulus n
   k = mpiGetByteLength(&key->n);

   //Check the length of the ciphertext
   if(ciphertextLength != k || ciphertextLength < 11)
      return ERROR_INVALID_LENGTH;

   //Allocate a buffer to store the encoded message EM
   em = osAllocMem(k);
   //Failed to allocate memory?
   if(!em) return ERROR_OUT_OF_MEMORY;

   //Start of exception handling block
   do
   {
      //Convert the ciphertext to an integer ciphertext representative c
      error = mpiReadRaw(&c, ciphertext, ciphertextLength);
      //Conversion failed?
      if(error) break;

      //Apply the RSADP decryption primitive
      error = rsadp(key, &c, &m);
      //Any error to report?
      if(error) break;

      //Convert the message representative m to an encoded message EM of length k octets
      error = mpiWriteRaw(&m, em, k);
      //Conversion failed?
      if(error) break;

      //Debug message
      TRACE_DEBUG("  Encoded message\r\n");
      TRACE_DEBUG_ARRAY("    ", em, k);

      //The first octet of EM must have a value of 0x00
      //and the block type BT shall be 0x02
      if(em[0] != 0x00 || em[1] != 0x02)
      {
         //Report an error
         error = ERROR_UNEXPECTED_VALUE;
         break;
      }

      //An octet with hexadecimal value 0x00 is used to separate PS from M
      for(i = 2; i < k && em[i] != 0x00; i++);

      //Check whether the padding string is valid
      if(i < 10 || i >= k)
      {
         //Report an error
         error = ERROR_INVALID_PADDING;
         break;
      }

      //Ensure that the output buffer is large enough
      if(messageSize < (k - i - 1))
      {
         //Report an error
         error = ERROR_INVALID_LENGTH;
         break;
      }

      //Recover the length of the message
      *messageLength = k - i - 1;
      //Copy the message contents
      memcpy(message, em + i + 1, *messageLength);

      //Debug message
      TRACE_DEBUG("  Message:\r\n");
      TRACE_DEBUG_ARRAY("    ", message, *messageLength);

      //End of exception handling block
   } while(0);

   //Release multiple precision integers
   mpiFree(&c);
   mpiFree(&m);
   //Free previously allocated memory
   osFreeMem(em);

   //Return status code
   return error;
}
Example #13
0
error_t tlsAddCertificate(TlsContext *context, const char_t *certChain,
   size_t certChainLength, const char_t *privateKey, size_t privateKeyLength)
{
   error_t error;
   const char_t *p;
   size_t n;
   uint8_t *derCert;
   size_t derCertSize;
   size_t derCertLength;
   X509CertificateInfo *certInfo;
   TlsCertificateType certType;
   TlsSignatureAlgo certSignAlgo;
   TlsHashAlgo certHashAlgo;
   TlsEcNamedCurve namedCurve;

   //Invalid TLS context?
   if(context == NULL)
      return ERROR_INVALID_PARAMETER;

   //Check parameters
   if(certChain == NULL || certChainLength == 0)
      return ERROR_INVALID_PARAMETER;
   if(privateKey == NULL || privateKeyLength == 0)
      return ERROR_INVALID_PARAMETER;

   //Make sure there is enough room to add the certificate
   if(context->numCerts >= TLS_MAX_CERTIFICATES)
      return ERROR_OUT_OF_RESOURCES;

   //Allocate a memory buffer to store X.509 certificate info
   certInfo = osAllocMem(sizeof(X509CertificateInfo));
   //Failed to allocate memory?
   if(!certInfo) return ERROR_OUT_OF_MEMORY;

   //Point to the beginning of the certificate chain
   p = certChain;
   n = certChainLength;

   //DER encoded certificate
   derCert = NULL;
   derCertSize = 0;
   derCertLength = 0;

   //Start of exception handling block
   do
   {
      //Decode end entity certificate
      error = pemReadCertificate(&p, &n, &derCert, &derCertSize, &derCertLength);
      //Any error to report?
      if(error) break;

      //Parse X.509 certificate
      error = x509ParseCertificate(derCert, derCertLength, certInfo);
      //Failed to parse the X.509 certificate?
      if(error) break;

      //Retrieve the signature algorithm that has been used to sign the certificate
      error = tlsGetCertificateType(certInfo, &certType,
         &certSignAlgo, &certHashAlgo, &namedCurve);
      //The specified signature algorithm is not supported?
      if(error) break;

      //End of exception handling block
   } while(0);

   //Check whether the certificate is acceptable
   if(!error)
   {
      //Point to the structure that describes the certificate
      TlsCertDesc *cert = &context->certs[context->numCerts];

      //Save the certificate chain and the corresponding private key
      cert->certChain = certChain;
      cert->certChainLength = certChainLength;
      cert->privateKey = privateKey;
      cert->privateKeyLength = privateKeyLength;
      cert->type = certType;
      cert->signAlgo = certSignAlgo;
      cert->hashAlgo = certHashAlgo;
      cert->namedCurve = namedCurve;

      //Update the number of certificates
      context->numCerts++;
   }

   //Release previously allocated memory
   osFreeMem(derCert);
   osFreeMem(certInfo);

   //Return status code
   return error;
}
Example #14
0
error_t ping(NetInterface *interface, const IpAddr *ipAddr,
   size_t size, uint8_t ttl, systime_t timeout, systime_t *rtt)
{
   error_t error;
   uint_t i;
   size_t length;
   uint16_t identifier;
   uint16_t sequenceNumber;
   systime_t startTime;
   systime_t roundTripTime;
   Socket *socket;
   IcmpEchoMessage *message;

   //Limit the size of the ping request
   size = MIN (size, PING_MAX_DATA_SIZE);

   //Debug message
   TRACE_INFO("Pinging %s with %u bytes of data...\r\n",
      ipAddrToString(ipAddr, NULL), size);

   //Length of the complete ICMP message including header and data
   length = sizeof(IcmpEchoMessage) + size;

   //Allocate memory buffer to hold an ICMP message
   message = osAllocMem(length);
   //Failed to allocate memory?
   if(!message) return ERROR_OUT_OF_MEMORY;

   //Identifier field is used to help matching requests and replies
   identifier = netGetRand();
   //Sequence Number field is increment each time an Echo Request is sent
   sequenceNumber = osAtomicInc16(&pingSequenceNumber);

   //Format ICMP Echo Request message
   message->type = ICMP_TYPE_ECHO_REQUEST;
   message->code = 0;
   message->checksum = 0;
   message->identifier = identifier;
   message->sequenceNumber = sequenceNumber;

   //Copy data
   for(i = 0; i < size; i++)
      message->data[i] = i & 0xFF;

#if (IPV4_SUPPORT == ENABLED)
   //Target address is an IPv4 address?
   if(ipAddr->length == sizeof(Ipv4Addr))
   {
      Ipv4Addr srcIpAddr;

      //Select the source IPv4 address and the relevant network
      //interface to use when pinging the specified host
      error = ipv4SelectSourceAddr(&interface, ipAddr->ipv4Addr, &srcIpAddr);

      //Any error to report?
      if(error)
      {
         //Free previously allocated memory
         osFreeMem(message);
         //Return the corresponding error code
         return error;
      }

      //ICMP Echo Request message
      message->type = ICMP_TYPE_ECHO_REQUEST;
      //Message checksum calculation
      message->checksum = ipCalcChecksum(message, length);

      //Open a raw socket
      socket = socketOpen(SOCKET_TYPE_RAW_IP, SOCKET_IP_PROTO_ICMP);
   }
   else
#endif
#if (IPV6_SUPPORT == ENABLED)
   //Target address is an IPv6 address?
   if(ipAddr->length == sizeof(Ipv6Addr))
   {
      Ipv6PseudoHeader pseudoHeader;

      //Select the source IPv6 address and the relevant network
      //interface to use when pinging the specified host
      error = ipv6SelectSourceAddr(&interface, &ipAddr->ipv6Addr, &pseudoHeader.srcAddr);

      //Any error to report?
      if(error)
      {
         //Free previously allocated memory
         osFreeMem(message);
         //Return the corresponding error code
         return error;
      }

      //ICMPv6 Echo Request message
      message->type = ICMPV6_TYPE_ECHO_REQUEST;
      //Format IPv6 pseudo header
      pseudoHeader.destAddr = ipAddr->ipv6Addr;
      pseudoHeader.length = htonl(length);
      pseudoHeader.reserved = 0;
      pseudoHeader.nextHeader = IPV6_ICMPV6_HEADER;

      //Message checksum calculation
      message->checksum = ipCalcUpperLayerChecksum(
         &pseudoHeader, sizeof(Ipv6PseudoHeader), message, length);

      //Open a raw socket
      socket = socketOpen(SOCKET_TYPE_RAW_IP, SOCKET_IP_PROTO_ICMPV6);
   }
   else
#endif
   //Target address is not valid?
   {
      //Free previously allocated memory
      osFreeMem(message);
      //Report an error
      return ERROR_INVALID_ADDRESS;
   }

   //Failed to open socket?
   if(!socket)
   {
      //Free previously allocated memory
      osFreeMem(message);
      //Report an error
      return ERROR_OPEN_FAILED;
   }

   //Set the TTL value to be used
   socket->ttl = ttl;

   //Associate the newly created socket with the relevant interface
   error = socketBindToInterface(socket, interface);

   //Unable to bind the socket to the desired interface?
   if(error)
   {
      //Free previously allocated memory
      osFreeMem(message);
      //Close socket
      socketClose(socket);
      //Return status code
      return error;
   }

   //Connect the socket to the target host
   error = socketConnect(socket, ipAddr, 0);

   //Any error to report?
   if(error)
   {
      //Free previously allocated memory
      osFreeMem(message);
      //Close socket
      socketClose(socket);
      //Return status code
      return error;
   }

   //Send Echo Request message
   error = socketSend(socket, message, length, NULL, 0);

   //Failed to send message ?
   if(error)
   {
      //Free previously allocated memory
      osFreeMem(message);
      //Close socket
      socketClose(socket);
      //Return status code
      return error;
   }

   //Save the time at which the request was sent
   startTime = osGetSystemTime();

   //Timeout value exceeded?
   while((osGetSystemTime() - startTime) < timeout)
   {
      //Adjust receive timeout
      error = socketSetTimeout(socket, timeout);
      //Any error to report?
      if(error) break;

      //Wait for an incoming ICMP message
      error = socketReceive(socket, message,
         sizeof(IcmpEchoMessage) + size, &length, 0);
      //Any error to report?
      if(error) break;

      //Check message length
      if(length != (sizeof(IcmpEchoMessage) + size))
         continue;
      //Verify message type
      if(ipAddr->length == sizeof(Ipv4Addr) && message->type != ICMP_TYPE_ECHO_REPLY)
         continue;
      if(ipAddr->length == sizeof(Ipv6Addr) && message->type != ICMPV6_TYPE_ECHO_REPLY)
         continue;
      //Response identifier matches request identifier?
      if(message->identifier != identifier)
         continue;
      //Make sure the sequence number is correct
      if(message->sequenceNumber != sequenceNumber)
         continue;

      //Loop through data field
      for(i = 0; i < size; i++)
      {
         //Compare received data against expected data
         if(message->data[i] != (i & 0xFF)) break;
      }

      //Valid Echo Reply message received?
      if(i == size)
      {
         //Calculate round-trip time
         roundTripTime = osGetSystemTime() - startTime;
         //Debug message
         TRACE_INFO("Echo received (round-trip time = %" PRIu32 " ms)...\r\n", roundTripTime);

         //Free previously allocated memory
         osFreeMem(message);
         //Close socket
         socketClose(socket);

         //Return round-trip time
         if(rtt != NULL)
            *rtt = roundTripTime;

         //No error to report
         return NO_ERROR;
      }
   }

   //Debug message
   TRACE_INFO("No echo received!\r\n");
   //Free previously allocated memory
   osFreeMem(message);
   //Close socket
   socketClose(socket);

   //No Echo Reply received from host...
   return ERROR_NO_RESPONSE;
}
Example #15
0
error_t ssiExecuteScript(HttpConnection *connection, const char_t *uri, uint_t level)
{
   error_t error;
   size_t length;

#if (HTTP_SERVER_FS_SUPPORT == ENABLED)
   bool_t more;
   uint_t pos;
   uint_t n;
   char_t *buffer;
   FsFile *file;
#else
   uint_t i;
   uint_t j;
   char_t *data;
#endif

   //Recursion limit exceeded?
   if(level >= HTTP_SERVER_SSI_MAX_RECURSION)
      return NO_ERROR;

   //Retrieve the full pathname
   httpGetAbsolutePath(connection, uri,
      connection->buffer, HTTP_SERVER_BUFFER_SIZE);

#if (HTTP_SERVER_FS_SUPPORT == ENABLED)
   //Open the file for reading
   file = fsOpenFile(connection->buffer, FS_FILE_MODE_READ);
   //Failed to open the file?
   if(!file) return ERROR_NOT_FOUND;

   //Allocate a memory buffer
   buffer = osAllocMem(HTTP_SERVER_BUFFER_SIZE);
   //Failed to allocate memory?
   if(!buffer)
   {
      //Close the file
      fsCloseFile(file);
      //Report an error
      return ERROR_OUT_OF_MEMORY;
   }
#else
   //Get the resource data associated with the URI
   error = resGetData(connection->buffer, (uint8_t **) &data, &length);
   //The specified URI cannot be found?
   if(error) return error;
#endif

   //Send the HTTP response header before executing the script
   if(!level)
   {
      //Format HTTP response header
      connection->response.statusCode = 200;
      connection->response.contentType = mimeGetType(uri);
      connection->response.chunkedEncoding = TRUE;

      //Send the header to the client
      error = httpWriteHeader(connection);
      //Any error to report?
      if(error)
      {
#if (HTTP_SERVER_FS_SUPPORT == ENABLED)
         //Close the file
         fsCloseFile(file);
         //Release memory buffer
         osFreeMem(buffer);
#endif
         //Return status code
         return error;
      }
   }

#if (HTTP_SERVER_FS_SUPPORT == ENABLED)
   //Point to the beginning of the buffer
   pos = 0;
   length = 0;

   //This flag indicates whether data should be read
   more = TRUE;

   //Parse the specified file
   while(1)
   {
      //Read more data if needed
      if(more)
      {
         //Read data from the specified file
         error = fsReadFile(file, buffer + pos + length,
            HTTP_SERVER_BUFFER_SIZE - (pos + length), &n);

         //End of input stream?
         if(error)
         {
            //Purge data buffer
            error = httpWriteStream(connection, buffer + pos, length);
            //Exit immediately
            break;
         }

         //Adjust the length of the buffer
         length += n;
         //Clear flag
         more = FALSE;
      }

      //Search for any SSI tags
      error = ssiSearchTag(buffer + pos, length, "<!--#", 5, &n);

      //Full match?
      if(error == NO_ERROR)
      {
         //Send the part of the file that precedes the tag
         error = httpWriteStream(connection, buffer + pos, n);
         //Failed to send data?
         if(error) break;

         //Advance data pointer
         pos += n;
         length -= n;

         //Search for the comment terminator
         error = ssiSearchTag(buffer + pos + 5, length - 5, "-->", 3, &n);

         //Full match?
         if(error == NO_ERROR)
         {
            //Advance data pointer over the opening identifier
            pos += 5;
            length -= 5;

            //Process SSI directive
            error = ssiProcessCommand(connection, buffer + pos, n, uri, level);
            //Any error to report?
            if(error) break;

            //Advance data pointer over the SSI tag
            pos += n + 3;
            length -= n + 3;
         }
         //No match or partial match?
         else
         {
            if(pos > 0)
            {
               //Move the remaining bytes to the start of the buffer
               memmove(buffer, buffer + pos, length);
               //Rewind to the beginning of the buffer
               pos = 0;
               //More data are needed
               more = TRUE;
            }
            else
            {
               //Send data to the client
               error = httpWriteStream(connection, buffer + pos, length);
               //Any error to report?
               if(error) break;

               //Rewind to the beginning of the buffer
               pos = 0;
               length = 0;
               //More data are needed
               more = TRUE;
            }
         }
      }
      //Partial match?
      else if(error == ERROR_PARTIAL_MATCH)
      {
         //Send the part of the file that precedes the tag
         error = httpWriteStream(connection, buffer + pos, n);
         //Failed to send data?
         if(error) break;

         //Advance data pointer
         pos += n;
         length -= n;

         //Move the remaining bytes to the start of the buffer
         memmove(buffer, buffer + pos, length);
         //Rewind to the beginning of the buffer
         pos = 0;
         //More data are needed
         more = TRUE;
      }
      //No match?
      else
      {
         //Send data to the client
         error = httpWriteStream(connection, buffer + pos, length);
         //Any error to report?
         if(error) break;

         //Rewind to the beginning of the buffer
         pos = 0;
         length = 0;
         //More data are needed
         more = TRUE;
      }
   }

   //Close the file
   fsCloseFile(file);
   //Release memory buffer
   osFreeMem(buffer);

   //Properly close the output stream
   if(!level && error == NO_ERROR)
      error = httpCloseStream(connection);
#else
   //Parse the specified file
   while(length > 0)
   {
      //Search for any SSI tags
      error = ssiSearchTag(data, length, "<!--#", 5, &i);

      //Opening identifier found?
      if(!error)
      {
         //Search for the comment terminator
         error = ssiSearchTag(data + i + 5, length - i - 5, "-->", 3, &j);
      }

      //Check whether a valid SSI tag has been found?
      if(!error)
      {
         //Send the part of the file that precedes the tag
         error = httpWriteStream(connection, data, i);
         //Failed to send data?
         if(error) return error;

         //Advance data pointer over the opening identifier
         data += i + 5;
         length -= i + 5;

         //Process SSI directive
         error = ssiProcessCommand(connection, data, j, uri, level);
         //Any error to report?
         if(error) return error;

         //Advance data pointer over the SSI tag
         data += j + 3;
         length -= j + 3;
      }
      else
      {
         //Send the rest of the file
         error = httpWriteStream(connection, data, length);
         //Failed to send data?
         if(error) return error;
         //Advance data pointer
         data += length;
         length = 0;
      }
   }

   //Properly close the output stream
   if(!level)
      error = httpCloseStream(connection);
#endif

   //Return status code
   return error;
}
Example #16
0
error_t tlsParseCertificate(TlsContext *context, const TlsCertificate *message, size_t length)
{
   error_t error;
   const uint8_t *p;
   size_t n;
   const char_t *pemCert;
   size_t pemCertLength;
   uint8_t *derCert;
   size_t derCertSize;
   size_t derCertLength;

   //X.509 certificates
   X509CertificateInfo *certInfo = NULL;
   X509CertificateInfo *issuerCertInfo = NULL;

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

   //Check the length of the Certificate message
   if(length < sizeof(TlsCertificate))
      return ERROR_DECODING_FAILED;

   //TLS operates as a client or a server?
   if(context->entity == TLS_CONNECTION_END_CLIENT)
   {
      //Check current state
      if(context->state != TLS_STATE_SERVER_CERTIFICATE)
         return ERROR_UNEXPECTED_MESSAGE;
   }
   else
   {
      //Check current state
      if(context->state != TLS_STATE_CLIENT_CERTIFICATE)
         return ERROR_UNEXPECTED_MESSAGE;
   }

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

   //Get the size occupied by the certificate list
   n = LOAD24BE(message->certificateListLength);
   //Remaining bytes to process
   length -= sizeof(TlsCertificate);

   //Ensure that the chain of certificates is valid
   if(n > length)
      return ERROR_DECODING_FAILED;

   //Compute the length of the certificate list
   length = n;

   //The sender's certificate must come first in the list
   p = message->certificateList;

   //Start of exception handling block
   do
   {
      //Assume an error...
      error = ERROR_OUT_OF_MEMORY;

      //Allocate a memory buffer to store X.509 certificate info
      certInfo = osAllocMem(sizeof(X509CertificateInfo));
      //Failed to allocate memory?
      if(!certInfo) break;

      //Allocate a memory buffer to store the parent certificate
      issuerCertInfo = osAllocMem(sizeof(X509CertificateInfo));
      //Failed to allocate memory?
      if(!issuerCertInfo) break;

      //TLS operates as a server?
      if(context->entity == TLS_CONNECTION_END_SERVER)
      {
         //Empty certificate list?
         if(!length)
         {
            //Check whether mutual authentication is required
            if(context->clientAuthMode == TLS_CLIENT_AUTH_REQUIRED)
            {
               //If client authentication is required by the server for the handshake
               //to continue, it may respond with a fatal handshake failure alert
               error = ERROR_HANDSHAKE_FAILED;
               break;
            }
            else
            {
               //Client authentication is optional
               context->peerCertType = TLS_CERT_NONE;
               //Exit immediately
               error = NO_ERROR;
               break;
            }
         }
      }

      //Each certificate is preceded by a 3-byte length field
      if(length < 3)
      {
         //Report an error
         error = ERROR_DECODING_FAILED;
         break;
      }

      //Get the size occupied by the certificate
      n = LOAD24BE(p);
      //Jump to the beginning of the DER encoded certificate
      p += 3;
      length -= 3;

      //Make sure that the certificate is valid
      if(n > length)
      {
         //Report an error
         error = ERROR_DECODING_FAILED;
         break;
      }

      //Display ASN.1 structure
      error = asn1DumpObject(p, n, 0);
      //Any error to report?
      if(error) break;

      //Parse X.509 certificate
      error = x509ParseCertificate(p, n, certInfo);
      //Failed to parse the X.509 certificate?
      if(error) break;

#if (TLS_CLIENT_SUPPORT == ENABLED)
      //TLS operates as a client?
      if(context->entity == TLS_CONNECTION_END_CLIENT)
      {
         //Check if the hostname must be verified
         if(context->serverName != NULL)
         {
            //Point to the last character of the common name
            int_t i = certInfo->subject.commonNameLen - 1;
            //Point to the last character of the hostname
            int_t j = strlen(context->serverName) - 1;

            //Check the common name in the server certificate against
            //the actual hostname that is being requested
            while(i >= 0 && j >= 0)
            {
               //Wildcard certificate found?
               if(certInfo->subject.commonName[i] == '*' && i == 0)
               {
                  //The CN is acceptable
                  j = 0;
               }
               //Perform case insensitive character comparison
               else if(tolower((uint8_t) certInfo->subject.commonName[i]) != context->serverName[j])
               {
                  break;
               }

               //Compare previous characters
               i--;
               j--;
            }

            //If the host names do not match, reject the certificate
            if(i >= 0 || j >= 0)
            {
               //Debug message
               TRACE_WARNING("Server name mismatch!\r\n");
               //Report an error
               error = ERROR_BAD_CERTIFICATE;
               break;
            }
         }
      }
#endif

      //The certificate contains a valid RSA public key?
      if(!oidComp(certInfo->subjectPublicKeyInfo.oid, certInfo->subjectPublicKeyInfo.oidLen,
         RSA_ENCRYPTION_OID, sizeof(RSA_ENCRYPTION_OID)))
      {
         //Retrieve the RSA public key
         error = x509ReadRsaPublicKey(certInfo, &context->peerRsaPublicKey);
         //Any error to report
         if(error) break;

         //Save the certificate type
         context->peerCertType = TLS_CERT_RSA_SIGN;
      }
      //The certificate contains a valid DSA public key?
      else if(!oidComp(certInfo->subjectPublicKeyInfo.oid, certInfo->subjectPublicKeyInfo.oidLen,
         DSA_OID, sizeof(DSA_OID)))
      {
         //Retrieve the DSA public key
         error = x509ReadDsaPublicKey(certInfo, &context->peerDsaPublicKey);
         //Any error to report
         if(error) break;

         //Save the certificate type
         context->peerCertType = TLS_CERT_DSS_SIGN;
      }
      //The certificate contains a valid EC public key?
      else if(!oidComp(certInfo->subjectPublicKeyInfo.oid, certInfo->subjectPublicKeyInfo.oidLen,
         EC_PUBLIC_KEY_OID, sizeof(EC_PUBLIC_KEY_OID)))
      {
         const EcCurveInfo *curveInfo;

         //Retrieve EC domain parameters
         curveInfo = ecGetCurveInfo(certInfo->subjectPublicKeyInfo.ecParams.namedCurve,
            certInfo->subjectPublicKeyInfo.ecParams.namedCurveLen);

         //Make sure the specified elliptic curve is supported
         if(curveInfo == NULL)
         {
            //Report an error
            error = ERROR_BAD_CERTIFICATE;
            //Exit immediately
            break;
         }

         //Load EC domain parameters
         error = ecLoadDomainParameters(&context->peerEcParams, curveInfo);
         //Any error to report?
         if(error) break;

         //Retrieve the EC public key
         error = ecImport(&context->peerEcParams, &context->peerEcPublicKey,
            certInfo->subjectPublicKeyInfo.ecPublicKey.q, certInfo->subjectPublicKeyInfo.ecPublicKey.qLen);
         //Any error to report
         if(error) break;

         //Save the certificate type
         context->peerCertType = TLS_CERT_ECDSA_SIGN;
      }
      //The certificate does not contain any valid public key?
      else
      {
         //Report an error
         error = ERROR_BAD_CERTIFICATE;
         break;
      }

      //Next certificate
      p += n;
      length -= n;

      //PKIX path validation
      while(length > 0)
      {
         //Each certificate is preceded by a 3-byte length field
         if(length < 3)
         {
            //Report an error
            error = ERROR_DECODING_FAILED;
            break;
         }

         //Get the size occupied by the certificate
         n = LOAD24BE(p);
         //Jump to the beginning of the DER encoded certificate
         p += 3;
         length -= 3;

         //Ensure that the certificate is valid
         if(n > length)
         {
            //Report an error
            error = ERROR_DECODING_FAILED;
            break;
         }

         //Display ASN.1 structure
         error = asn1DumpObject(p, n, 0);
         //Any error to report?
         if(error) break;

         //Parse X.509 certificate
         error = x509ParseCertificate(p, n, issuerCertInfo);
         //Failed to parse the X.509 certificate?
         if(error) break;

         //Validate current certificate
         error = x509ValidateCertificate(certInfo, issuerCertInfo);
         //Certificate validation failed?
         if(error) break;

         //Keep track of the issuer certificate
         memcpy(certInfo, issuerCertInfo, sizeof(X509CertificateInfo));

         //Next certificate
         p += n;
         length -= n;
      }

      //Propagate exception if necessary...
      if(error) break;

      //Point to the first trusted CA certificate
      pemCert = context->trustedCaList;
      //Get the total length, in bytes, of the trusted CA list
      pemCertLength = context->trustedCaListLength;

      //DER encoded certificate
      derCert = NULL;
      derCertSize = 0;
      derCertLength = 0;

      //Loop through the list
      while(pemCertLength > 0)
      {
         //Decode PEM certificate
         error = pemReadCertificate(&pemCert, &pemCertLength,
            &derCert, &derCertSize, &derCertLength);
         //Any error to report?
         if(error) break;

         //Parse X.509 certificate
         error = x509ParseCertificate(derCert, derCertLength, issuerCertInfo);
         //Failed to parse the X.509 certificate?
         if(error) break;

         //Validate the certificate with the current trusted CA
         error = x509ValidateCertificate(certInfo, issuerCertInfo);
         //Certificate validation succeeded?
         if(!error) break;
      }

      //The certificate could not be matched with a known, trusted CA?
      if(error == ERROR_END_OF_FILE)
         error = ERROR_UNKNOWN_CA;

      //Free previously allocated memory
      osFreeMem(derCert);

      //End of exception handling block
   } while(0);

   //Free previously allocated memory
   osFreeMem(certInfo);
   osFreeMem(issuerCertInfo);

   //Clean up side effects
   if(error)
   {
      //Release previously allocated memory
      rsaFreePublicKey(&context->peerRsaPublicKey);
      dsaFreePublicKey(&context->peerDsaPublicKey);
      ecFreeDomainParameters(&context->peerEcParams);
      ecFree(&context->peerEcPublicKey);
   }

   //TLS operates as a client or a server?
   if(context->entity == TLS_CONNECTION_END_CLIENT)
   {
      //Update FSM state
      if(context->keyExchMethod != TLS_KEY_EXCH_RSA)
         context->state = TLS_STATE_SERVER_KEY_EXCHANGE;
      else
         context->state = TLS_STATE_CERTIFICATE_REQUEST;
   }
   else
   {
      //Prepare to receive ClientKeyExchange message...
      context->state = TLS_STATE_CLIENT_KEY_EXCHANGE;
   }

   //Return status code
   return error;
}
Example #17
0
void tcpEchoListenerTask(void *param)
{
   error_t error;
   uint16_t clientPort;
   IpAddr clientIpAddr;
   Socket *serverSocket;
   Socket *clientSocket;
   EchoServiceContext *context;
   OsTask *task;

   //Point to the listening socket
   serverSocket = (Socket *) param;

   //Main loop
   while(1)
   {
      //Accept an incoming connection
      clientSocket = socketAccept(serverSocket, &clientIpAddr, &clientPort);
      //Check whether a valid connection request has been received
      if(!clientSocket) continue;

      //Debug message
      TRACE_INFO("Echo service: connection established with client %s port %" PRIu16 "\r\n",
         ipAddrToString(&clientIpAddr, NULL), clientPort);

      //The socket operates in non-blocking mode
      error = socketSetTimeout(clientSocket, 0);

      //Any error to report?
      if(error)
      {
         //Close socket
         socketClose(clientSocket);
         //Wait for an incoming connection attempt
         continue;
      }

      //Allocate resources for the new connection
      context = osAllocMem(sizeof(EchoServiceContext));

      //Failed to allocate memory?
      if(!context)
      {
         //Close socket
         socketClose(clientSocket);
         //Wait for an incoming connection attempt
         continue;
      }

      //Record the handle of the newly created socket
      context->socket = clientSocket;

      //Create a task to service the current connection
      task = osCreateTask("TCP Echo Connection", tcpEchoConnectionTask,
         context, ECHO_SERVICE_STACK_SIZE, ECHO_SERVICE_PRIORITY);

      //Did we encounter an error?
      if(task == OS_INVALID_HANDLE)
      {
         //Close socket
         socketClose(clientSocket);
         //Release resources
         osFreeMem(context);
      }
   }
}
Example #18
0
OsTask *osCreateTask(const char_t *name, OsTaskCode taskCode,
   void *params, size_t stackSize, int_t priority)
{
   uint_t i;
   void *wa;
   OsTask *task = NULL;

   //Compute the size of the stack in bytes
   stackSize *= sizeof(uint_t);

   //Allocate a memory block to hold the working area
   wa = osAllocMem(THD_WA_SIZE(stackSize));

   //Successful memory allocation?
   if(wa != NULL)
   {
      //Enter critical section
      chSysLock();

      //Loop through task table
      for(i = 0; i < OS_PORT_MAX_TASKS; i++)
      {
         //Check whether the current entry is free
         if(taskTable[i].tp == NULL)
            break;
      }

      //Any entry available in the table?
      if(i < OS_PORT_MAX_TASKS)
      {
         //Create a new task
         taskTable[i].tp = chThdCreateI(wa, THD_WA_SIZE(stackSize),
            priority, (tfunc_t) taskCode, params);

         //Check whether the task was successfully created
         if(taskTable[i].tp != NULL)
         {
            //Insert the newly created task in the ready list
            chSchWakeupS(taskTable[i].tp, RDY_OK);

            //Save task pointer
            task = &taskTable[i];
            //Save working area base address
            waTable[i] = wa;

            //Leave critical section
            chSysUnlock();
         }
         else
         {
            //Leave critical section
            chSysUnlock();
            //Clean up side effects
            osFreeMem(wa);
         }
      }
      else
      {
         //Leave critical section
         chSysUnlock();
         //No entry available in the table
         osFreeMem(wa);
      }
   }

   //Return a pointer to the newly created task
   return task;
}
error_t smtpSendMail(const SmtpAuthInfo *authInfo, const SmtpMail *mail)
{
   error_t error;
   uint_t i;
   uint_t replyCode;
   IpAddr serverIpAddr;
   SmtpClientContext *context;

   //Check parameters
   if(!authInfo || !mail)
      return ERROR_INVALID_PARAMETER;
   //Make sure the server name is valid
   if(!authInfo->serverName)
      return ERROR_INVALID_PARAMETER;

   //Debug message
   TRACE_INFO("Sending a mail to %s port %" PRIu16 "...\r\n",
      authInfo->serverName, authInfo->serverPort);

   //The specified SMTP server can be either an IP or a host name
   error = getHostByName(authInfo->interface,
      authInfo->serverName, &serverIpAddr, 0);
   //Unable to resolve server name?
   if(error)
      return ERROR_NAME_RESOLUTION_FAILED;

   //Allocate a memory buffer to hold the SMTP client context
   context = osAllocMem(sizeof(SmtpClientContext));
   //Failed to allocate memory?
   if(!context)
      return ERROR_OUT_OF_MEMORY;

   //Open a TCP socket
   context->socket = socketOpen(SOCKET_TYPE_STREAM, SOCKET_IP_PROTO_TCP);
   //Failed to open socket?
   if(!context->socket)
   {
      //Free previously allocated resources
      osFreeMem(context);
      //Report an error
      return ERROR_OPEN_FAILED;
   }

#if (SMTP_TLS_SUPPORT == ENABLED)
   //Do not use SSL/TLS for the moment
   context->tlsContext = NULL;
#endif

   //Start of exception handling block
   do
   {
      //Bind the socket to a particular network interface?
      if(authInfo->interface)
      {
         //Associate the socket with the relevant interface
         error = socketBindToInterface(context->socket, authInfo->interface);
         //Any error to report?
         if(error) break;
      }

      //Set timeout for blocking operations
      error = socketSetTimeout(context->socket, SMTP_DEFAULT_TIMEOUT);
      //Any error to report?
      if(error) break;

      //Connect to the SMTP server
      error = socketConnect(context->socket, &serverIpAddr, authInfo->serverPort);
      //Connection to server failed?
      if(error) break;

#if (SMTP_TLS_SUPPORT == ENABLED)
      //Open a secure SSL/TLS session?
      if(authInfo->useTls)
      {
         //Initialize TLS context
         context->tlsContext = tlsInit();
         //Initialization failed?
         if(!context->tlsContext)
         {
            //Unable to allocate memory
            error = ERROR_OUT_OF_MEMORY;
            //Stop immediately
            break;
         }

         //Bind TLS to the relevant socket
         error = tlsSetSocket(context->tlsContext, context->socket);
         //Any error to report?
         if(error) break;

         //Select client operation mode
         error = tlsSetConnectionEnd(context->tlsContext, TLS_CONNECTION_END_CLIENT);
         //Any error to report?
         if(error) break;

         //Set the PRNG algorithm to be used
         error = tlsSetPrng(context->tlsContext, authInfo->prngAlgo, authInfo->prngContext);
         //Any error to report?
         if(error) break;

         //Perform TLS handshake
         error = tlsConnect(context->tlsContext);
         //Failed to established a TLS session?
         if(error) break;
      }
#endif

      //Wait for the connection greeting reply
      error = smtpSendCommand(context, NULL, &replyCode, NULL);
      //Any communication error to report?
      if(error) break;

      //Check whether the greeting message was properly received
      if(!SMTP_REPLY_CODE_2YZ(replyCode))
      {
         //An unexpected response was received...
         error = ERROR_UNEXPECTED_RESPONSE;
         //Stop immediately
         break;
      }

      //Clear security features
      context->authLoginSupported = FALSE;
      context->authPlainSupported = FALSE;
      context->authCramMd5Supported = FALSE;
      context->startTlsSupported = FALSE;

      //Send EHLO command and parse server response
      error = smtpSendCommand(context, "EHLO [127.0.0.1]\r\n",
         &replyCode, smtpEhloReplyCallback);
      //Any communication error to report?
      if(error) break;

      //Check SMTP response code
      if(!SMTP_REPLY_CODE_2YZ(replyCode))
      {
         //An unexpected response was received...
         error = ERROR_UNEXPECTED_RESPONSE;
         //Stop immediately
         break;
      }

#if (SMTP_TLS_SUPPORT == ENABLED)
      //Check whether the STARTTLS command is supported
      if(context->startTlsSupported && !context->tlsContext)
      {
         //Send STARTTLS command
         error = smtpSendCommand(context, "STARTTLS\r\n", &replyCode, NULL);
         //Any communication error to report?
         if(error) break;

         //Check SMTP response code
         if(!SMTP_REPLY_CODE_2YZ(replyCode))
         {
            //An unexpected response was received...
            error = ERROR_UNEXPECTED_RESPONSE;
            //Stop immediately
            break;
         }

         //Initialize TLS context
         context->tlsContext = tlsInit();
         //Initialization failed?
         if(!context->tlsContext)
         {
            //Unable to allocate memory
            error = ERROR_OUT_OF_MEMORY;
            //Stop immediately
            break;
         }

         //Bind TLS to the relevant socket
         error = tlsSetSocket(context->tlsContext, context->socket);
         //Any error to report?
         if(error) break;

         //Select client operation mode
         error = tlsSetConnectionEnd(context->tlsContext, TLS_CONNECTION_END_CLIENT);
         //Any error to report?
         if(error) break;

         //Set the PRNG algorithm to be used
         error = tlsSetPrng(context->tlsContext, authInfo->prngAlgo, authInfo->prngContext);
         //Any error to report?
         if(error) break;

         //Perform TLS handshake
         error = tlsConnect(context->tlsContext);
         //Failed to established a TLS session?
         if(error) break;

         //Clear security features
         context->authLoginSupported = FALSE;
         context->authPlainSupported = FALSE;
         context->authCramMd5Supported = FALSE;

         //Send EHLO command and parse server response
         error = smtpSendCommand(context, "EHLO [127.0.0.1]\r\n",
            &replyCode, smtpEhloReplyCallback);
         //Any communication error to report?
         if(error) break;

         //Check SMTP response code
         if(!SMTP_REPLY_CODE_2YZ(replyCode))
         {
            //An unexpected response was received...
            error = ERROR_UNEXPECTED_RESPONSE;
            //Stop immediately
            break;
         }
      }
#endif

      //Authentication requires a valid user name and password
      if(authInfo->userName && authInfo->password)
      {
#if (SMTP_LOGIN_AUTH_SUPPORT == ENABLED)
         //LOGIN authentication mechanism supported?
         if(context->authLoginSupported)
         {
            //Perform LOGIN authentication
            error = smtpSendAuthLogin(context, authInfo);
            //Authentication failed?
            if(error) break;
         }
         else
#endif
#if (SMTP_PLAIN_AUTH_SUPPORT == ENABLED)
         //PLAIN authentication mechanism supported?
         if(context->authPlainSupported)
         {
            //Perform PLAIN authentication
            error = smtpSendAuthPlain(context, authInfo);
            //Authentication failed?
            if(error) break;
         }
         else
#endif
#if (SMTP_CRAM_MD5_AUTH_SUPPORT == ENABLED)
         //CRAM-MD5 authentication mechanism supported?
         if(context->authCramMd5Supported)
         {
            //Perform CRAM-MD5 authentication
            error = smtpSendAuthCramMd5(context, authInfo);
            //Authentication failed?
            if(error) break;
         }
         else
#endif
         //No authentication mechanism supported?
         {
            //Skip authentication step
         }
      }

      //Format the MAIL FROM command (a null return path must be accepted)
      if(mail->from.addr)
         sprintf(context->buffer, "MAIL FROM:<%s>\r\n", mail->from.addr);
      else
         strcpy(context->buffer, "MAIL FROM:<>\r\n");

      //Send the command to the server
      error = smtpSendCommand(context, context->buffer, &replyCode, NULL);
      //Any communication error to report?
      if(error) break;

      //Check SMTP response code
      if(!SMTP_REPLY_CODE_2YZ(replyCode))
      {
         //An unexpected response was received...
         error = ERROR_UNEXPECTED_RESPONSE;
         //Stop immediately
         break;
      }

      //Format the RCPT TO command
      for(i = 0; i < mail->recipientCount; i++)
      {
         //Skip recipient addresses that are not valid
         if(!mail->recipients[i].addr)
            continue;

         //Format the RCPT TO command
         sprintf(context->buffer, "RCPT TO:<%s>\r\n", mail->recipients[i].addr);
         //Send the command to the server
         error = smtpSendCommand(context, context->buffer, &replyCode, NULL);
         //Any communication error to report?
         if(error) break;

         //Check SMTP response code
         if(!SMTP_REPLY_CODE_2YZ(replyCode))
         {
            //An unexpected response was received...
            error = ERROR_UNEXPECTED_RESPONSE;
            //Stop immediately
            break;
         }
      }

      //Propagate exception if necessary
      if(error) break;

      //Send message body
      error = smtpSendData(context, mail);
      //Any error to report?
      if(error) break;

      //End of exception handling block
   } while(0);

   //Check status code
   if(error == NO_ERROR ||
      error == ERROR_UNEXPECTED_RESPONSE ||
      error == ERROR_AUTHENTICATION_FAILED)
   {
      //Properly disconnect from the SMTP server
      smtpSendCommand(context, "QUIT\r\n", &replyCode, NULL);
   }

#if (SMTP_TLS_SUPPORT == ENABLED)
   //Gracefully close SSL/TLS session
   if(context->tlsContext != NULL)
      tlsFree(context->tlsContext);
#endif

   //Close socket
   socketClose(context->socket);
   //Clean up previously allocated resources
   osFreeMem(context);

   //Return status code
   return error;
}
Example #20
0
error_t rsassaPkcs1v15Verify(const RsaPublicKey *key, const HashAlgo *hash,
   const uint8_t *digest, const uint8_t *signature, size_t signatureLength)
{
   error_t error;
   uint_t k;
   uint8_t *em;
   const uint8_t *oid;
   size_t oidLength;
   const uint8_t *d;
   size_t dLength;
   Mpi s;
   Mpi m;

   //Check parameters
   if(key == NULL || hash == NULL || digest == NULL || signature == NULL)
      return ERROR_INVALID_PARAMETER;

   //Debug message
   TRACE_DEBUG("RSA PKCS #1 v1.5 signature verification...\r\n");
   TRACE_DEBUG("  Modulus:\r\n");
   TRACE_DEBUG_MPI("    ", &key->n);
   TRACE_DEBUG("  Public exponent:\r\n");
   TRACE_DEBUG_MPI("    ", &key->e);
   TRACE_DEBUG("  Message digest:\r\n");
   TRACE_DEBUG_ARRAY("    ", digest, hash->digestSize);
   TRACE_DEBUG("  Signature:\r\n");
   TRACE_DEBUG_ARRAY("    ", signature, signatureLength);

   //Initialize multiple-precision integers
   mpiInit(&s);
   mpiInit(&m);

   //Get the length in octets of the modulus n
   k = mpiGetByteLength(&key->n);

   //Check the length of the signature
   if(signatureLength != k)
      return ERROR_INVALID_LENGTH;

   //Allocate a memory buffer to hold the encoded message
   em = osAllocMem(k);
   //Failed to allocate memory?
   if(!em) return ERROR_OUT_OF_MEMORY;

   //Start of exception handling block
   do
   {
      //Convert the signature to an integer signature representative s
      error = mpiReadRaw(&s, signature, signatureLength);
      //Conversion failed?
      if(error) break;

      //Apply the RSAVP1 verification primitive
      error = rsavp1(key, &s, &m);
      //Any error to report?
      if(error) break;

      //Convert the message representative m to an encoded message EM of length k octets
      error = mpiWriteRaw(&m, em, k);
      //Conversion failed?
      if(error) break;

      //Debug message
      TRACE_DEBUG("  Encoded message\r\n");
      TRACE_DEBUG_ARRAY("    ", em, k);

      //Parse the encoded message EM
      error = emsaPkcs1v15Decode(em, k, &oid, &oidLength, &d, &dLength);
      //Any error to report?
      if(error) break;

      //Assume an error...
      error = ERROR_INVALID_SIGNATURE_ALGO;
      //Ensure the hash algorithm identifier matches the OID
      if(oidComp(oid, oidLength, hash->oid, hash->oidSize))
         break;
      //Check the length of the digest
      if(dLength != hash->digestSize)
         break;

      //Compare the message digest
      error = memcmp(digest, d, dLength) ? ERROR_INVALID_SIGNATURE : NO_ERROR;

      //End of exception handling block
   } while(0);

   //Release multiple precision integers
   mpiFree(&s);
   mpiFree(&m);
   //Free previously allocated memory
   osFreeMem(em);

   //Return status code
   return error;
}
error_t httpServerProcessSetConfig(HttpConnection *connection)
{
   error_t error;
   uint_t i;
   size_t n;
   char_t *p;
   char_t *buffer;
   char_t *separator;
   char_t *property;
   char_t *value;
   Settings *newSettings;

   //Point to the scratch buffer
   buffer = connection->buffer;

   //Allocate a memory buffer to hold the new configuration
   newSettings = osAllocMem(sizeof(Settings));
   //Failed to allocate memory?
   if(!newSettings) return ERROR_OUT_OF_MEMORY;

   //Start of exception handling block
   do
   {
      //Retrieve default settings
      error = getDefaultSettings(newSettings);
      //Any error to report?
      if(error) break;

      //Process HTTP request body
      while(1)
      {
         //Read the HTTP request body until an ampersand is encountered
         error = httpReadStream(connection, buffer,
            HTTP_SERVER_BUFFER_SIZE - 1, &n, HTTP_FLAG_BREAK('&'));
         //End of stream detected?
         if(error) break;

         //Properly terminate the string with a NULL character
         buffer[n] = '\0';

         //Remove the trailing ampersand
         if(n > 0 && buffer[n - 1] == '&')
            buffer[--n] = '\0';

         //Decode the percent-encoded string
         error = httpDecodePercentEncodedString(buffer, buffer, HTTP_SERVER_BUFFER_SIZE);
         //Any error detected?
         if(error) break;

         //Check whether a separator is present
         separator = strchr(buffer, '=');

         //Separator found?
         if(separator)
         {
            //Split the line
            *separator = '\0';
            //Get property name and value
            property = strTrimWhitespace(buffer);
            value = strTrimWhitespace(separator + 1);

            //Debug message
            TRACE_DEBUG("[%s]=%s\r\n", property, value);

            //Icecast settings
            if(!strcasecmp(property, "icecastSettingsUrl"))
            {
               //Check resource length
               if(strlen(value) >= sizeof(newSettings->icecast.url))
               {
                  //Report an error
                  error = ERROR_INVALID_SYNTAX;
                  break;
               }

               //Save resource
               strcpy(newSettings->icecast.url, value);
            }
            else if(!strcasecmp(property, "icecastSettingsPort"))
            {
               //Save Icecast server port
               newSettings->icecast.port = strtoul(value, &p, 10);

               //Invalid port number?
               if(*p != '\0')
               {
                  //Report an error
                  error = ERROR_INVALID_SYNTAX;
                  break;
               }
            }
            //LAN settings
            else if(!strcasecmp(property, "lanSettingsMacAddr"))
            {
               //Save MAC address
               error = macStringToAddr(value, &newSettings->lan.macAddr);
               //Invalid address?
               if(error) break;
            }
            else if(!strcasecmp(property, "lanSettingsHostName"))
            {
               //Check the length of the host name
               if(strlen(value) >= sizeof(newSettings->lan.hostname))
               {
                  //Report an error
                  error = ERROR_INVALID_SYNTAX;
                  break;
               }

               //Save host name
               strcpy(newSettings->lan.hostname, value);
            }
            else if(!strcasecmp(property, "lanSettingsEnableDhcp"))
            {
               //Check flag value
               if(!strcasecmp(value, "off"))
               {
                  //DHCP client is disabled
                  newSettings->lan.enableDhcp = FALSE;
               }
               else if(!strcasecmp(value, "on"))
               {
                  //DHCP client is enabled
                  newSettings->lan.enableDhcp = TRUE;
               }
               else
               {
                  //Invalid value
                  error = ERROR_INVALID_SYNTAX;
                  break;
               }
            }
            else if(!strcasecmp(property, "lanSettingsHostAddr"))
            {
               //Save IPv4 host address
               error = ipv4StringToAddr(value, &newSettings->lan.hostAddr);
               //Invalid address?
               if(error) break;
            }
            else if(!strcasecmp(property, "lanSettingsSubnetMask"))
            {
               //Save subnet mask
               error = ipv4StringToAddr(value, &newSettings->lan.subnetMask);
               //Invalid mask?
               if(error) break;
            }
            else if(!strcasecmp(property, "lanSettingsDefaultGateway"))
            {
               //Save default gateway
               error = ipv4StringToAddr(value, &newSettings->lan.defaultGateway);
               //Invalid address?
               if(error) break;
            }
            else if(!strcasecmp(property, "lanSettingsPrimaryDns"))
            {
               //Save primary DNS
               error = ipv4StringToAddr(value, &newSettings->lan.primaryDns);
               //Invalid address?
               if(error) break;
            }
            else if(!strcasecmp(property, "lanSettingsSecondaryDns"))
            {
               //Save secondary DNS
               error = ipv4StringToAddr(value, &newSettings->lan.secondaryDns);
               //Invalid address?
               if(error) break;
            }
            //Proxy settings
            else if(!strcasecmp(property, "proxySettingsEnable"))
            {
               //Check flag value
               if(!strcasecmp(value, "off"))
               {
                  //Proxy server is disabled
                  newSettings->proxy.enable = FALSE;
               }
               else if(!strcasecmp(value, "on"))
               {
                  //Proxy server is enabled
                  newSettings->proxy.enable = TRUE;
               }
               else
               {
                  //Invalid value
                  error = ERROR_INVALID_SYNTAX;
                  break;
               }
            }
            else if(!strcasecmp(property, "proxySettingsName"))
            {
               //Check the length of proxy server name
               if(strlen(value) >= sizeof(newSettings->proxy.name))
               {
                  //Report an error
                  error = ERROR_INVALID_SYNTAX;
                  break;
               }

               //Save proxy server name
               strcpy(newSettings->proxy.name, value);
            }
            else if(!strcasecmp(property, "proxySettingsPort"))
            {
               //Save proxy server port
               newSettings->proxy.port = strtoul(value, &p, 10);

               //Invalid port number?
               if(*p != '\0')
               {
                  //Report an error
                  error = ERROR_INVALID_SYNTAX;
                  break;
               }
            }
         }
      }

      //Check status code
      if(error == NO_ERROR || error == ERROR_END_OF_STREAM)
      {
         //Commit changes
         appSettings = *newSettings;
         //Write settings to non-volatile memory
         error = saveSettings(newSettings);
      }
      else if(error != ERROR_INVALID_SYNTAX)
      {
         //Propagate exception
         break;
      }

      //Point to the scratch buffer
      buffer = connection->buffer + 384;
      //Format XML data
      n = sprintf(buffer, "<data>\r\n  <status>");

      if(error == ERROR_INVALID_SYNTAX)
         n += sprintf(buffer + n, "Invalid configuration!\r\n");
      else if(error != NO_ERROR)
         n += sprintf(buffer + n, "Failed to save settings to non-volatile memory!\r\n");
      else
         n += sprintf(buffer + n, "Settings successfully saved. Please reboot the board.\r\n");

      //Terminate XML data
      n += sprintf(buffer + n, "</status>\r\n</data>\r\n");

      //Format HTTP response header
      connection->response.version = connection->request.version;
      connection->response.statusCode = 200;
      connection->response.keepAlive = connection->request.keepAlive;
      connection->response.noCache = TRUE;
      connection->response.contentType = mimeGetType(".xml");
      connection->response.chunkedEncoding = FALSE;
      connection->response.contentLength = n;

      //Send the header to the client
      error = httpWriteHeader(connection);
      //Any error to report?
      if(error) break;

      //Send response body
      error = httpWriteStream(connection, buffer, n);
      //Any error to report?
      if(error) break;

      //Properly close output stream
      error = httpCloseStream(connection);
      //Any error to report?
      if(error) break;

      //End of exception handling block
   } while(0);

   //Free previously allocated memory
   osFreeMem(newSettings);
   //Return status code
   return error;
}
OsTask *osCreateTask(const char_t *name, OsTaskCode taskCode,
   void *params, size_t stackSize, int_t priority)
{
   uint_t i;
   OS_TASK *task;
   void *stack;

   //Enter critical section
   osSuspendAllTasks();

   //Loop through TCB table
   for(i = 0; i < OS_PORT_MAX_TASKS; i++)
   {
      //Check whether the current entry is free
      if(tcbTable[i] == NULL)
         break;
   }

   //Any entry available in the table?
   if(i < OS_PORT_MAX_TASKS)
   {
      //Allocate a memory block to hold the task's control block
      task = osAllocMem(sizeof(OS_TASK));

      //Successful memory allocation?
      if(task != NULL)
      {
         //Allocate a memory block to hold the task's stack
         stack = osAllocMem(stackSize * sizeof(uint_t));

         //Successful memory allocation?
         if(stack != NULL)
         {
            //Create a new task
            OS_CreateTaskEx(task, name, priority, taskCode,
               stack, stackSize * sizeof(uint_t), 1, params);

            //Save TCB base address
            tcbTable[i] = task;
            //Save stack base address
            stkTable[i] = stack;
         }
         else
         {
            osFreeMem(task);
            //Memory allocation failed
            task = NULL;
         }
      }
   }
   else
   {
      //Memory allocation failed
      task = NULL;
   }

   //Leave critical section
   osResumeAllTasks();

   //Return task pointer
   return task;
}
error_t httpServerProcessGetConfig(HttpConnection *connection)
{
   error_t error;
   uint_t i;
   size_t n;
   char_t *buffer;
   char_t temp[40];

   //Allocate a memory buffer
   buffer = osAllocMem(2048);
   //Failed to allocate memory?
   if(!buffer) return ERROR_OUT_OF_MEMORY;

   //Format XML data
   n = sprintf(buffer, "<settings>\r\n");

   //Icecast settings
   n += sprintf(buffer + n, "  <icecast>\r\n");
   //Icecast resource
   n += sprintf(buffer + n, "    <url>%s</url>\r\n",
      appSettings.icecast.url);
   //Icecast server port
   n += sprintf(buffer + n, "    <port>%" PRIu16 "</port>\r\n",
      appSettings.icecast.port);
   //End of Icecast settings
   n += sprintf(buffer + n, "  </icecast>\r\n");

   //LAN settings
   n += sprintf(buffer + n, "  <lan>\r\n");
   //MAC address
   n += sprintf(buffer + n, "    <macAddr>%s</macAddr>\r\n",
      macAddrToString(&appSettings.lan.macAddr, temp));
   //Host name
   n += sprintf(buffer + n, "    <hostName>%s</hostName>\r\n",
      appSettings.lan.hostname);
   //Enable DHCP
   n += sprintf(buffer + n, "    <enableDhcp>%u</enableDhcp>\r\n",
      appSettings.lan.enableDhcp);
   //IPv4 host address
   n += sprintf(buffer + n, "    <hostAddr>%s</hostAddr>\r\n",
      ipv4AddrToString(appSettings.lan.hostAddr, temp));
   //Subnet mask
   n += sprintf(buffer + n, "    <subnetMask>%s</subnetMask>\r\n",
      ipv4AddrToString(appSettings.lan.subnetMask, temp));
   //Default gateway
   n += sprintf(buffer + n, "    <defaultGateway>%s</defaultGateway>\r\n",
      ipv4AddrToString(appSettings.lan.defaultGateway, temp));
   //Primary DNS
   n += sprintf(buffer + n, "    <primaryDns>%s</primaryDns>\r\n",
      ipv4AddrToString(appSettings.lan.primaryDns, temp));
   //Secondary DNS
   n += sprintf(buffer + n, "    <secondaryDns>%s</secondaryDns>\r\n",
      ipv4AddrToString(appSettings.lan.secondaryDns, temp));
   //End of LAN settings
   n += sprintf(buffer + n, "  </lan>\r\n");

   //Proxy settings
   n += sprintf(buffer + n, "  <proxy>\r\n");
   //Enable proxy server
   n += sprintf(buffer + n, "    <enable>%u</enable>\r\n",
      appSettings.proxy.enable);
   //Proxy server name
   n += sprintf(buffer + n, "    <name>%s</name>\r\n",
      appSettings.proxy.name);
   //Proxy server port
   n += sprintf(buffer + n, "    <port>%" PRIu16 "</port>\r\n",
      appSettings.proxy.port);
   //End of proxy settings
   n += sprintf(buffer + n, "  </proxy>\r\n");

  //End of settings
   n += sprintf(buffer + n, "</settings>\r\n");

   //Format HTTP response header
   connection->response.version = connection->request.version;
   connection->response.statusCode = 200;
   connection->response.keepAlive = connection->request.keepAlive;
   connection->response.noCache = TRUE;
   connection->response.contentType = mimeGetType(".xml");
   connection->response.chunkedEncoding = FALSE;
   connection->response.contentLength = n;

   //Send the header to the client
   error = httpWriteHeader(connection);

   //Check status code
   if(!error)
   {
      //Send response body
      error = httpWriteStream(connection, buffer, n);
   }

   //Check status code
   if(!error)
   {
      //Properly close output stream
      error = httpCloseStream(connection);
   }

   //Free previously allocated memory
   osFreeMem(buffer);
   //Return status code
   return error;
}