示例#1
0
error_t dhcpv6DumpAuthOption(const Dhcpv6Option *option, uint_t level)
{
   uint_t n;
   Dhcpv6AuthOption *authOption;

   //Check the length of the option
   if(ntohs(option->length) < sizeof(Dhcpv6AuthOption))
      return ERROR_INVALID_OPTION;

   //Point to the option contents
   authOption = (Dhcpv6AuthOption *) option->value;
   //Get the length of the authentication information
   n = ntohs(option->length) - sizeof(Dhcpv6AuthOption);

   //Dump contents
   TRACE_DEBUG("%sAuthentication option (%u bytes)\r\n", prefix[level], ntohs(option->length));
   TRACE_DEBUG("%sProtocol = %u\r\n", prefix[level + 1], authOption->protocol);
   TRACE_DEBUG("%sAlgorithm = %u\r\n", prefix[level + 1], authOption->algorithm);
   TRACE_DEBUG("%sRDM = %u\r\n", prefix[level + 1], authOption->rdm);
   TRACE_DEBUG("%sReplay Detection\r\n", prefix[level + 1]);
   TRACE_DEBUG_ARRAY(prefix[level + 2], authOption->replayDetection, 8);
   TRACE_DEBUG("%sAuthentication Information (%u bytes)\r\n", prefix[level + 1], n);
   TRACE_DEBUG_ARRAY(prefix[level + 2], authOption->authInfo, n);

   //No error to report
   return NO_ERROR;
}
示例#2
0
error_t dhcpDumpRawData(const DhcpOption *option)
{
   //Dump option contents
   TRACE_DEBUG_ARRAY("    ", option->value, option->length);

   //No error to report
   return NO_ERROR;
}
void sntpDumpMessage(const NtpHeader *message, size_t length)
{
#if (SNTP_TRACE_LEVEL >= TRACE_LEVEL_DEBUG)
   uint8_t *p;
   NtpAuthData* authData;

   //Point to the beginning of the message
   p = (uint8_t *) message;

   //Check message length
   if(length >= sizeof(NtpHeader))
   {
      //Dump NTP message
      TRACE_DEBUG("  Mode = %" PRIu8 "\r\n", message->mode);
      TRACE_DEBUG("  Version = %" PRIu8 "\r\n", message->vn);
      TRACE_DEBUG("  Leap indicator = %" PRIu8 "\r\n", message->li);
      TRACE_DEBUG("  Stratum = %" PRIu8 "\r\n", message->stratum);
      TRACE_DEBUG("  Poll = %" PRIu8 "\r\n", message->poll);
      TRACE_DEBUG("  Precision = %" PRId8 "\r\n", message->precision);
      TRACE_DEBUG("  Root Delay = %" PRIu32 "\r\n", ntohl(message->rootDelay));
      TRACE_DEBUG("  Root Dispersion = %" PRIu32 "\r\n", ntohl(message->rootDispersion));
      TRACE_DEBUG("  Reference Identifier = %" PRIu32 "\r\n", ntohl(message->referenceIdentifier));

      //Dump reference timestamp
      TRACE_DEBUG("  ReferenceTimestamp\r\n");
      sntpDumpTimestamp(&message->referenceTimestamp);

      //Dump originate timestamp
      TRACE_DEBUG("  Originate Timestamp\r\n");
      sntpDumpTimestamp(&message->originateTimestamp);

      //Dump receive timestamp
      TRACE_DEBUG("  Receive Timestamp\r\n");
      sntpDumpTimestamp(&message->receiveTimestamp);

      //Dump transmit timestamp
      TRACE_DEBUG("  Transmit Timestamp\r\n");
      sntpDumpTimestamp(&message->transmitTimestamp);

      //Advance data pointer
      p += sizeof(NtpHeader);
      length -= sizeof(NtpHeader);

      //Any authentication data?
      if(length >= sizeof(NtpAuthData))
      {
         //Point to the beginning of the authentication data
         authData = (NtpAuthData *) p;

         //Dump transmit timestamp
         TRACE_DEBUG("  Key Identifier = %" PRIu32 "\r\n", ntohl(authData->keyIdentifier));
         //Dump message digest
         TRACE_DEBUG("  Message Digest\r\n");
         TRACE_DEBUG_ARRAY("    ", authData->messageDigest, 16);
      }
   }
#endif
}
示例#4
0
error_t dhcpv6DumpGenericOption(const Dhcpv6Option *option, uint_t level)
{
   //Dump contents
   TRACE_DEBUG("%sOption %u (%u bytes)\r\n", prefix[level], ntohs(option->code), ntohs(option->length));
   TRACE_DEBUG_ARRAY(prefix[level + 1], option->value, ntohs(option->length));

   //No error to report
   return NO_ERROR;
}
示例#5
0
error_t dhcpv6DumpDomainListOption(const Dhcpv6Option *option, uint_t level)
{
   //Dump contents
   TRACE_DEBUG("%sDomain Search List option (%u bytes)\r\n", prefix[level], ntohs(option->length));
   TRACE_DEBUG_ARRAY(prefix[level + 1], option->value, ntohs(option->length));

   //No error to report
   return NO_ERROR;
}
示例#6
0
error_t dhcpv6DumpVendorSpecificInfoOption(const Dhcpv6Option *option, uint_t level)
{
   //Dump contents
   TRACE_DEBUG("%sVendor Specific Information option (%u bytes)\r\n", prefix[level], ntohs(option->length));
   TRACE_DEBUG_ARRAY(prefix[level + 1], option->value, ntohs(option->length));

   //No error to report
   return NO_ERROR;
}
示例#7
0
error_t dhcpv6DumpServerIdOption(const Dhcpv6Option *option, uint_t level)
{
   //Dump contents
   TRACE_DEBUG("%sServer Identifier option (%u bytes)\r\n", prefix[level], ntohs(option->length));
   TRACE_DEBUG_ARRAY(prefix[level + 1], option->value, ntohs(option->length));

   //No error to report
   return NO_ERROR;
}
示例#8
0
error_t tlsSendFinished(TlsContext *context)
{
   error_t error;
   size_t length;
   TlsFinished *message;

   //The verify data is generated from all messages in this
   //handshake up to but not including the Finished message
   error = tlsComputeVerifyData(context, context->entity);
   //Unable to generate the verify data?
   if(error) return error;

   //Point to the ChangeCipherSpec message
   message = (TlsFinished *) (context->txBuffer + sizeof(TlsRecord));
   //Set message type
   message->msgType = TLS_TYPE_FINISHED;
   //Set message length
   STORE24BE(context->verifyDataLength, message->length);

   //Copy the resulting verify data
   memcpy(message->verifyData, context->verifyData, context->verifyDataLength);
   //Length of the complete handshake message
   length = context->verifyDataLength + sizeof(TlsHandshake);

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

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

   //TLS operates as a client or a server?
   if(context->entity == TLS_CONNECTION_END_CLIENT)
   {
      //Use abbreviated or full handshake?
      if(context->resume)
         context->state = TLS_STATE_APPLICATION_DATA;
      else
         context->state = TLS_STATE_SERVER_CHANGE_CIPHER_SPEC;
   }
   else
   {
      //Use abbreviated or full handshake?
      if(context->resume)
         context->state = TLS_STATE_CLIENT_CHANGE_CIPHER_SPEC;
      else
         context->state = TLS_STATE_APPLICATION_DATA;
   }

   //Successful processing
   return NO_ERROR;
}
示例#9
0
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;
}
示例#10
0
文件: dh.c 项目: nandojve/embedded
error_t dhComputeSharedSecret(DhContext *context,
   uint8_t *output, size_t outputSize, size_t *outputLength)
{
   error_t error;
   size_t k;
   Mpi z;

   //Debug message
   TRACE_DEBUG("Computing Diffie-Hellman shared secret...\r\n");

   //Get the length in octets of the prime modulus
   k = mpiGetByteLength(&context->params.p);

   //Make sure that the output buffer is large enough
   if(outputSize < k)
      return ERROR_INVALID_LENGTH;

   //The multiple precision integer must be initialized before it can be used
   mpiInit(&z);

   //Start of exception handling block
   do
   {
      //Calculate the shared secret key (k = yb ^ xa mod p)
      error = mpiExpMod(&z, &context->yb, &context->xa, &context->params.p);
      //Any error to report?
      if(error) return error;

      //Convert the resulting integer to an octet string
      error = mpiWriteRaw(&z, output, k);
      //Conversion failed?
      if(error) return error;

      //Length of the resulting shared secret
      *outputLength = k;

      //Debug message
      TRACE_DEBUG("  Shared secret (%" PRIuSIZE " bytes):\r\n", *outputLength);
      TRACE_DEBUG_ARRAY("    ", output, *outputLength);

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

   //Release previously allocated resources
   mpiFree(&z);
   //Return status code
   return error;
}
示例#11
0
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;
}
示例#12
0
error_t ipv6cpDumpOptions(const PppOption *option, size_t length)
{
   //Parse options
   while(length > 0)
   {
      //Malformed IPV6CP packet?
      if(length < sizeof(PppOption))
         return ERROR_INVALID_LENGTH;

      //Check option length
      if(option->length < sizeof(PppOption))
         return ERROR_INVALID_LENGTH;
      if(option->length > length)
         return ERROR_INVALID_LENGTH;

      //Display the name of the current option
      if(option->type < arraysize(ipv6cpOptionLabel))
         TRACE_DEBUG("  %s option (%" PRIu8 " bytes)\r\n", ipv6cpOptionLabel[option->type], option->length);
      else
         TRACE_DEBUG("  Option %" PRIu8 " (%" PRIu8 " bytes)\r\n", option->type, option->length);

      //Check option code
      switch(option->type)
      {
      //Raw data?
      default:
         //Dump option contents
         TRACE_DEBUG_ARRAY("    ", option->data, option->length - sizeof(PppOption));
         break;
      }

      //Remaining bytes to process
      length -= option->length;
      //Jump to the next option
      option = (PppOption *) ((uint8_t *) option + option->length);
   }

   //No error to report
   return NO_ERROR;
}
示例#13
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;
}
示例#14
0
error_t lcpDumpOptions(const PppOption *option, size_t length)
{
   uint32_t value;

   //Parse options
   while(length > 0)
   {
      //Malformed LCP packet?
      if(length < sizeof(PppOption))
         return ERROR_INVALID_LENGTH;

      //Check option length
      if(option->length < sizeof(PppOption))
         return ERROR_INVALID_LENGTH;
      if(option->length > length)
         return ERROR_INVALID_LENGTH;

      //Display the name of the current option
      if(option->type < arraysize(lcpOptionLabel))
         TRACE_DEBUG("  %s option (%" PRIu8 " bytes)\r\n", lcpOptionLabel[option->type], option->length);
      else
         TRACE_DEBUG("  Option %" PRIu8 " (%" PRIu8 " bytes)\r\n", option->type, option->length);

      //Check option code
      switch(option->type)
      {
      //16-bit unsigned value?
      case LCP_OPTION_MRU:
         //Check length field
         if(option->length != (sizeof(PppOption) + sizeof(uint16_t)))
            return ERROR_INVALID_OPTION;
         //Retrieve 16-bit value
         value = LOAD16BE(option->data);
         //Dump option contents
         TRACE_DEBUG("    %" PRIu32 "\r\n", value);
         break;

      //32-bit unsigned value?
      case LCP_OPTION_ACCM:
      case LCP_OPTION_MAGIC_NUMBER:
         //Check length field
         if(option->length != (sizeof(PppOption) + sizeof(uint32_t)))
            return ERROR_INVALID_OPTION;
         //Retrieve 32-bit value
         value = LOAD32BE(option->data);
         //Dump option contents
         TRACE_DEBUG("    0x%08" PRIX32 "\r\n", value);
         break;

      //Raw data?
      default:
         //Dump option contents
         TRACE_DEBUG_ARRAY("    ", option->data, option->length - sizeof(PppOption));
         break;
      }

      //Remaining bytes to process
      length -= option->length;
      //Jump to the next option
      option = (PppOption *) ((uint8_t *) option + option->length);
   }

   //No error to report
   return NO_ERROR;
}
示例#15
0
error_t ipcpDumpOptions(const PppOption *option, size_t length)
{
#if (IPV4_SUPPORT == ENABLED)
   Ipv4Addr ipAddr;
#endif

   //Parse options
   while(length > 0)
   {
      //Malformed IPCP packet?
      if(length < sizeof(PppOption))
         return ERROR_INVALID_LENGTH;

      //Check option length
      if(option->length < sizeof(PppOption))
         return ERROR_INVALID_LENGTH;
      if(option->length > length)
         return ERROR_INVALID_LENGTH;

      //Display the name of the current option
      if(option->type < arraysize(ipcpOptionLabel))
         TRACE_DEBUG("  %s option (%" PRIu8 " bytes)\r\n", ipcpOptionLabel[option->type], option->length);
      else if(option->type >= 128 && option->type < (128 + arraysize(ipcpOptionLabel2)))
         TRACE_DEBUG("  %s option (%" PRIu8 " bytes)\r\n", ipcpOptionLabel2[option->type - 128], option->length);
      else
         TRACE_DEBUG("  Option %" PRIu8 " (%" PRIu8 " bytes)\r\n", option->type, option->length);

      //Check option code
      switch(option->type)
      {
#if (IPV4_SUPPORT == ENABLED)
      //IP address?
      case IPCP_OPTION_IP_ADDRESS:
      case IPCP_OPTION_PRIMARY_DNS:
      case IPCP_OPTION_PRIMARY_NBNS:
      case IPCP_OPTION_SECONDARY_DNS:
      case IPCP_OPTION_SECONDARY_NBNS:
         //Check length field
         if(option->length != (sizeof(PppOption) + sizeof(Ipv4Addr)))
            return ERROR_INVALID_OPTION;
         //Retrieve IPv4 address
         ipv4CopyAddr(&ipAddr, option->data);
         //Dump option contents
         TRACE_DEBUG("    %s\r\n", ipv4AddrToString(ipAddr, NULL));
         break;
#endif
      //Raw data?
      default:
         //Dump option contents
         TRACE_DEBUG_ARRAY("    ", option->data, option->length - sizeof(PppOption));
         break;
      }

      //Remaining bytes to process
      length -= option->length;
      //Jump to the next option
      option = (PppOption *) ((uint8_t *) option + option->length);
   }

   //No error to report
   return NO_ERROR;
}
示例#16
0
error_t papDumpPacket(const PppPacket *packet, size_t length)
{
   const char_t *label;

   //Make sure the PAP packet is valid
   if(length < sizeof(PppPacket))
      return ERROR_INVALID_LENGTH;

   //Check the length field
   if(ntohs(packet->length) > length)
      return ERROR_INVALID_LENGTH;
   if(ntohs(packet->length) < sizeof(PppPacket))
      return ERROR_INVALID_LENGTH;

   //Save the length of the PAP packet
   length = ntohs(packet->length);

   //Retrieve the name of the PAP packet
   if(packet->code < arraysize(papCodeLabel))
      label = papCodeLabel[packet->code];
   else
      label = "Unknown";

   //Dump PAP packet header
   TRACE_DEBUG("  Code = %" PRIu8 " (%s)\r\n", packet->code, label);
   TRACE_DEBUG("  Identifier = %" PRIu8  "\r\n", packet->identifier);
   TRACE_DEBUG("  Length = %" PRIu16 "\r\n", ntohs(packet->length));

   //Authenticate-Request packet?
   if(packet->code == PAP_CODE_AUTH_REQ)
   {
      uint8_t *q;
      PapAuthReqPacket *p;

      //Cast PAP packet
      p = (PapAuthReqPacket *) packet;

      //Valid packet length?
      if(length < sizeof(PapAuthReqPacket))
         return ERROR_INVALID_LENGTH;

      //Peer-ID-Length field
      TRACE_DEBUG("  Peer-ID-Length = %" PRIu8 "\r\n", p->peerIdLength);

      //Check the length of the Peer-ID field
      if(length < (sizeof(PapAuthAckPacket) + 1 + p->peerIdLength))
         return ERROR_INVALID_LENGTH;

      //Peer-ID field
      TRACE_DEBUG("  Peer-ID\r\n");
      TRACE_DEBUG_ARRAY("    ", p->peerId, p->peerIdLength);

      //Point to the Passwd-Length field
      q = p->peerId + p->peerIdLength;

      //Passwd-Length field
      TRACE_DEBUG("  Passwd-Length = %" PRIu8 "\r\n", q[0]);

      //Check the length of the Password field
      if(length < (sizeof(PapAuthAckPacket) + 1 + p->peerIdLength + q[0]))
         return ERROR_INVALID_LENGTH;

      //Password field
      TRACE_DEBUG("  Password\r\n");
      TRACE_DEBUG_ARRAY("    ", q + 1, q[0]);
   }
   //Authenticate-Ack or Authenticate-Nak packet?
   else if(packet->code == PAP_CODE_AUTH_ACK ||
      packet->code == PAP_CODE_AUTH_NAK)
   {
      PapAuthAckPacket *p;

      //Cast PAP packet
      p = (PapAuthAckPacket *) packet;

      //Valid packet length?
      if(length < sizeof(PapAuthAckPacket))
         return ERROR_INVALID_LENGTH;

      //Msg-Length field
      TRACE_DEBUG("  Msg-Length = %" PRIu8 "\r\n", p->msgLength);

      //Check the length of the Message field
      if(length < (sizeof(PapAuthAckPacket) + p->msgLength))
         return ERROR_INVALID_LENGTH;

      if(length > 0)
      {
         //Message field
         TRACE_DEBUG("  Message\r\n");
         TRACE_DEBUG_ARRAY("    ", p->message, p->msgLength);
      }
   }
   //Unknown packet?
   else
   {
      //Retrieve the length of data
      length -= sizeof(PppPacket);

      //Any data?
      if(length > 0)
      {
         //Dump data
         TRACE_DEBUG("  Data (%" PRIuSIZE " bytes)\r\n", length);
         TRACE_DEBUG_ARRAY("    ", packet->data, length);
      }
   }

   //No error to report
   return NO_ERROR;
}
示例#17
0
error_t chapDumpPacket(const PppPacket *packet, size_t length)
{
   const char_t *label;

   //Make sure the CHAP packet is valid
   if(length < sizeof(PppPacket))
      return ERROR_INVALID_LENGTH;

   //Check the length field
   if(ntohs(packet->length) > length)
      return ERROR_INVALID_LENGTH;
   if(ntohs(packet->length) < sizeof(PppPacket))
      return ERROR_INVALID_LENGTH;

   //Save the length of the CHAP packet
   length = ntohs(packet->length);

   //Retrieve the name of the CHAP packet
   if(packet->code < arraysize(chapCodeLabel))
      label = chapCodeLabel[packet->code];
   else
      label = "Unknown";

   //Dump CHAP packet header
   TRACE_DEBUG("  Code = %" PRIu8 " (%s)\r\n", packet->code, label);
   TRACE_DEBUG("  Identifier = %" PRIu8  "\r\n", packet->identifier);
   TRACE_DEBUG("  Length = %" PRIu16 "\r\n", ntohs(packet->length));

   //Challenge or Response packet?
   if(packet->code == CHAP_CODE_CHALLENGE ||
      packet->code == CHAP_CODE_RESPONSE)
   {
      uint8_t *q;
      ChapChallengePacket *p;

      //Cast CHAP packet
      p = (ChapChallengePacket *) packet;

      //Valid packet length?
      if(length < sizeof(ChapChallengePacket))
         return ERROR_INVALID_LENGTH;

      //Value-Size field
      TRACE_DEBUG("  Value-Size = %" PRIu8 "\r\n", p->valueSize);

      //Check the length of the Value field
      if(length < (sizeof(ChapChallengePacket) + p->valueSize))
         return ERROR_INVALID_LENGTH;

      //Value field
      TRACE_DEBUG("  Value\r\n");
      TRACE_DEBUG_ARRAY("    ", p->value, p->valueSize);

      //Point to the Name field
      q = p->value + p->valueSize;
      //Retrieve the length of the Name field
      length -= sizeof(ChapChallengePacket) + p->valueSize;

      //Name field
      TRACE_DEBUG("  Name (%" PRIuSIZE " bytes)\r\n", length);
      TRACE_DEBUG_ARRAY("    ", q, length);
   }
   //Success or Failure packet?
   else if(packet->code == CHAP_CODE_SUCCESS ||
      packet->code == CHAP_CODE_FAILURE)
   {
      ChapSuccessPacket *p;

      //Cast CHAP packet
      p = (ChapSuccessPacket *) packet;

      //Valid packet length?
      if(length < sizeof(ChapSuccessPacket))
         return ERROR_INVALID_LENGTH;

      //Retrieve the length of Message field
      length -= sizeof(ChapSuccessPacket);

      //Message field
      TRACE_DEBUG("  Message (%" PRIuSIZE " bytes)\r\n", length);
      TRACE_DEBUG_ARRAY("    ", p->message, length);
   }
   //Unknown packet?
   else
   {
      //Retrieve the length of data
      length -= sizeof(PppPacket);

      //Any data?
      if(length > 0)
      {
         //Dump data
         TRACE_DEBUG("  Data (%" PRIuSIZE " bytes)\r\n", length);
         TRACE_DEBUG_ARRAY("    ", packet->data, length);
      }
   }

   //No error to report
   return NO_ERROR;
}
示例#18
0
error_t lcpDumpPacket(const PppPacket *packet, size_t length)
{
   error_t error;
   const char_t *label;

   //Make sure the LCP packet is valid
   if(length < sizeof(PppPacket))
      return ERROR_INVALID_LENGTH;

   //Check the length field
   if(ntohs(packet->length) > length)
      return ERROR_INVALID_LENGTH;
   if(ntohs(packet->length) < sizeof(PppPacket))
      return ERROR_INVALID_LENGTH;

   //Save the length of the LCP packet
   length = ntohs(packet->length);

   //Retrieve the name of the LCP packet
   if(packet->code < arraysize(lcpCodeLabel))
      label = lcpCodeLabel[packet->code];
   else
      label = "Unknown";

   //Dump LCP packet header
   TRACE_DEBUG("  Code = %" PRIu8 " (%s)\r\n", packet->code, label);
   TRACE_DEBUG("  Identifier = %" PRIu8  "\r\n", packet->identifier);
   TRACE_DEBUG("  Length = %" PRIu16 "\r\n", ntohs(packet->length));

   //Configure-Request, Configure-Ack, Configure-Nak or Configure-Reject packet?
   if(packet->code == PPP_CODE_CONFIGURE_REQ ||
      packet->code == PPP_CODE_CONFIGURE_ACK ||
      packet->code == PPP_CODE_CONFIGURE_NAK ||
      packet->code == PPP_CODE_CONFIGURE_REJ)
   {
      //Cast LCP packet
      PppConfigurePacket *p = (PppConfigurePacket *) packet;

      //Valid packet length?
      if(length < sizeof(PppConfigurePacket))
         return ERROR_INVALID_LENGTH;

      //Retrieve the length of the option list
      length -= sizeof(PppConfigurePacket);

      //Dump options
      error = lcpDumpOptions((PppOption *) p->options, length);
      //Any error to report?
      if(error) return error;
   }
   //Terminate-Request or Terminate-Ack packet?
   else if(packet->code == PPP_CODE_TERMINATE_REQ ||
      packet->code == PPP_CODE_TERMINATE_ACK)
   {
      //Cast LCP packet
      PppTerminatePacket *p = (PppTerminatePacket *) packet;

      //Valid packet length?
      if(length < sizeof(PppTerminatePacket))
         return ERROR_INVALID_LENGTH;

      //Retrieve the length of data
      length -= sizeof(PppTerminatePacket);

      //Any data?
      if(length > 0)
      {
         //Dump data
         TRACE_DEBUG("  Data (%" PRIuSIZE " bytes)\r\n", length);
         TRACE_DEBUG_ARRAY("    ", p->data, length);
      }
   }
   //Code-Reject packet?
   else if(packet->code == PPP_CODE_CODE_REJ)
   {
      //Cast LCP packet
      PppCodeRejPacket *p = (PppCodeRejPacket *) packet;

      //Valid packet length?
      if(length < sizeof(PppCodeRejPacket))
         return ERROR_INVALID_LENGTH;

      //Retrieve the length of Rejected-Packet field
      length -= sizeof(PppCodeRejPacket);

      //Rejected-Packet
      TRACE_DEBUG("  Rejected-Packet (%" PRIuSIZE " bytes)\r\n", length);
      TRACE_DEBUG_ARRAY("    ", p->rejectedPacket, length);
   }
   //Protocol-Reject packet?
   else if(packet->code == PPP_CODE_PROTOCOL_REJ)
   {
      //Cast LCP packet
      PppProtocolRejPacket *p = (PppProtocolRejPacket *) packet;

      //Valid packet length?
      if(length < sizeof(PppProtocolRejPacket))
         return ERROR_INVALID_LENGTH;

      //Retrieve the length of Rejected-Information field
      length -= sizeof(PppProtocolRejPacket);

      //Rejected-Protocol
      TRACE_DEBUG("  Rejected-Protocol = %" PRIu16 "\r\n", htons(p->rejectedProtocol));
      //Rejected-Information
      TRACE_DEBUG("  Rejected-Information (%" PRIuSIZE " bytes)\r\n", length);
      TRACE_DEBUG_ARRAY("    ", p->rejectedInfo, length);
   }
   //Echo-Request, Echo-Reply or Discard-Request packet?
   else if(packet->code == PPP_CODE_ECHO_REQ ||
      packet->code == PPP_CODE_ECHO_REP ||
      packet->code == PPP_CODE_DISCARD_REQ)
   {
      //Cast LCP packet
      PppEchoPacket *p = (PppEchoPacket *) packet;

      //Valid packet length?
      if(length < sizeof(PppEchoPacket))
         return ERROR_INVALID_LENGTH;

      //Retrieve the length of data
      length -= sizeof(PppEchoPacket);

      //Magic-Number
      TRACE_DEBUG("  Magic-Number = %" PRIu32 "\r\n", htonl(p->magicNumber));
      //Data
      TRACE_DEBUG("  Data (%" PRIuSIZE " bytes)\r\n", length);
      TRACE_DEBUG_ARRAY("    ", p->data, length);
   }
   //Unknown packet?
   else
   {
      //Retrieve the length of data
      length -= sizeof(PppPacket);

      //Any data?
      if(length > 0)
      {
         //Dump data
         TRACE_DEBUG("  Data (%" PRIuSIZE " bytes)\r\n", length);
         TRACE_DEBUG_ARRAY("    ", packet->data, length);
      }
   }

   //No error to report
   return NO_ERROR;
}
示例#19
0
error_t ncpDumpPacket(const PppPacket *packet, size_t length, PppProtocol protocol)
{
   error_t error;
   const char_t *label;

   //Make sure the NDP packet is valid
   if(length < sizeof(PppPacket))
      return ERROR_INVALID_LENGTH;

   //Check the length field
   if(ntohs(packet->length) > length)
      return ERROR_INVALID_LENGTH;
   if(ntohs(packet->length) < sizeof(PppPacket))
      return ERROR_INVALID_LENGTH;

   //Save the length of the NDP packet
   length = ntohs(packet->length);

   //Retrieve the name of the NDP packet
   if(packet->code < arraysize(ncpCodeLabel))
      label = ncpCodeLabel[packet->code];
   else
      label = "Unknown";

   //Dump NDP packet header
   TRACE_DEBUG("  Code = %" PRIu8 " (%s)\r\n", packet->code, label);
   TRACE_DEBUG("  Identifier = %" PRIu8  "\r\n", packet->identifier);
   TRACE_DEBUG("  Length = %" PRIu16 "\r\n", ntohs(packet->length));

   //Configure-Request, Configure-Ack, Configure-Nak or Configure-Reject packet?
   if(packet->code == PPP_CODE_CONFIGURE_REQ ||
      packet->code == PPP_CODE_CONFIGURE_ACK ||
      packet->code == PPP_CODE_CONFIGURE_NAK ||
      packet->code == PPP_CODE_CONFIGURE_REJ)
   {
      //Cast NDP packet
      PppConfigurePacket *p = (PppConfigurePacket *) packet;

      //Valid packet length?
      if(length < sizeof(PppConfigurePacket))
         return ERROR_INVALID_LENGTH;

      //Retrieve the length of the option list
      length -= sizeof(PppConfigurePacket);

      //IPCP protocol?
      if(protocol == PPP_PROTOCOL_IPCP)
      {
         //Dump options
         error = ipcpDumpOptions((PppOption *) p->options, length);
         //Any error to report?
         if(error) return error;
      }
      //IPV6CP protocol?
      else if(protocol == PPP_PROTOCOL_IPV6CP)
      {
         //Dump options
         error = ipv6cpDumpOptions((PppOption *) p->options, length);
         //Any error to report?
         if(error) return error;
      }
   }
   //Terminate-Request or Terminate-Ack packet?
   else if(packet->code == PPP_CODE_TERMINATE_REQ ||
      packet->code == PPP_CODE_TERMINATE_ACK)
   {
      //Cast NDP packet
      PppTerminatePacket *p = (PppTerminatePacket *) packet;

      //Valid packet length?
      if(length < sizeof(PppTerminatePacket))
         return ERROR_INVALID_LENGTH;

      //Retrieve the length of data
      length -= sizeof(PppTerminatePacket);

      //Any data?
      if(length > 0)
      {
         //Dump data
         TRACE_DEBUG("  Data (%" PRIuSIZE " bytes)\r\n", length);
         TRACE_DEBUG_ARRAY("    ", p->data, length);
      }
   }
   //Code-Reject packet?
   else if(packet->code == PPP_CODE_CODE_REJ)
   {
      //Cast NDP packet
      PppCodeRejPacket *p = (PppCodeRejPacket *) packet;

      //Valid packet length?
      if(length < sizeof(PppCodeRejPacket))
         return ERROR_INVALID_LENGTH;

      //Retrieve the length of Rejected-Packet field
      length -= sizeof(PppCodeRejPacket);

      //Rejected-Packet
      TRACE_DEBUG("  Rejected-Packet (%" PRIuSIZE " bytes)\r\n", length);
      TRACE_DEBUG_ARRAY("    ", p->rejectedPacket, length);
   }
   //Unknown packet?
   else
   {
      //Retrieve the length of data
      length -= sizeof(PppPacket);

      //Any data?
      if(length > 0)
      {
         //Dump data
         TRACE_DEBUG("  Data (%" PRIuSIZE " bytes)\r\n", length);
         TRACE_DEBUG_ARRAY("    ", packet->data, length);
      }
   }

   //No error to report
   return NO_ERROR;
}
示例#20
0
error_t tlsParseFinished(TlsContext *context, const TlsFinished *message, size_t length)
{
   error_t error;

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

   //Check the length of the Finished message
   if(length < sizeof(TlsFinished))
      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_FINISHED)
         return ERROR_UNEXPECTED_MESSAGE;

      //The verify data is generated from all messages in this
      //handshake up to but not including the Finished message
      error = tlsComputeVerifyData(context, TLS_CONNECTION_END_SERVER);
   }
   else
   {
      //Check current state
      if(context->state != TLS_STATE_CLIENT_FINISHED)
         return ERROR_UNEXPECTED_MESSAGE;

      //The verify data is generated from all messages in this
      //handshake up to but not including the Finished message
      error = tlsComputeVerifyData(context, TLS_CONNECTION_END_CLIENT);
   }

   //Unable to generate the verify data?
   if(error) return error;

   //Check message length
   if(LOAD24BE(message->length) != context->verifyDataLength)
      return ERROR_DECODING_FAILED;

   //Check the resulting verify data
   if(memcmp(message->verifyData, context->verifyData, context->verifyDataLength))
      return ERROR_INVALID_SIGNATURE;

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

   //TLS operates as a client or a server?
   if(context->entity == TLS_CONNECTION_END_CLIENT)
   {
      //Use abbreviated or full handshake?
      if(context->resume)
         context->state = TLS_STATE_CLIENT_CHANGE_CIPHER_SPEC;
      else
         context->state = TLS_STATE_APPLICATION_DATA;
   }
   else
   {
      //Use abbreviated or full handshake?
      if(context->resume)
         context->state = TLS_STATE_APPLICATION_DATA;
      else
         context->state = TLS_STATE_SERVER_CHANGE_CIPHER_SPEC;
   }

   //Successful processing
   return NO_ERROR;
}
示例#21
0
error_t snmpParseMessage(SnmpAgentContext *context, const uint8_t *p, size_t length)
{
   error_t error;
   int32_t version;
   Asn1Tag tag;

   //Debug message
   TRACE_INFO("SNMP message received from %s port %" PRIu16 " (%" PRIuSIZE " bytes)...\r\n",
      ipAddrToString(&context->remoteIpAddr, NULL), context->remotePort, length);

   //Display the contents of the SNMP message
   TRACE_DEBUG_ARRAY("  ", p, length);

   //Dump ASN.1 structure
   error = asn1DumpObject(p, length, 0);
   //Any error to report?
   if(error) return error;

   //The SNMP message is encapsulated within a sequence
   error = asn1ReadTag(p, length, &tag);
   //Failed to decode ASN.1 tag?
   if(error) return error;

   //Enforce encoding, class and type
   error = asn1CheckTag(&tag, TRUE, ASN1_CLASS_UNIVERSAL, ASN1_TYPE_SEQUENCE);
   //The tag does not match the criteria?
   if(error) return error;

   //Point to the first field of the sequence
   p = tag.value;
   length = tag.length;

   //Read version identifier
   error = asn1ReadInt32(p, length, &tag, &version);
   //Failed to decode ASN.1 tag?
   if(error) return error;

   //The SNMP agent verifies the version number. If there is a mismatch,
   //it discards the datagram and performs no further actions
   if(version != context->version)
      return ERROR_INVALID_VERSION;

   //Point to the next field
   p += tag.totalLength;
   length -= tag.totalLength;

   //Read SNMP community name
   error = asn1ReadTag(p, length, &tag);
   //Failed to decode ASN.1 tag?
   if(error) return error;

   //Enforce encoding, class and type
   error = asn1CheckTag(&tag, FALSE, ASN1_CLASS_UNIVERSAL, ASN1_TYPE_OCTET_STRING);
   //The tag does not match the criteria?
   if(error) return error;

   //Save community name
   context->request.community = tag.value;
   context->request.communityLen = tag.length;

   //Point to the next field
   p += tag.totalLength;
   length -= tag.totalLength;

   //Read PDU
   error = asn1ReadTag(p, length, &tag);
   //Failed to decode ASN.1 tag?
   if(error) return error;

   //Check encoding
   if(tag.constructed != TRUE)
      return ERROR_WRONG_ENCODING;
   //Enforce class
   if(tag.class != ASN1_CLASS_CONTEXT_SPECIFIC)
      return ERROR_INVALID_CLASS;

   //Save PDU type
   context->request.pduType = (SnmpPduType) tag.type;

   //Process the protocol data unit
   switch(context->request.pduType)
   {
   case SNMP_PDU_GET_REQUEST:
   case SNMP_PDU_GET_NEXT_REQUEST:
      //Parse GetRequest-PDU or GetNextRequest-PDU
      error = snmpParseGetRequestPdu(context, tag.value, tag.length);
      break;
   case SNMP_PDU_GET_BULK_REQUEST:
      //Parse GetBulkRequest-PDU
      error = snmpParseGetBulkRequestPdu(context, tag.value, tag.length);
      break;
   case SNMP_PDU_SET_REQUEST:
      //Parse SetRequest-PDU
      error = snmpParseSetRequestPdu(context, tag.value, tag.length);
      break;
   default:
      //Invalid PDU type
      error = ERROR_INVALID_TYPE;
      break;
   }

   //Failed to parse PDU?
   if(error)
      return error;

   //Format response PDU header
   error = snmpWritePduHeader(context);
   //Any error to report?
   if(error) return error;

   //Debug message
   TRACE_INFO("SNMP message sent (%" PRIuSIZE " bytes)...\r\n", context->response.messageLen);
   //Display the contents of the SNMP message
   TRACE_DEBUG_ARRAY("  ", context->response.message, context->response.messageLen);

   //Display ASN.1 structure
   error = asn1DumpObject(context->response.message, context->response.messageLen, 0);
   //Any error to report?
   if(error) return error;

   //Send SNMP response message
   error = socketSendTo(context->socket, &context->remoteIpAddr, context->remotePort,
      context->response.message, context->response.messageLen, NULL, 0);

   //Return status code
   return error;
}
示例#22
0
error_t tlsWriteRecord(TlsContext *context,
   size_t length, TlsContentType contentType)
{
   error_t error;
   uint_t i;
   size_t paddingLength;

   //Point to the TLS record
   TlsRecord *record = (TlsRecord *) context->txBuffer;
   //Format TLS record
   record->type = contentType;
   record->version = htons(context->version);
   record->length = htons(length);

   //Debug message
   TRACE_DEBUG("Sending TLS record...\r\n");
   TRACE_DEBUG_ARRAY("  ", record, length + sizeof(TlsRecord));

   //Protect record payload?
   if(context->changeCipherSpecSent)
   {
      //Message authentication is required?
      if(context->hashAlgo)
      {
#if (TLS_MAX_VERSION >= SSL_VERSION_3_0 && TLS_MIN_VERSION <= SSL_VERSION_3_0)
         //Check whether SSL 3.0 is currently used
         if(context->version == SSL_VERSION_3_0)
         {
            //SSL 3.0 uses an older obsolete version of the HMAC construction
            error = sslComputeMac(context, context->writeMacKey,
               context->writeSeqNum, record, record->data, length, record->data + length);
            //Any error to report?
            if(error) return error;
         }
         else
#endif
#if (TLS_MAX_VERSION >= TLS_VERSION_1_0 && TLS_MIN_VERSION <= TLS_VERSION_1_2)
         //Check whether TLS 1.0, TLS 1.1 or TLS 1.2 is currently used
         if(context->version >= TLS_VERSION_1_0)
         {
            //TLS uses a HMAC construction
            hmacInit(&context->hmacContext, context->hashAlgo,
               context->writeMacKey, context->macKeyLength);
            //Compute MAC over the sequence number and the record contents
            hmacUpdate(&context->hmacContext, context->writeSeqNum, sizeof(TlsSequenceNumber));
            hmacUpdate(&context->hmacContext, record, length + sizeof(TlsRecord));
            //Append the resulting MAC to the message
            hmacFinal(&context->hmacContext, record->data + length);
         }
         else
#endif
         //The negotiated TLS version is not valid...
         {
            //Report an error
            return ERROR_INVALID_VERSION;
         }

         //Debug message
         TRACE_DEBUG("Write sequence number:\r\n");
         TRACE_DEBUG_ARRAY("  ", context->writeSeqNum, sizeof(TlsSequenceNumber));
         TRACE_DEBUG("Computed MAC:\r\n");
         TRACE_DEBUG_ARRAY("  ", record->data + length, context->hashAlgo->digestSize);

         //Adjust the length of the message
         length += context->hashAlgo->digestSize;
         //Fix length field
         record->length = htons(length);

         //Increment sequence number
         tlsIncSequenceNumber(context->writeSeqNum);
      }

      //Encryption is required?
      if(context->cipherAlgo)
      {
#if (TLS_STREAM_CIPHER_SUPPORT == ENABLED)
         //Stream cipher?
         if(context->cipherMode == CIPHER_MODE_STREAM)
         {
            //Debug message
            TRACE_DEBUG("Record before encryption:\r\n");
            TRACE_DEBUG_ARRAY("  ", record, length + sizeof(TlsRecord));
            //Encrypt record contents
            context->cipherAlgo->encryptStream(context->writeCipherContext,
               record->data, record->data, length);
         }
         else
#endif
#if (TLS_CBC_CIPHER_SUPPORT == ENABLED)
         //CBC block cipher?
         if(context->cipherMode == CIPHER_MODE_CBC)
         {
#if (TLS_MAX_VERSION >= TLS_VERSION_1_1 && TLS_MIN_VERSION <= TLS_VERSION_1_2)
            //TLS 1.1 and 1.2 use an explicit IV
            if(context->version >= TLS_VERSION_1_1)
            {
               //Make room for the IV at the beginning of the data
               memmove(record->data + context->recordIvLength, record->data, length);

               //The initialization vector should be chosen at random
               error = context->prngAlgo->read(context->prngContext,
                  record->data, context->recordIvLength);
               //Any error to report?
               if(error) return error;

               //Adjust the length of the message
               length += context->recordIvLength;
            }
#endif
            //Get the actual amount of bytes in the last block
            paddingLength = (length + 1) % context->cipherAlgo->blockSize;
            //Padding is added to force the length of the plaintext to be
            //an integral multiple of the cipher's block length
            if(paddingLength > 0)
               paddingLength = context->cipherAlgo->blockSize - paddingLength;

            //Write padding bytes
            for(i = 0; i <= paddingLength; i++)
               record->data[length + i] = paddingLength;

            //Compute the length of the resulting message
            length += paddingLength + 1;
            //Fix length field
            record->length = htons(length);

            //Debug message
            TRACE_DEBUG("Record before encryption:\r\n");
            TRACE_DEBUG_ARRAY("  ", record, length + sizeof(TlsRecord));

            //CBC encryption
            error = cbcEncrypt(context->cipherAlgo, context->writeCipherContext,
               context->writeIv, record->data, record->data, length);
            //Any error to report?
            if(error) return error;
         }
         else
#endif
#if (TLS_CCM_CIPHER_SUPPORT == ENABLED || TLS_GCM_CIPHER_SUPPORT == ENABLED)
         //AEAD cipher?
         if(context->cipherMode == CIPHER_MODE_CCM ||
            context->cipherMode == CIPHER_MODE_GCM)
         {
            uint8_t *data;
            uint8_t *tag;
            size_t nonceLength;
            uint8_t nonce[12];
            uint8_t a[13];

            //Determine the total length of the nonce
            nonceLength = context->fixedIvLength + context->recordIvLength;
            //The salt is the implicit part of the nonce and is not sent in the packet
            memcpy(nonce, context->writeIv, context->fixedIvLength);

            //The explicit part of the nonce is chosen by the sender
            error = context->prngAlgo->read(context->prngContext,
               nonce + context->fixedIvLength, context->recordIvLength);
            //Any error to report?
            if(error) return error;

            //Make room for the explicit nonce at the beginning of the record
            memmove(record->data + context->recordIvLength, record->data, length);
            //The explicit part of the nonce is carried in each TLS record
            memcpy(record->data, nonce + context->fixedIvLength, context->recordIvLength);

            //Additional data to be authenticated
            memcpy(a, context->writeSeqNum, sizeof(TlsSequenceNumber));
            memcpy(a + sizeof(TlsSequenceNumber), record, sizeof(TlsRecord));

            //Plaintext data
            data = record->data + context->recordIvLength;
            //Buffer where to store the authentication tag
            tag = data + length;

#if (TLS_CCM_CIPHER_SUPPORT == ENABLED)
            //CCM cipher mode?
            if(context->cipherMode == CIPHER_MODE_CCM)
            {
               //Authenticated encryption using CCM
               error = ccmEncrypt(context->cipherAlgo, context->writeCipherContext,
                  nonce, nonceLength, a, 13, data, data, length, tag, context->authTagLength);
            }
            else
#endif
#if (TLS_GCM_CIPHER_SUPPORT == ENABLED)
            //GCM cipher mode?
            if(context->cipherMode == CIPHER_MODE_GCM)
            {
               //Authenticated encryption using GCM
               error = gcmEncrypt(context->cipherAlgo, context->writeCipherContext,
                  nonce, nonceLength, a, 13, data, data, length, tag, context->authTagLength);
            }
            else
#endif
            //Invalid cipher mode?
            {
               //The specified cipher mode is not supported
               error = ERROR_UNSUPPORTED_CIPHER_MODE;
            }

            //Failed to encrypt data?
            if(error) return error;

            //Compute the length of the resulting message
            length += context->recordIvLength + context->authTagLength;
            //Fix length field
            record->length = htons(length);

            //Increment sequence number
            tlsIncSequenceNumber(context->writeSeqNum);
         }
         else
#endif
         //Invalid cipher mode?
         {
            //The specified cipher mode is not supported
            return ERROR_UNSUPPORTED_CIPHER_MODE;
         }

         //Debug message
         TRACE_DEBUG("Encrypted record:\r\n");
         TRACE_DEBUG_ARRAY("  ", record, length + sizeof(TlsRecord));
      }
   }

   //Compute the length of the complete TLS record
   length += sizeof(TlsRecord);
   //Send TLS record
   return tlsIoWrite(context, record, length);
}
示例#23
0
error_t tlsReadRecord(TlsContext *context, uint8_t *data,
   size_t size, size_t *length, TlsContentType *contentType)
{
   error_t error;
   size_t i;
   size_t n;
   size_t paddingLength;
   TlsRecord record;

   //Read TLS record header
   error = tlsIoRead(context, &record, sizeof(TlsRecord));
   //Any error to report?
   if(error) return error;

   //Debug message
   TRACE_DEBUG("Record header:\r\n");
   TRACE_DEBUG_ARRAY("  ", &record, sizeof(record));

   //Check current state
   if(context->state > TLS_STATE_SERVER_HELLO)
   {
      //Once the server has sent the ServerHello message, enforce
      //incoming record versions
      if(ntohs(record.version) != context->version)
         return ERROR_VERSION_NOT_SUPPORTED;
   }

   //Convert the length field to host byte order
   n = ntohs(record.length);

   //Make sure that the buffer is large enough to hold the entire record
   if(n > size)
      return ERROR_RECORD_OVERFLOW;

   //Read record contents
   error = tlsIoRead(context, data, n);
   //Any error to report?
   if(error) return error;

   //Record payload is protected?
   if(context->changeCipherSpecReceived)
   {
      //Decrypt record if necessary
      if(context->cipherAlgo)
      {
         //Debug message
         TRACE_DEBUG("Encrypted record (%" PRIuSIZE " bytes):\r\n", n);
         TRACE_DEBUG_ARRAY("  ", data, n);

#if (TLS_STREAM_CIPHER_SUPPORT == ENABLED)
         //Stream cipher?
         if(context->cipherMode == CIPHER_MODE_STREAM)
         {
            //Decrypt record contents
            context->cipherAlgo->decryptStream(context->readCipherContext, data, data, n);
            //Debug message
            TRACE_DEBUG("Decrypted record (%" PRIuSIZE " bytes):\r\n", n);
            TRACE_DEBUG_ARRAY("  ", data, n);
         }
         else
#endif
#if (TLS_CBC_CIPHER_SUPPORT == ENABLED)
         //CBC block cipher?
         if(context->cipherMode == CIPHER_MODE_CBC)
         {
            //The length of the data must be a multiple of the block size
            if((n % context->cipherAlgo->blockSize) != 0)
               return ERROR_DECODING_FAILED;

            //CBC decryption
            error = cbcDecrypt(context->cipherAlgo,
               context->readCipherContext, context->readIv, data, data, n);
            //Any error to report?
            if(error) return error;

            //Debug message
            TRACE_DEBUG("Decrypted record (%" PRIuSIZE " bytes):\r\n", n);
            TRACE_DEBUG_ARRAY("  ", data, n);

#if (TLS_MAX_VERSION >= TLS_VERSION_1_1 && TLS_MIN_VERSION <= TLS_VERSION_1_2)
            //TLS 1.1 and 1.2 use an explicit IV
            if(context->version >= TLS_VERSION_1_1)
            {
               //Make sure the message length is acceptable
               if(n < context->recordIvLength)
                  return ERROR_DECODING_FAILED;

               //Adjust the length of the message
               n -= context->recordIvLength;
               //Discard the first cipher block (corresponding to the explicit IV)
               memmove(data, data + context->recordIvLength, n);
            }
#endif
            //Make sure the message length is acceptable
            if(n < context->cipherAlgo->blockSize)
               return ERROR_DECODING_FAILED;

            //Compute the length of the padding string
            paddingLength = data[n - 1];
            //Erroneous padding length?
            if(paddingLength >= n)
               return ERROR_BAD_RECORD_MAC;

            //The receiver must check the padding
            for(i = 0; i <= paddingLength; i++)
            {
               //Each byte in the padding data must be filled
               //with the padding length value
               if(data[n - 1 - i] != paddingLength)
                  return ERROR_BAD_RECORD_MAC;
            }

            //Remove padding bytes
            n -= paddingLength + 1;

            //Debug message
            TRACE_DEBUG("Padding removed (%" PRIuSIZE " bytes):\r\n", n);
            TRACE_DEBUG_ARRAY("  ", data, n);
         }
         else
#endif
#if (TLS_CCM_CIPHER_SUPPORT == ENABLED || TLS_GCM_CIPHER_SUPPORT == ENABLED)
         //AEAD cipher?
         if(context->cipherMode == CIPHER_MODE_CCM ||
            context->cipherMode == CIPHER_MODE_GCM)
         {
            uint8_t *ciphertext;
            uint8_t *tag;
            size_t nonceLength;
            uint8_t nonce[12];
            uint8_t a[13];

            //Make sure the message length is acceptable
            if(n < (context->recordIvLength + context->authTagLength))
               return ERROR_DECODING_FAILED;

            //Determine the total length of the nonce
            nonceLength = context->fixedIvLength + context->recordIvLength;
            //The salt is the implicit part of the nonce and is not sent in the packet
            memcpy(nonce, context->readIv, context->fixedIvLength);
            //The explicit part of the nonce is chosen by the sender
            memcpy(nonce + context->fixedIvLength, data, context->recordIvLength);

            //Calculate the length of the ciphertext
            n -= context->recordIvLength + context->authTagLength;
            //Fix the length field of the TLS record
            record.length = htons(n);

            //Additional data to be authenticated
            memcpy(a, context->readSeqNum, sizeof(TlsSequenceNumber));
            memcpy(a + sizeof(TlsSequenceNumber), &record, sizeof(TlsRecord));

            //Ciphertext data
            ciphertext = data + context->recordIvLength;
            //Authentication tag
            tag = ciphertext + n;

#if (TLS_CCM_CIPHER_SUPPORT == ENABLED)
            //CCM cipher mode?
            if(context->cipherMode == CIPHER_MODE_CCM)
            {
               //Decryption and verification (using CCM)
               error = ccmDecrypt(context->cipherAlgo, context->readCipherContext, nonce,
                  nonceLength, a, 13, ciphertext, ciphertext, n, tag, context->authTagLength);
            }
            else
#endif
#if (TLS_GCM_CIPHER_SUPPORT == ENABLED)
            //GCM cipher mode?
            if(context->cipherMode == CIPHER_MODE_GCM)
            {
               //Decryption and verification (using GCM)
               error = gcmDecrypt(context->cipherAlgo, context->readCipherContext, nonce,
                  nonceLength, a, 13, ciphertext, ciphertext, n, tag, context->authTagLength);
            }
            else
#endif
            //Invalid cipher mode?
            {
               //The specified cipher mode is not supported
               error = ERROR_UNSUPPORTED_CIPHER_MODE;
            }

            //Wrong authentication tag?
            if(error) return ERROR_BAD_RECORD_MAC;

            //Discard the explicit part of the nonce
            memmove(data, data + context->recordIvLength, n);

            //Debug message
            TRACE_DEBUG("Decrypted record (%" PRIuSIZE " bytes):\r\n", n);
            TRACE_DEBUG_ARRAY("  ", data, n);

            //Increment sequence number
            tlsIncSequenceNumber(context->readSeqNum);
         }
         else
#endif
         //Invalid cipher mode?
         {
            //The specified cipher mode is not supported
            return ERROR_UNSUPPORTED_CIPHER_MODE;
         }
      }

      //Check message authentication code if necessary
      if(context->hashAlgo)
      {
         //Make sure the message length is acceptable
         if(n < context->hashAlgo->digestSize)
            return ERROR_DECODING_FAILED;

         //Adjust the length of the message
         n -= context->hashAlgo->digestSize;
         //Fix the length field of the TLS record
         record.length = htons(n);

#if (TLS_MAX_VERSION >= SSL_VERSION_3_0 && TLS_MIN_VERSION <= SSL_VERSION_3_0)
         //Check whether SSL 3.0 is currently used
         if(context->version == SSL_VERSION_3_0)
         {
            //SSL 3.0 uses an older obsolete version of the HMAC construction
            error = sslComputeMac(context, context->readMacKey,
               context->readSeqNum, &record, data, n, context->hmacContext.digest);
            //Any error to report?
            if(error) return error;
         }
         else
#endif
#if (TLS_MAX_VERSION >= TLS_VERSION_1_0 && TLS_MIN_VERSION <= TLS_VERSION_1_2)
         //Check whether TLS 1.0, TLS 1.1 or TLS 1.2 is currently used
         if(context->version >= TLS_VERSION_1_0)
         {
            //TLS uses a HMAC construction
            hmacInit(&context->hmacContext, context->hashAlgo, context->readMacKey, context->macKeyLength);
            //Compute MAC over the sequence number and the record contents
            hmacUpdate(&context->hmacContext, context->readSeqNum, sizeof(TlsSequenceNumber));
            hmacUpdate(&context->hmacContext, &record, sizeof(TlsRecord));
            hmacUpdate(&context->hmacContext, data, n);
            hmacFinal(&context->hmacContext, NULL);
         }
         else
#endif
         //The negotiated TLS version is not valid...
         {
            //Report an error
            return ERROR_INVALID_VERSION;
         }

         //Debug message
         TRACE_DEBUG("Read sequence number:\r\n");
         TRACE_DEBUG_ARRAY("  ", context->readSeqNum, sizeof(TlsSequenceNumber));
         TRACE_DEBUG("Computed MAC:\r\n");
         TRACE_DEBUG_ARRAY("  ", context->hmacContext.digest, context->hashAlgo->digestSize);

         //Check the message authentication code
         if(memcmp(data + n, context->hmacContext.digest, context->hashAlgo->digestSize))
            return ERROR_BAD_RECORD_MAC;

         //Increment sequence number
         tlsIncSequenceNumber(context->readSeqNum);
      }
   }

   //Actual length of the record data
   *length = n;
   //Record type
   *contentType = (TlsContentType) record.type;

   //The TLS record has been successfully read
   return NO_ERROR;
}
示例#24
0
error_t rsassaPkcs1v15Sign(const RsaPrivateKey *key, const HashAlgo *hash,
   const uint8_t *digest, uint8_t *signature, size_t *signatureLength)
{
   error_t error;
   uint_t k;
   uint8_t *em;
   Mpi m;
   Mpi s;

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

   //Debug message
   TRACE_DEBUG("RSA PKCS #1 v1.5 signature generation...\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("  Message digest:\r\n");
   TRACE_DEBUG_ARRAY("    ", digest, hash->digestSize);

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

   //Get the length in octets of the modulus n
   k = mpiGetByteLength(&key->n);
   //Point to the buffer where the encoded message EM will be generated
   em = signature;

   //Apply the EMSA-PKCS1-v1.5 encoding operation
   error = emsaPkcs1v15Encode(hash, digest, em, k);
   //Any error to report?
   if(error) return error;

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

   //Start of exception handling block
   do
   {
      //Convert the encoded message EM to an integer message representative m
      error = mpiReadRaw(&m, em, k);
      //Conversion failed?
      if(error) break;

      //Apply the RSASP1 signature primitive
      error = rsasp1(key, &m, &s);
      //Any error to report?
      if(error) break;

      //Convert the signature representative s to a signature of length k octets
      error = mpiWriteRaw(&s, signature, k);
      //Conversion failed?
      if(error) break;

      //Length of the resulting signature
      *signatureLength = k;

      //Debug message
      TRACE_DEBUG("  Signature:\r\n");
      TRACE_DEBUG_ARRAY("    ", signature, *signatureLength);

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

   //Free previously allocated memory
   mpiFree(&m);
   mpiFree(&s);

   //Return status code
   return error;
}
示例#25
0
error_t rsaesPkcs1v15Encrypt(const PrngAlgo *prngAlgo, void *prngContext, const RsaPublicKey *key,
   const uint8_t *message, size_t messageLength, uint8_t *ciphertext, size_t *ciphertextLength)
{
   error_t error;
   uint_t i;
   uint_t j;
   uint_t k;
   uint_t n;
   uint8_t *p;
   Mpi m;
   Mpi c;

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

   //Debug message
   TRACE_DEBUG("RSA PKCS #1 v1.5 encryption...\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:\r\n");
   TRACE_DEBUG_ARRAY("    ", message, messageLength);

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

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

   //Check the length of the message
   if((messageLength + 11) > k)
      return ERROR_INVALID_LENGTH;

   //Point to the buffer where the encoded message EM will be formatted
   p = ciphertext;

   //The leading 0x00 octet ensures that the encoded message,
   //converted to an integer, is less than the modulus
   *(p++) = 0x00;
   //For a public-key operation, the block type BT shall be 0x02
   *(p++) = 0x02;

   //Length of the padding string PS
   n = k - messageLength - 3;

   //Generate the padding string (pseudo-randomly generated non-zero octets)
   while(n > 0)
   {
      //Generate random data
      error = prngAlgo->read(prngContext, p, n);
      //Any error to report?
      if(error) return error;

      //Parse the resulting octet string
      for(i = 0, j = 0; j < n; j++)
      {
         //Strip any byte with a value of zero
         if(p[j] != 0)
            p[i++] = p[j];
      }

      //Advance data pointer
      p += i;
      n -= i;
   }

   //Append a 0x00 octet to the padding string
   *(p++) = 0x00;
   //Copy the message to be encrypted
   memcpy(p, message, messageLength);

   //Rewind to the beginning of the encoded message
   p = ciphertext;

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

   //Start of exception handling block
   do
   {
      //Convert the encoded message EM to an integer message representative m
      error = mpiReadRaw(&m, p, k);
      //Conversion failed?
      if(error) break;

      //Apply the RSAEP encryption primitive
      error = rsaep(key, &m, &c);
      //Any error to report?
      if(error) break;

      //Convert the ciphertext representative c to a ciphertext of length k octets
      error = mpiWriteRaw(&c, ciphertext, k);
      //Conversion failed?
      if(error) break;

      //Length of the resulting ciphertext
      *ciphertextLength = k;

      //Debug message
      TRACE_DEBUG("  Ciphertext:\r\n");
      TRACE_DEBUG_ARRAY("    ", ciphertext, *ciphertextLength);

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

   //Free previously allocated memory
   mpiFree(&m);
   mpiFree(&c);

   //Return status code
   return error;
}
示例#26
0
error_t dhcpDumpMessage(const DhcpMessage *message, size_t length)
{
   error_t error;
   uint_t i;
   const char_t *label;
   DhcpOption *option;

   //Ensure the length of the DHCP message is acceptable
   if(length < sizeof(DhcpMessage))
   {
      //Report a warning
      TRACE_WARNING("DHCP message length is invalid!\r\n");
      //Dump message contents for debugging purpose
      TRACE_DEBUG_ARRAY("  ", message, length);
      //Report an error
      return ERROR_INVALID_LENGTH;
   }

   //Retrieve the name associated with the opcode
   label = (message->op < arraysize(opcodeLabel)) ? opcodeLabel[message->op] : "";

   //Dump DHCP message contents
   TRACE_DEBUG("  Op Code (op) = %" PRIu8 " (%s)\r\n", message->op, label);
   TRACE_DEBUG("  Hardware Type (htype) = %" PRIu8 "\r\n", message->htype);
   TRACE_DEBUG("  Hardware Address Length (hlen) = %" PRIu8 "\r\n", message->hlen);
   TRACE_DEBUG("  Hops (hops) = %" PRIu8 "\r\n", message->hops);
   TRACE_DEBUG("  Transaction ID (xid) = 0x%08" PRIX32 "\r\n", ntohl(message->xid));
   TRACE_DEBUG("  Seconds (secs) = %" PRIu16 "s\r\n", ntohs(message->secs));
   TRACE_DEBUG("  Flags (flags) = 0x%04" PRIX16 "\r\n", ntohs(message->flags));
   TRACE_DEBUG("  Client IP Address (ciaddr) = %s\r\n", ipv4AddrToString(message->ciaddr, NULL));
   TRACE_DEBUG("  Your IP Address (yiaddr) = %s\r\n", ipv4AddrToString(message->yiaddr, NULL));
   TRACE_DEBUG("  Server IP Address (siaddr) = %s\r\n", ipv4AddrToString(message->siaddr, NULL));
   TRACE_DEBUG("  Relay IP Address (giaddr) = %s\r\n", ipv4AddrToString(message->giaddr, NULL));
   TRACE_DEBUG("  Client Hardware Address (chaddr) = %s\r\n", macAddrToString(&message->chaddr, NULL));
   TRACE_DEBUG("  Magic Cookie = 0x%08" PRIX32 "\r\n", ntohl(message->magicCookie));

   //Get the length of the options field
   length -= sizeof(DhcpMessage);

   //Parse DHCP options
   for(i = 0; i < length; i++)
   {
      //Point to the current option
      option = (DhcpOption *) (message->options + i);

      //Pad option detected?
      if(option->code == DHCP_OPT_PAD)
         continue;
      //End option detected?
      if(option->code == DHCP_OPT_END)
         break;
      //Check option length
      if((i + 1) >= length || (i + 1 + option->length) >= length)
      {
         //Report a warning
         TRACE_WARNING("DHCP option length is invalid!\r\n");
         //Dump message contents for debugging purpose
         TRACE_DEBUG_ARRAY("  ", message, length);
         //Report an error
         return ERROR_INVALID_LENGTH;
      }

      //Display the name of the current option
      if(option->code < arraysize(optionLabel))
         TRACE_DEBUG("  %s option (%" PRIu8 " bytes)\r\n", optionLabel[option->code], option->length);
      else
         TRACE_DEBUG("  Option %" PRIu8 " (%" PRIu8 " bytes)\r\n", option->code, option->length);

      //Check option code
      switch(option->code)
      {
      //Message type?
      case DHCP_OPT_DHCP_MESSAGE_TYPE:
         error = dhcpDumpMessageType(option);
         break;
      //Parameter Request List option
      case DHCP_OPT_PARAM_REQUEST_LIST:
         error = dhcpDumpParamRequestList(option);
         break;
      //Boolean value?
      case DHCP_OPT_IP_FORWARDING:
      case DHCP_OPT_NON_LOCAL_SOURCE_ROUTING:
      case DHCP_OPT_ALL_SUBNETS_ARE_LOCAL:
      case DHCP_OPT_PERFORM_MASK_DISCOVERY:
      case DHCP_OPT_MASK_SUPPLIER:
      case DHCP_OPT_PERFORM_ROUTER_DISCOVERY:
      case DHCP_OPT_TRAILER_ENCAPSULATION:
      case DHCP_OPT_ETHERNET_ENCAPSULATION:
      case DHCP_OPT_TCP_KEEPALIVE_GARBAGE:
         error = dhcpDumpBoolean(option);
         break;
      //8-bit unsigned integer?
      case DHCP_OPT_DEFAULT_IP_TTL:
      case DHCP_OPT_TCP_DEFAULT_TTL:
      case DHCP_OPT_NETBIOS_NODE_TYPE:
      case DHCP_OPT_OPTION_OVERLOAD:
         error = dhcpDumpInt8(option);
         break;
      //16-bit unsigned integer?
      case DHCP_OPT_BOOT_FILE_SIZE:
      case DHCP_OPT_MAX_DATAGRAM_REASSEMBLY_SIZE:
      case DHCP_OPT_INTERFACE_MTU:
      case DHCP_OPT_MAX_DHCP_MESSAGE_SIZE:
         error = dhcpDumpInt16(option);
         break;
      //32-bit unsigned integer?
      case DHCP_OPT_PATH_MTU_AGING_TIMEOUT:
      case DHCP_OPT_ARP_CACHE_TIMEOUT:
      case DHCP_OPT_TCP_KEEPALIVE_INTERVAL:
      case DHCP_OPT_IP_ADDRESS_LEASE_TIME:
      case DHCP_OPT_RENEWAL_TIME_VALUE:
      case DHCP_OPT_REBINDING_TIME_VALUE:
         error = dhcpDumpInt32(option);
         break;
      //Character strings?
      case DHCP_OPT_HOST_NAME:
      case DHCP_OPT_MERIT_DUMP_FILE:
      case DHCP_OPT_DOMAIN_NAME:
      case DHCP_OPT_ROOT_PATH:
      case DHCP_OPT_EXTENSIONS_PATH:
      case DHCP_OPT_NIS_DOMAIN:
      case DHCP_OPT_MESSAGE:
      case DHCP_OPT_NISP_DOMAIN:
      case DHCP_OPT_TFTP_SERVER_NAME:
      case DHCP_OPT_BOOTFILE_NAME:
         error = dhcpDumpString(option);
         break;
      //IPv4 address?
      case DHCP_OPT_SUBNET_MASK:
      case DHCP_OPT_SWAP_SERVER:
      case DHCP_OPT_BROADCAST_ADDRESS:
      case DHCP_OPT_ROUTER_SOLICITATION_ADDRESS:
      case DHCP_OPT_REQUESTED_IP_ADDRESS:
      case DHCP_OPT_SERVER_IDENTIFIER:
         error = dhcpDumpIpv4Addr(option);
         break;
      //List of IPv4 addresses?
      case DHCP_OPT_ROUTER:
      case DHCP_OPT_TIME_SERVER:
      case DHCP_OPT_NAME_SERVER:
      case DHCP_OPT_DNS_SERVER:
      case DHCP_OPT_LOG_SERVER:
      case DHCP_OPT_COOKIE_SERVER:
      case DHCP_OPT_LPR_SERVER:
      case DHCP_OPT_IMPRESS_SERVER:
      case DHCP_OPT_RESOURCE_LOCATION_SERVER:
      case DHCP_OPT_NIS_SERVER:
      case DHCP_OPT_NTP_SERVER:
      case DHCP_OPT_NETBIOS_NBNS_SERVER:
      case DHCP_OPT_NETBIOS_NBDD_SERVER:
      case DHCP_OPT_X11_FONT_SERVER:
      case DHCP_OPT_X11_DISPLAY_MANAGER:
      case DHCP_OPT_NISP_SERVER:
      case DHCP_OPT_MOBILE_IP_HOME_AGENT:
      case DHCP_OPT_SMTP_SERVER:
      case DHCP_OPT_POP3_SERVER:
      case DHCP_OPT_NNTP_SERVER:
      case DHCP_OPT_DEFAULT_WWW_SERVER:
      case DHCP_OPT_DEFAULT_FINGER_SERVER:
      case DHCP_OPT_DEFAULT_IRC_SERVER:
      case DHCP_OPT_STREETTALK_SERVER:
      case DHCP_OPT_STDA_SERVER:
         error = dhcpDumpIpv4AddrList(option);
         break;
      //Raw data?
      default:
         error = dhcpDumpRawData(option);
         break;
      }

      //Failed to parse current option?
      if(error)
      {
         //Report a warning
         TRACE_WARNING("Failed to parse DHCP options!\r\n");
         //Dump message contents for debugging purpose
         TRACE_DEBUG_ARRAY("  ", message, length);
      }

      //Jump to the next option
      i += option->length + 1;
   }

   //No error to report
   return NO_ERROR;
}
示例#27
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;
}
示例#28
0
error_t tlsSendCertificate(TlsContext *context)
{
   error_t error;
   bool_t sendCert;
   uint8_t *p;
   size_t length;
   const char_t *pemCert;
   size_t pemCertLength;
   uint8_t *derCert;
   size_t derCertSize;
   size_t derCertLength;
   TlsCertificate *message;

   //TLS operates as a client or a server?
   if(context->entity == TLS_CONNECTION_END_CLIENT)
   {
      //The client must send a Certificate message if the server requests it
      sendCert = context->clientCertRequested ? TRUE : FALSE;

#if (TLS_MAX_VERSION >= SSL_VERSION_3_0 && TLS_MIN_VERSION <= SSL_VERSION_3_0)
      //SSL 3.0 currently selected?
      if(context->version == SSL_VERSION_3_0)
      {
         //The server requests a certificate but no suitable certificate is available?
         if(sendCert && context->cert == NULL)
         {
            //The client should send a no_certificate alert instead
            error = tlsSendAlert(context, TLS_ALERT_LEVEL_WARNING, TLS_ALERT_NO_CERTIFICATE);
            //Any error to report?
            if(error) return error;

            //Skip Certificate message...
            sendCert = FALSE;
         }
      }
#endif
   }
   else
   {
      //The server must send a Certificate message whenever the agreed-upon
      //key exchange method uses certificates for authentication
      sendCert = (context->cert != NULL) ? TRUE : FALSE;
   }

   //Check whether a Certificate message must be sent
   if(sendCert)
   {
      //Buffer where to format the message
      p = context->txBuffer + sizeof(TlsRecord);

      //Point to the Certificate message
      message = (TlsCertificate *) p;
      //Format message header
      message->msgType = TLS_TYPE_CERTIFICATE;

      //Point to the first certificate of the list
      p = message->certificateList;
      //Length of the certificate list in bytes
      length = 0;

      //Check whether a certificate is available
      if(context->cert != NULL)
      {
         //Point to the certificate chain
         pemCert = context->cert->certChain;
         //Get the total length, in bytes, of the certificate chain
         pemCertLength = context->cert->certChainLength;
      }
      else
      {
         //If no suitable certificate is available, the message
         //contains an empty certificate list
         pemCert = NULL;
         pemCertLength = 0;
      }

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

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

         //Total length of the certificate list
         length += derCertLength + 3;

         //Prevent the buffer from overflowing
         if((length + sizeof(TlsCertificate)) > TLS_MAX_PROTOCOL_DATA_LENGTH)
            return ERROR_MESSAGE_TOO_LONG;

         //Each certificate is preceded by a 3-byte length field
         STORE24BE(derCertLength, p);
         //Copy the current certificate
         memcpy(p + 3, derCert, derCertLength);

         //Advance data pointer
         p += derCertLength + 3;
      }

      //Free previously allocated memory
      osFreeMem(derCert);

      //A 3-byte length field shall precede the certificate list
      STORE24BE(length, message->certificateListLength);
      //Consider the 3-byte length field
      length += 3;

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

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

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

   //Update FSM state
   context->state = (context->entity == TLS_CONNECTION_END_CLIENT) ?
      TLS_STATE_CLIENT_KEY_EXCHANGE : TLS_STATE_SERVER_KEY_EXCHANGE;

   //Successful processing
   return NO_ERROR;
}
示例#29
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;
}
示例#30
0
error_t dhcpv6DumpOptions(const uint8_t *options, size_t length, uint_t level)
{
   error_t error;
   uint_t i;
   Dhcpv6Option *option;

   //Check whether the maximum level of recursion is reached
   if(level >= 6)
   {
      //If the maximum level of recursion is reached, then dump contents
      TRACE_DEBUG(prefix[level], "Options (% bytes)\r\n", length);
      TRACE_DEBUG_ARRAY(prefix[level + 1], options, length);
      //Exit immediately
      return NO_ERROR;
   }

   //Parse DHCPv6 options
   for(i = 0; i < length; )
   {
      //Point to the current option
      option = (Dhcpv6Option *) (options + i);

      //Make sure the option is valid
      if((i + sizeof(Dhcpv6Option)) > length)
         return ERROR_INVALID_OPTION;
      //Check the length of the option data
      if((i + sizeof(Dhcpv6Option) + ntohs(option->length)) > length)
         return ERROR_INVALID_OPTION;

      //Check option code
      switch(ntohs(option->code))
      {
      //Client Identifier option
      case DHCPV6_OPTION_CLIENTID:
         error = dhcpv6DumpClientIdOption(option, level);
         break;
      //Server Identifier option
      case DHCPV6_OPTION_SERVERID:
         error = dhcpv6DumpServerIdOption(option, level);
         break;
      //IA_NA option
      case DHCPV6_OPTION_IA_NA:
         error = dhcpv6DumpIaNaOption(option, level);
         break;
      //IA_TA option
      case DHCPV6_OPTION_IA_TA:
         error = dhcpv6DumpIaTaOption(option, level);
         break;
      //IA Address option
      case DHCPV6_OPTION_IAADDR:
         error = dhcpv6DumpIaAddrOption(option, level);
         break;
      //Option Request option
      case DHCPV6_OPTION_ORO:
         error = dhcpv6DumpOroOption(option, level);
         break;
       //Preference option
      case DHCPV6_OPTION_PREFERENCE:
         error = dhcpv6DumpPreferenceOption(option, level);
         break;
      //Elapsed Time option
      case DHCPV6_OPTION_ELAPSED_TIME:
         error = dhcpv6DumpElapsedTimeOption(option, level);
         break;
      //Relay Message option
      case DHCPV6_OPTION_RELAY_MSG:
         error = dhcpv6DumpRelayMessageOption(option, level);
         break;
      //Authentication option
      case DHCPV6_OPTION_AUTH:
         error = dhcpv6DumpAuthOption(option, level);
         break;
      //Server Unicast option
      case DHCPV6_OPTION_UNICAST:
         error = dhcpv6DumpServerUnicastOption(option, level);
         break;
      //Status Code option
      case DHCPV6_OPTION_STATUS_CODE:
         error = dhcpv6DumpStatusCodeOption(option, level);
         break;
      //Rapid Commit option
      case DHCPV6_OPTION_RAPID_COMMIT:
         error = dhcpv6DumpRapidCommitOption(option, level);
         break;
      //User Class option
      case DHCPV6_OPTION_USER_CLASS:
         error = dhcpv6DumpUserClassOption(option, level);
         break;
      //Vendor Class option
      case DHCPV6_OPTION_VENDOR_CLASS:
         error = dhcpv6DumpVendorClassOption(option, level);
         break;
      //Vendor Specific Information option
      case DHCPV6_OPTION_VENDOR_OPTS:
         error = dhcpv6DumpVendorSpecificInfoOption(option, level);
         break;
      //Interface ID option
      case DHCPV6_OPTION_INTERFACE_ID:
         error = dhcpv6DumpInterfaceIdOption(option, level);
         break;
      //Reconfigure Message option
      case DHCPV6_OPTION_RECONF_MSG:
         error = dhcpv6DumpReconfMessageOption(option, level);
         break;
      //Reconfigure Accept option
      case DHCPV6_OPTION_RECONF_ACCEPT:
         error = dhcpv6DumpReconfAcceptOption(option, level);
         break;
      //DNS Recursive Name Server option
      case DHCPV6_OPTION_DNS_SERVERS:
         error = dhcpv6DumpDnsServersOption(option, level);
         break;
      //Domain Search List option
      case DHCPV6_OPTION_DOMAIN_LIST:
         error = dhcpv6DumpDomainListOption(option, level);
         break;
      //Unknown option...
      default:
         error = dhcpv6DumpGenericOption(option, level);
         break;
      }

      //Failed to parse current option?
      if(error) return error;

      //Jump to the next option
      i += sizeof(Dhcpv6Option) + ntohs(option->length);
   }

   //No error to report
   return NO_ERROR;

}