예제 #1
0
error_t dhcpv6DumpRelayMessageOption(const Dhcpv6Option *option, uint_t level)
{
   uint8_t type;
   const char_t *label;

   //Check the length of the option
   if(!ntohs(option->length))
      return ERROR_INVALID_OPTION;

   //Retrieve the message type
   type = option->value[0];
   //Get the corresponding label
   label = (type < arraysize(messageLabel)) ? messageLabel[type] : "Unknown";

   //Relay agent/server message?
   if(type == DHCPV6_MSG_TYPE_RELAY_FORW || type == DHCPV6_MSG_TYPE_RELAY_REPL)
   {
      //Get the inner message
      const Dhcpv6RelayMessage *message = (Dhcpv6RelayMessage *) option->value;

      //Ensure the length of the DHCPv6 message is acceptable
      if(ntohs(option->length) < sizeof(Dhcpv6RelayMessage))
         return ERROR_INVALID_OPTION;

      //Dump message header
      TRACE_DEBUG("%sRelay Message option (%u bytes)\r\n", prefix[level], ntohs(option->length));
      TRACE_DEBUG("%sMessage Type = %u (%s)\r\n", prefix[level + 1], message->msgType, label);
      TRACE_DEBUG("%sHop Count = %u\r\n", prefix[level + 1], message->hopCount);
      TRACE_DEBUG("%sLink Address = %s\r\n", prefix[level + 1], ipv6AddrToString(&message->linkAddress, NULL));
      TRACE_DEBUG("%sPeer Address = %s\r\n", prefix[level + 1], ipv6AddrToString(&message->peerAddress, NULL));

      //Dump message options
      return dhcpv6DumpOptions(message->options, ntohs(option->length) - sizeof(Dhcpv6RelayMessage), level + 1);
   }
   //Client/server message?
   else
   {
      //Get the inner message
      const Dhcpv6Message *message = (Dhcpv6Message *) option->value;

      //Ensure the length of the DHCPv6 message is acceptable
      if(ntohs(option->length) < sizeof(Dhcpv6Message))
         return ERROR_INVALID_OPTION;

      //Dump message header
      TRACE_DEBUG("%sRelay Message option (%u bytes)\r\n", prefix[level], ntohs(option->length));
      TRACE_DEBUG("%sMessage Type = %u (%s)\r\n", prefix[level + 1], message->msgType, label);
      TRACE_DEBUG("%sTransaction ID = 0x%06X\r\n", prefix[level + 1], LOAD24BE(message->transactionId));

      //Dump message options
      return dhcpv6DumpOptions(message->options, ntohs(option->length) - sizeof(Dhcpv6Message), level + 1);
   }
}
예제 #2
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;
}
예제 #3
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;
}
예제 #4
0
error_t tlsReadProtocolData(TlsContext *context,
   void **data, size_t *length, TlsContentType *contentType)
{
   error_t error;
   size_t n;
   TlsContentType type;
   TlsHandshake *message;

   //Clear status code
   error = NO_ERROR;

   //Fragment reassembly process
   do
   {
      //Empty receive buffer?
      if(context->rxBufferLength == 0)
      {
         //Read a TLS record
         error = tlsReadRecord(context, context->rxBuffer, TLS_RX_BUFFER_SIZE, &n, &type);
         //Any error to report?
         if(error) return error;

         //Save record type
         context->rxBufferType = type;
         //Number of bytes available for reading
         context->rxBufferLength = n;
         //Rewind to the beginning of the buffer
         context->rxBufferReadIndex = 0;
         //Set write index
         context->rxBufferWriteIndex = context->rxBufferLength;
      }
      //Imcomplete message received?
      else if(error == ERROR_MORE_DATA_REQUIRED)
      {
         //Make room at the end of the buffer
         if(context->rxBufferReadIndex > 0)
         {
            //Move unread data to the beginning of the buffer
            memmove(context->rxBuffer, context->rxBuffer +
               context->rxBufferReadIndex, context->rxBufferLength);

            //Rewind to the beginning of the buffer
            context->rxBufferReadIndex = 0;
            //Set write index
            context->rxBufferWriteIndex = context->rxBufferLength;
         }

         //Read a TLS record
         error = tlsReadRecord(context, context->rxBuffer + context->rxBufferWriteIndex,
            TLS_RX_BUFFER_SIZE - context->rxBufferLength, &n, &type);
         //Any error to report?
         if(error) return error;

         //Fragmented records with mixed types cannot be interleaved
         if(type != context->rxBufferType)
            return ERROR_UNEXPECTED_MESSAGE;

         //Number of bytes available for reading
         context->rxBufferLength += n;
         //Update write index
         context->rxBufferWriteIndex += n;
      }

      //Handshake message received?
      if(context->rxBufferType == TLS_TYPE_HANDSHAKE)
      {
         //A message may be fragmented across several records
         if(context->rxBufferLength < sizeof(TlsHandshake))
         {
            //Read an additional record
            error = ERROR_MORE_DATA_REQUIRED;
         }
         else
         {
            //Point to the handshake message
            message = (TlsHandshake *) (context->rxBuffer + context->rxBufferReadIndex);
            //Retrieve the length of the handshake message
            n = sizeof(TlsHandshake) + LOAD24BE(message->length);

            //A message may be fragmented across several records
            if(context->rxBufferLength < n)
            {
               //Read an additional record
               error = ERROR_MORE_DATA_REQUIRED;
            }
            else
            {
               //Pass the handshake message to the higher layer
               error = NO_ERROR;
            }
         }
      }
      //ChangeCipherSpec message received?
      else if(context->rxBufferType == TLS_TYPE_CHANGE_CIPHER_SPEC)
      {
         //A message may be fragmented across several records
         if(context->rxBufferLength < sizeof(TlsChangeCipherSpec))
         {
            //Read an additional record
            error = ERROR_MORE_DATA_REQUIRED;
         }
         else
         {
            //Length of the ChangeCipherSpec message
            n = sizeof(TlsChangeCipherSpec);
            //Pass the ChangeCipherSpec message to the higher layer
            error = NO_ERROR;
         }
      }
      //Alert message received?
      else if(context->rxBufferType == TLS_TYPE_ALERT)
      {
         //A message may be fragmented across several records
         if(context->rxBufferLength < sizeof(TlsAlert))
         {
            //Read an additional record
            error = ERROR_MORE_DATA_REQUIRED;
         }
         else
         {
            //Length of the Alert message
            n = sizeof(TlsAlert);
            //Pass the Alert message to the higher layer
            error = NO_ERROR;
         }
      }
      //Application data received?
      else if(context->rxBufferType == TLS_TYPE_APPLICATION_DATA)
      {
         //Length of the application data
         n = context->rxBufferLength;
         //Pass the application data to the higher layer
         error = NO_ERROR;
      }
      //Unknown content type?
      else
      {
         //Report an error
         error = ERROR_UNEXPECTED_MESSAGE;
      }

      //Read as many records as necessary to reassemble the data
   } while(error == ERROR_MORE_DATA_REQUIRED);

   //Successful processing?
   if(!error)
   {
      //Pointer to the received data
      *data = context->rxBuffer + context->rxBufferReadIndex;
      //Length, in byte, of the data
      *length = n;
      //Protocol type
      *contentType = context->rxBufferType;
   }

   //Return status code
   return error;
}
예제 #5
0
error_t dhcpv6DumpMessage(const void *message, size_t length)
{
   error_t error;
   uint8_t type;
   const char_t *label;

   //Empty message?
   if(!length)
      return ERROR_INVALID_LENGTH;

   //Retrieve the message type
   type = *((uint8_t *) message);
   //Get the corresponding label
   label = (type < arraysize(messageLabel)) ? messageLabel[type] : "Unknown";

   //Relay agent/server message?
   if(type == DHCPV6_MSG_TYPE_RELAY_FORW || type == DHCPV6_MSG_TYPE_RELAY_REPL)
   {
      //Ensure the length of the DHCPv6 message is acceptable
      if(length < sizeof(Dhcpv6RelayMessage))
      {
         //Report an error
         error = ERROR_INVALID_LENGTH;
      }
      else
      {
         //Point to the DHCPv6 message
         const Dhcpv6RelayMessage *relayMessage = message;

         //Dump message header
         TRACE_DEBUG("  Message Type = %u (%s)\r\n", relayMessage->msgType, label);
         TRACE_DEBUG("  Hop Count = %u\r\n", relayMessage->hopCount);
         TRACE_DEBUG("  Link Address = %s\r\n", ipv6AddrToString(&relayMessage->linkAddress, NULL));
         TRACE_DEBUG("  Peer Address = %s\r\n", ipv6AddrToString(&relayMessage->peerAddress, NULL));

         //Dump message options
         error = dhcpv6DumpOptions(relayMessage->options, length - sizeof(Dhcpv6RelayMessage), 1);
      }

   }
   //Client/server message?
   else
   {
      //Ensure the length of the DHCPv6 message is acceptable
      if(length < sizeof(Dhcpv6Message))
      {
         //Report an error
         error = ERROR_INVALID_LENGTH;
      }
      else
      {
         //Point to the DHCPv6 message
         const Dhcpv6Message *clientMessage = message;

         //Dump message header
         TRACE_DEBUG("  Message Type = %u (%s)\r\n", clientMessage->msgType, label);
         TRACE_DEBUG("  Transaction ID = 0x%06X\r\n", LOAD24BE(clientMessage->transactionId));

         //Dump message options
         error = dhcpv6DumpOptions(clientMessage->options, length - sizeof(Dhcpv6Message), 1);
      }
   }

   //Did we encounter an error?
   if(error)
   {
      //Debug message
      TRACE_WARNING("DHCPv6 message is not valid!\r\n");
      //Dump message contents for debugging purpose
      TRACE_DEBUG_ARRAY("  ", message, length);
   }

   //Return status code
   return error;
}