DTLS example using CyaSSL 2.7.0 and x509 certs. Doesn't work at present due to DTLS handshake failure. Debugging.

Dependencies:   NTPClient VodafoneUSBModem cyassl-lib mbed-rtos mbed-src

main.cpp

Committer:
ashleymills
Date:
2013-09-05
Revision:
0:35b690909566

File content as of revision 0:35b690909566:

#define __DEBUG__ 4 //Maximum verbosity
#ifndef __MODULE__
#define __MODULE__ "main.cpp"
#endif

#define DEBUG_CYASSL 1
#include "bsd_socket.h"
#include "mbed.h"
#include "rtos.h"
#include "dbg.h"
#include "cyassl/ssl.h"
#include "VodafoneUSBModem.h"
//#include "EthernetInterface.h"
#include "NTPClient.h"

#include "logging.h"

#define APN_GDSP

#ifdef APN_GDSP
   #define APN "ppinternetd.gdsp" 
   #define APN_USERNAME ""
   #define APN_PASSWORD ""
#endif

#ifdef APN_CONTRACT
   #define APN "internet" 
   #define APN_USERNAME "web"
   #define APN_PASSWORD "web"
#endif

#ifdef APN_PAYG
   #define APN "smart" 
   #define APN_USERNAME "web"
   #define APN_PASSWORD "web"
#endif

#include "certs/device_certificate.h"
#include "certs/device_private_key.h"
#include "certs/root_certificate.h"

#include <cyassl/ctaocrypt/types.h>


static INLINE unsigned int my_psk_client_cb(CYASSL* ssl, const char* hint,
        char* identity, unsigned int id_max_len, unsigned char* key,
        unsigned int key_max_len)
{
    (void)ssl;
    (void)hint;
    (void)key_max_len;
    
    DBG("PSK client callback callled.");
    
    // identity is OpenSSL testing default for openssl s_client, keep same
    strncpy(identity, "Client_identity", id_max_len);


    // test key in hex is 0x1a2b3c4d , in decimal 439,041,101 , we're using
    //   unsigned binary
    key[0] = 26;
    key[1] = 43;
    key[2] = 60;
    key[3] = 77;

    return 4;   // length of key in octets or 0 for error
}
/*

static INLINE unsigned int my_psk_server_cb(CYASSL* ssl, const char* identity,
        unsigned char* key, unsigned int key_max_len)
{
    (void)ssl;
    (void)key_max_len;


    DBG("PSK server callback called.");

    // identity is OpenSSL testing default for openssl s_client, keep same
    if (strncmp(identity, "Client_identity", 15) != 0)
        return 0;

    // test key in hex is 0x1a2b3c4d , in decimal 439,041,101 , we're using
    // unsigned binary
    key[0] = 26;
    key[1] = 43;
    key[2] = 60;
    key[3] = 77;

    return 4;   // length of key in octets or 0 for error
}
*/

sockaddr_in bindAddr,serverAddress;

bool connectToSocketUDP(char *ipAddress, int port, int *sockfd) {
  *sockfd = -1;
  // create the socket
  if((*sockfd=socket(AF_INET,SOCK_DGRAM,0))<0) {
     DBG("Error opening socket");
     return false;
  }
  socklen_t sockAddrInLen = sizeof(struct sockaddr_in);
   
  // bind socket to 11111
  memset(&bindAddr,  0x00, sockAddrInLen);
  bindAddr.sin_family = AF_INET; // IP family
  bindAddr.sin_port = htons(11111);
  bindAddr.sin_addr.s_addr = IPADDR_ANY; // 32 bit IP representation
  // call bind
  if(bind(*sockfd,(const struct sockaddr *)&bindAddr,sockAddrInLen)!=0) {
     DBG("Error binding socket");
     perror(NULL);
  }

  INFO("UDP socket created and bound to: %s:%d",inet_ntoa(bindAddr.sin_addr),ntohs(bindAddr.sin_port));
         
  // create the socket address

  memset(&serverAddress, 0x00, sizeof(struct sockaddr_in));
  serverAddress.sin_addr.s_addr = inet_addr(ipAddress);
  serverAddress.sin_family = AF_INET;
  serverAddress.sin_port = htons(port);

  // do socket connect
  //LOG("Connecting socket to %s:%d", inet_ntoa(serverAddress.sin_addr), ntohs(serverAddress.sin_port));
  if(connect(*sockfd, (const struct sockaddr *)&serverAddress, sizeof(serverAddress))<0) {
     shutdown(*sockfd,SHUT_RDWR);
     close(*sockfd);
     DBG("Could not connect");
     return false;
  }
  return true;
}

bool connectToSocket(char *ipAddress, int port, int *sockfd) {
  *sockfd = -1;
  // create the socket
  if((*sockfd=socket(AF_INET,SOCK_STREAM,0))<0) {
     DBG("Error opening socket");
     return false;
  }
         
  // create the socket address
  sockaddr_in serverAddress;
  std::memset(&serverAddress, 0, sizeof(struct sockaddr_in));
  serverAddress.sin_addr.s_addr = inet_addr(ipAddress);
  serverAddress.sin_family = AF_INET;
  serverAddress.sin_port = htons(port);

  // do socket connect
  //LOG("Connecting socket to %s:%d", inet_ntoa(serverAddress.sin_addr), ntohs(serverAddress.sin_port));
  if(connect(*sockfd, (const struct sockaddr *)&serverAddress, sizeof(serverAddress))<0) {
     shutdown(*sockfd,SHUT_RDWR);
     close(*sockfd);
     DBG("Could not connect");
     return false;
  }
  return true;
}
/*
int handshakeCallback(HandShakeInfo* hinfo) {
   DBG("Handshake callback called");
}
int timeoutCallback(TimeoutInfo *tinfo) {
   DBG("Timeout callback called");
}
*/


DigitalOut myled(LED1);
//#define INTERFACE EthernetInterface
#define INTERFACE VodafoneUSBModem

void printError(CYASSL *ssl, int resultCode) {
   int err = CyaSSL_get_error(ssl, resultCode);
   char errorString[80];
   CyaSSL_ERR_error_string(err, errorString);
   DBG("Error: CyaSSL_write %s", errorString);
}

void debugCallback(const int logLevel,const char *const logMessage) {
   DBG(logMessage);
}


int main() {
   DBG_INIT();
   DBG_SET_SPEED(115200);
   DBG_SET_NEWLINE("\r\n");
   DBG("\r\n\r\n\r\n\r\n");
   
   int ret = 0;
   
   // init modem
   INTERFACE modem;
   // connnect modem to cellular network
   DBG("connecting to network interface");
   if(modem.connect(APN,APN_USERNAME,APN_PASSWORD)!=0) {
      DBG("Error connecting to mobile network");
   }
   /*
   modem.init();
   if(modem.connect(10000)) {
      DBG("Error initialising ethernet interface");
   }
   */
   DBG("Connected to network interface");
   
   //DBG("IP: %s",modem.getIPAddress());
    
   // need to set the time before doing anything else
   NTPClient ntp;
   time_t currentTime = time(NULL);
   int obtainedTimeSuccessfully = false;
   // try 100 times and then just force a watchdog reboot
   for(int i=0; i<100; i++) {
      obtainedTimeSuccessfully = false;
   
      if(ntp.setTime("0.pool.ntp.org")==0) {
         // there is a bug from somewhere which results in a negative timestamp
         currentTime = time(NULL);
         if(currentTime>0) {
            obtainedTimeSuccessfully = true;
            INFO("Time set successfully, time is now (UTC): %s", ctime(&currentTime));
         }
      }
      if(obtainedTimeSuccessfully) {
         break;
      }
   }
   
    
   // set SSL method to SSL v3 (TLS v1.2)
   //CyaSSLv23_client_method();
     
   CyaSSL_Init();// Initialize CyaSSL
   if(CyaSSL_Debugging_ON()==0) {
      DBG("CyaSSL debugging enabled");
   } else {
      DBG("CyaSSL debugging not compiled in");
   }
   
   CyaSSL_SetLoggingCb(&debugCallback);

   

   // set client method
   
   // TLS
   //CYASSL_CTX* ctx = CyaSSL_CTX_new(CyaSSLv23_client_method());
   
   // DTLS
   CYASSL_METHOD* method = CyaDTLSv1_2_client_method();
   if(method == NULL) {
      // unable to get method
   }
   CYASSL_CTX* ctx;
   ctx = CyaSSL_CTX_new(method);
   if(ctx == NULL){
      DBG("CyaSSL_CTX_new error.\n");
      exit(EXIT_FAILURE);
   }
   
   DBG("Setup SSL context");
   
   

   
   // use pre-shared keys
   //CyaSSL_CTX_set_psk_client_callback(ctx,my_psk_client_cb);
   /*
   if(CyaSSL_CTX_load_verify_buffer(ctx, serverCert, strlen((const char*)serverCert),SSL_FILETYPE_PEM)==0) {
   DBG("loaded server cert OK");
   }*/

   
   // load certificates for CA and us
   // load CA cert
   ret = CyaSSL_CTX_load_verify_buffer(ctx,rootCertificate, rootCertificateLength,SSL_FILETYPE_ASN1);
   // load device cert
   ret = CyaSSL_CTX_use_certificate_buffer(ctx, deviceCertificate, deviceCertificateLength, SSL_FILETYPE_ASN1);
   // load device private key
   ret = CyaSSL_CTX_use_PrivateKey_buffer(ctx, devicePrivateKey, devicePrivateKeyLength, SSL_FILETYPE_ASN1);

   
   int sockfd = NULL;
   //if(!connectToSocketUDP("192.168.1.99", 11111, &sockfd)) {
   if(!connectToSocketUDP("95.47.118.120", 11111, &sockfd)) {
      DBG("Error connecting to socket");
   }
   
  /*
   // connect to SSL enabled webserver
   int sockfd = NULL;
   if(!connectToSocket("95.47.118.120", 11111, &sockfd)) {
      DBG("Error connecting to socket");
   }
   DBG("Connected to non-SSL socket");
   */
   
   // hook into SSL
   // Create CYASSL object
   CYASSL* ssl;
   ssl = CyaSSL_new(ctx);
   if(ssl == NULL) {
      DBG("CyaSSL_new error.");
      exit(EXIT_FAILURE);
   }
   DBG("CyaSSL_new OK");
   
   // setup callbacks for handshake failure
   /*
   Timeval timeout;
   timeout.tv_sec  = 5;
   timeout.tv_usec = 0;
   ret = CyaSSL_connect_ex(ssl, handshakeCallback, timeoutCallback, timeout);
   */
   
   // attach to socket
   DBG("Attaching CyaSSL to socket");
   CyaSSL_set_fd(ssl, sockfd);
   DBG("Attached CyaSSL to socket");
   
   // DTLS stuff
   ret = CyaSSL_dtls_set_peer(ssl, &serverAddress, sizeof(serverAddress));
   if(ret != SSL_SUCCESS) {
      // failed to set DTLS peer
      DBG("Failed to set DTLS peer");
   }
   
   ret = CyaSSL_dtls(ssl);
   if(ret) {
      // SSL session has been configured to use DTLS
      DBG("DTLS configured");
   } else {
      DBG("DTLS not configured");
   }
   
   
   
   DBG("Issuing CyaSSL_connect");
   int result = CyaSSL_connect(ssl);
   if(result!=SSL_SUCCESS) {
      DBG("CyaSSL_connect failed");
      printError(ssl,result);
   }
   DBG("CyaSSL_connect OK");
   
   result = CyaSSL_write(ssl,"onion",5);
   DBG("Wrote %d things",result);
   if(result<0) {
      printError(ssl,result);
   }
   
    char buffer[200];
    int d =0;
    if((d=CyaSSL_read(ssl, &buffer, 200))>0) {
       DBG("Received %d bytes: %s",d,buffer);
    }
   
   // clean up
   CyaSSL_CTX_free(ctx);
   CyaSSL_Cleanup();  
   
}