Advertisement
phoenixdigital

HTTPS Library

Oct 28th, 2016
115
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 15.37 KB | None | 0 0
  1. /*
  2.   This file follows client.c from matrixSSL-3.7.2b closely to make a post/
  3.   get using https. It is also inspired by the httpclient library available
  4.   on github for the particle photon
  5.   (https://github.com/nmattisson/HttpClient)
  6.  */
  7. // WARNING WARNING WARNING:
  8. // This is for test purposes only, the RSA keys included in header files are SAMPLE
  9. // If you use these keys in production, an attacker can de-crypt your data, and look
  10. // at it, and you might as well have been using http without https.
  11.  
  12. #include "httpsclient-particle.h"
  13. #ifdef ID_RSA
  14. #include "2048_RSA.h"
  15. #include "2048_RSA_KEY.h"
  16. #include "ALL_RSA_CAS.h"
  17. #endif
  18.  
  19. uint32_t freemem;
  20.  
  21. int32 rc, CAstreamLen, i;
  22. sslKeys_t *keys;
  23. sslSessionId_t *sid;
  24. //struct g_sslstats stats;
  25. unsigned char *CAstream;
  26. tlsExtension_t *extension;
  27. int32 len, sessionFlag, extLen;
  28. ssl_t *ssl;
  29. unsigned char *g_buf, *ext;
  30. sslSessOpts_t options;
  31.  
  32. const int g_key_len = 2048;
  33. uint32 g_cipher[1] = {60};
  34. const int g_ciphers = 1;
  35. // INFO: Turns out it's a huge deal to make this >= 3000.
  36. //       The TCPClient really does take >2000ms to give us a packet for some reason?!!
  37. const uint16_t TIMEOUT = 20000;
  38. unsigned char * g_httpRequestHdr;
  39. const char end_header[] = "\r\n\r\n";
  40.  
  41. // TODO: Complete HACK, is it necessary to know how many bytes to expect from
  42. //       the server?
  43. uint32 g_bytes_requested = 100000;
  44.  
  45. #ifdef ID_RSA
  46. int32 loadRsaKeys(uint32 key_len, sslKeys_t *keys,
  47.              unsigned char *CAstream, int32 CAstreamLen) {
  48.   int32 rc;
  49. // INFO: 2048 is just good enough for now
  50.   if (true) Serial.println("Using 2048 bit RSA private key");
  51.   rc = matrixSslLoadRsaKeysMem(keys, RSA2048, sizeof(RSA2048), RSA2048KEY,
  52.                    sizeof(RSA2048KEY), CAstream, CAstreamLen);
  53.   if (rc < 0) {
  54.     if (true) _psTrace("No certificate material loaded.  Exiting");
  55.     if (CAstream) {
  56.       psFree(CAstream, NULL);
  57.     }
  58.     matrixSslDeleteKeys(keys);
  59.     matrixSslClose();
  60.   }
  61.  
  62.   return rc;
  63. }
  64. #endif
  65.  
  66. const char * g_host;
  67. const char * g_path;
  68.  
  69. void httpsclientSetPath(const char * path) {
  70.   g_path = path;
  71. }
  72.  
  73. int httpsclientSetup(const char * host, const char * path) {
  74.     if (true) Serial.println("MatrixSSL library httpsclientSetup.");
  75.   int rc;
  76.   g_host = host;
  77.   g_path = path;
  78.   if ((rc = matrixSslOpen()) < 0) {
  79.     if (true) _psTrace("MatrixSSL library init failure.");
  80.     return rc;
  81.   }
  82.  
  83.   if ((rc = matrixSslNewKeys(&keys, NULL)) < 0) {
  84.     if (true) Serial.println("MatrixSSL library key init failure.");
  85.     return HTTPS_ERROR;
  86.   }
  87. #ifndef USE_ONLY_PSK_CIPHER_SUITE
  88.   /*
  89.     In-memory based keys
  90.     Build the CA list first for potential client auth usage
  91.   */
  92.   CAstreamLen = 0;
  93. #ifdef USE_RSA_CIPHER_SUITE
  94.   CAstreamLen += sizeof(RSACAS);
  95. #ifdef USE_ECC_CIPHER_SUITE
  96.   CAstreamLen += sizeof(ECDHRSACAS);
  97. #endif
  98. #endif
  99. #ifdef USE_ECC_CIPHER_SUITE
  100.   CAstreamLen += sizeof(ECCAS);
  101. #endif
  102.   if (CAstreamLen > 0) {
  103.     CAstream = (unsigned char *) psMalloc(NULL, CAstreamLen);
  104.   } else {
  105.     CAstream = NULL;
  106.   }
  107.   CAstreamLen = 0;
  108. #ifdef USE_RSA_CIPHER_SUITE
  109.   memcpy(CAstream, RSACAS, sizeof(RSACAS));
  110.   CAstreamLen += sizeof(RSACAS);
  111. #ifdef USE_ECC_CIPHER_SUITE
  112.   memcpy(CAstream + CAstreamLen, ECDHRSACAS, sizeof(ECDHRSACAS));
  113.   CAstreamLen += sizeof(ECDHRSACAS);
  114. #endif
  115. #endif
  116. #ifdef USE_ECC_CIPHER_SUITE
  117.   memcpy(CAstream + CAstreamLen, ECCAS, sizeof(ECCAS));
  118.   CAstreamLen += sizeof(ECCAS);
  119. #endif
  120.  
  121.  
  122. #ifdef ID_RSA
  123.   rc = loadRsaKeys(g_key_len, keys, CAstream, CAstreamLen);
  124.   if (rc < 0) {
  125.     if (true) {
  126.       Serial.print("Keys didn't load!: loadRsaKeys returned: ");
  127.       Serial.println(rc);
  128.     }
  129.     return rc;
  130.   }
  131.   if (true) _psTrace("Keys Loaded");
  132.     if (true) Serial.println("Keys Loaded");
  133. #endif
  134.  
  135.   if (CAstream) psFree(CAstream, NULL);
  136.  
  137. #endif /* USE_ONLY_PSK_CIPHER_SUITE */
  138.  
  139.   matrixSslNewSessionId(&sid, NULL);
  140.   if (true) Serial.println("New Session key!: ");
  141.   sessionFlag = SSL_FLAGS_TLS_1_2;
  142. }
  143.  
  144. static int32 httpWriteRequest(uint32 msg_length, const char * message) {
  145.   unsigned char   *buf;
  146.   int32 available, requested;
  147.  
  148.   requested = strlen((char *)g_httpRequestHdr) + strlen(g_path) + 1 + msg_length + 10;
  149.   if ((available = matrixSslGetWritebuf(ssl, &buf, requested)) < 0) {
  150.     return PS_MEM_FAIL;
  151.   }
  152.   requested = min(requested, available);
  153.   snprintf((char *)buf, requested, (char *)g_httpRequestHdr, g_path,
  154.        msg_length, message);
  155.   if (true) _psTrace((char*)buf);
  156.  
  157.   if (matrixSslEncodeWritebuf(ssl, strlen((char *)buf)) < 0) {
  158.     return PS_MEM_FAIL;
  159.   }
  160.   return MATRIXSSL_REQUEST_SEND;
  161.  
  162. }
  163.  
  164. static int32 certCb(ssl_t *ssl, psX509Cert_t *cert, int32 alert) {
  165. #ifndef USE_ONLY_PSK_CIPHER_SUITE
  166.  
  167.   if (true) {
  168.     Serial.print("certCb invoked: "); Serial.println(alert);
  169.   }
  170.   /* Did we even find a CA that issued the certificate? */
  171.   if (alert == SSL_ALERT_UNKNOWN_CA) {
  172.     /* Example to allow anonymous connections based on a define */
  173.     if (ALLOW_ANON_CONNECTIONS) {
  174.       if (true)
  175.     Serial.println("Allowing anonymous connection for:");
  176.       //cert->subject.commonName holds the value?
  177.       return SSL_ALLOW_ANON_CONNECTION;
  178.     }
  179.     if (true)
  180.       Serial.println("ERROR: No matching CA found.  Terminating connection");
  181.   }
  182.   psX509Cert_t    *next;
  183.  
  184.   /* If the expectedName passed to matrixSslNewClientSession does not
  185.     match any of the server subject name or subjAltNames, we will have
  186.     the alert below.
  187.     For security, the expected name (typically a domain name) _must_
  188.     match one of the certificate subject names, or the connection
  189.     should not continue.
  190.     The default MatrixSSL certificates use localhost and 127.0.0.1 as
  191.     the subjects, so unless the server IP matches one of those, this
  192.     alert will happen.
  193.     To temporarily disable the subjet name validation, NULL can be passed
  194.     as expectedName to matrixNewClientSession.
  195.   */
  196.   if (alert == SSL_ALERT_CERTIFICATE_UNKNOWN) {
  197.     //ssl->expectedName not found in cert subject names
  198.     if (true)
  199.       Serial.println("ERROR: expectedName not found in cert subject names");
  200.   }
  201.  
  202.   if (alert == SSL_ALERT_CERTIFICATE_EXPIRED) {
  203. #ifdef POSIX
  204.  
  205.     if (true)
  206.       Serial.println("ERROR: A cert did not fall within the "
  207.              "notBefore/notAfter window");
  208.  
  209. #else
  210.     if (true)
  211.       Serial.println("WARNING: Certificate date window validation not "
  212.              "implemented");
  213.     alert = 0;
  214. #endif
  215.   }
  216.  
  217.   if (alert == SSL_ALERT_ILLEGAL_PARAMETER) {
  218.     if (true)
  219.       Serial.println("ERROR: Found correct CA but X.509 extension details are "
  220.              "wrong");
  221.   }
  222.  
  223.   /* Key usage related problems on chain */
  224.   for (next = cert; next != NULL; next = next->next) {
  225.     if (next->authStatus == PS_CERT_AUTH_FAIL_EXTENSION) {
  226.       if (next->authFailFlags & PS_CERT_AUTH_FAIL_KEY_USAGE_FLAG) {
  227.     if (true)
  228.       Serial.println("CA keyUsage extension doesn't allow cert signing");
  229.       }
  230.       if (next->authFailFlags & PS_CERT_AUTH_FAIL_EKU_FLAG) {
  231.     if (true)
  232.       Serial.println("Cert extendedKeyUsage extension doesn't allow TLS");
  233.       }
  234.     }
  235.   }
  236.  
  237.   if (alert == SSL_ALERT_BAD_CERTIFICATE) {
  238.     /* Should never let a connection happen if this is set.  There was
  239.        either a problem in the presented chain or in the final CA test */
  240.     if (true)
  241.       Serial.println("ERROR: Problem in certificate validation.  Exiting.");
  242.   }
  243.  
  244.  
  245.   if (alert == 0) {
  246.     // Passes test: cert->subject.commonName
  247.     if (true) Serial.println("SUCCESS: Validated!");
  248.   }
  249. #endif /* !USE_ONLY_PSK_CIPHER_SUITE */
  250.   return alert;
  251. }
  252.  
  253. static int32 extensionCb(ssl_t *ssl, unsigned short extType,
  254.              unsigned short extLen, void *e) {
  255.   unsigned char   *c;
  256.   short len;
  257.   char proto[128];
  258.  
  259.   c = (unsigned char*)e;
  260.  
  261.   if (extType == EXT_ALPN) {
  262.     memset(proto, 0x0, 128);
  263.     /* two byte proto list len, one byte proto len, then proto */
  264.     c += 2; /* Skip proto list len */
  265.     len = *c; c++;
  266.     memcpy(proto, c, len);
  267.     if (true) {
  268.       Serial.print("Server agreed to use ");
  269.       Serial.println(proto);
  270.     }
  271.   }
  272.   return PS_SUCCESS;
  273. }
  274.  
  275. static int32 TCPRead (int len) {
  276.   unsigned int bufferPosition = 0;
  277.   char c;
  278.   unsigned long lastRead = millis();
  279.   bool error = false;
  280.   bool timeout = false;
  281.  
  282.   do {
  283.     while (client.available()) {
  284.       c = client.read();
  285.       // if (true) {
  286.       //    if (bufferPosition == 0) Serial.println("TCP Receiving ...");
  287.       //    if ((c < 32) || (c > 126)) Serial.print('.');
  288.       //    else Serial.print(c);
  289.       //    if (bufferPosition % 80 == 0) Serial.println();
  290.       // }
  291.       lastRead = millis();
  292.       if (c == -1) {
  293.     error = true;
  294.     if (true)
  295.       Serial.println("HttpClient>\tError: No data available.");
  296.     break;
  297.       }
  298.  
  299.       // Check that received character fits in buffer before storing.
  300.       if (bufferPosition < len) {
  301.     g_buf[bufferPosition++] = c;
  302.       }
  303.       if (bufferPosition == len) {
  304.     return bufferPosition;
  305.       }
  306.     }
  307.  
  308.     if (true) {
  309.       _psTrace("HttpClient>\tDone before full len ");
  310.       Serial.println(bufferPosition);
  311.     }
  312.  
  313.     //  Check for timeout since last read
  314.     timeout = millis() - lastRead > TIMEOUT;
  315.     if (!error && !timeout) {
  316.       delay(200);
  317.     }
  318.   } while (client.connected() && !timeout && (bufferPosition == 0));
  319.   return bufferPosition;
  320. }
  321.  
  322. int httpsClientConnection(unsigned char * requestContent, uint32 msg_len,
  323.               const char * message) {
  324.   int32 rc, len, transferred;
  325.   g_httpRequestHdr = requestContent;
  326.  
  327.   memset(&options, 0x0, sizeof(sslSessOpts_t));
  328.   options.versionFlag = sessionFlag;
  329.   options.userPtr = keys;
  330.   matrixSslNewHelloExtension(&extension, NULL);
  331.   matrixSslCreateSNIext(NULL, (unsigned char*)g_host, (uint32)strlen(g_host),
  332.             &ext, &extLen);
  333.   matrixSslLoadHelloExtension(extension, ext, extLen, EXT_SNI);
  334.   // TOOD: Dynamic memory allocation, possible memory leak
  335.   psFree(ext, NULL);
  336.  
  337.   rc = matrixSslNewClientSession(&ssl, keys, sid, g_cipher, g_ciphers, certCb,
  338.                  NULL, extension, extensionCb, &options);
  339.  
  340.   if (true) {
  341.     Serial.print("matrixSslNewClientSession:");
  342.     Serial.println(rc);
  343.   }
  344.  
  345.   matrixSslDeleteHelloExtension(extension);
  346.  
  347.   if (rc != MATRIXSSL_REQUEST_SEND) {
  348.     if (true)
  349.       Serial.println("New Client Session Failed: Exiting\n");
  350.     return HTTPS_ERROR;
  351.   }
  352.  
  353.   if (true) {
  354.     freemem = System.freeMemory();
  355.     Serial.print("free memory 3: ");
  356.     Serial.println(freemem);
  357.   }
  358.  
  359.  WRITE_MORE:
  360.   while ((len = matrixSslGetOutdata(ssl, &g_buf)) > 0) {
  361.     transferred = client.write(g_buf, len);
  362.     client.flush();
  363.  
  364.     if (transferred <= 0) {
  365.       goto L_CLOSE_ERR;
  366.     }
  367.     else {
  368.       /* Indicate that we've written > 0 bytes of data */
  369.       if (true) {
  370.     Serial.print("Bytes sent Successfully?!: ");Serial.println(len);
  371.       }
  372.       if ((rc = matrixSslSentData(ssl, transferred)) < 0) {
  373.     goto L_CLOSE_ERR;
  374.       }
  375.       if (true) {
  376.     Serial.print("matrixSslSentData: ");
  377.     Serial.println(rc);
  378.       }
  379.       if (rc == MATRIXSSL_REQUEST_CLOSE) {
  380.     // TOOD: Anything here?
  381.     return MATRIXSSL_SUCCESS;
  382.       }
  383.       if (rc == MATRIXSSL_HANDSHAKE_COMPLETE) {
  384.     /* If we sent the Finished SSL message, initiate the HTTP req */
  385.     /* (This occurs on a resumption handshake) */
  386.     if (httpWriteRequest(msg_len, message) < 0) {
  387.       goto L_CLOSE_ERR;
  388.     }
  389.     goto WRITE_MORE;
  390.       }
  391.       /* SSL_REQUEST_SEND is handled by loop logic */
  392.       if (true)
  393.     Serial.println("Sent Successfully?!, everything good");
  394.     }
  395.   }
  396.  READ_MORE:
  397.   if ((len = matrixSslGetReadbuf(ssl, &g_buf)) <= 0) {
  398.     if (true) {
  399.       Serial.print("matrixSslGetReadbuf: ");
  400.       Serial.println(len);
  401.     }
  402.     goto L_CLOSE_ERR;
  403.   }
  404.   if (true) {
  405.     Serial.print("matrixSslGetReadbuf: ");
  406.     Serial.println(len);
  407.   }
  408.   if ((transferred = TCPRead(len)) < 0) {
  409.     if (true) {
  410.       Serial.print("Received: ");
  411.       Serial.println(transferred);
  412.     }
  413.     goto L_CLOSE_ERR;
  414.   }
  415.   if (true) {
  416.     Serial.print("Received: ");
  417.     Serial.println(transferred);
  418.   }
  419.   if (transferred == 0) {
  420.     goto L_CLOSE_ERR;
  421.   }
  422.   if ((rc = matrixSslReceivedData(ssl, (int32)transferred, &g_buf,
  423.                   (uint32*)&len)) < 0) {
  424.     goto L_CLOSE_ERR;
  425.   }
  426.   if (true) {
  427.     Serial.print("matrixSslReceivedData: Tx: ");
  428.     Serial.print((int32) transferred);
  429.     Serial.print(" Len: "); Serial.print(len);
  430.     Serial.print(" rc: "); Serial.println(rc);
  431.   }
  432.  
  433.  PROCESS_MORE:
  434.   switch (rc) {
  435.   case MATRIXSSL_HANDSHAKE_COMPLETE:
  436. #ifdef REHANDSHAKE_TEST
  437.     /*
  438.       Test rehandshake capabilities of server.  If a successful
  439.       session resmption rehandshake occurs, this client will be last to
  440.       send handshake data and MATRIXSSL_HANDSHAKE_COMPLETE will hit on
  441.       the WRITE_MORE handler and httpWriteRequest will occur there.
  442.  
  443.       NOTE: If the server doesn't support session resumption it is
  444.       possible to fall into an endless rehandshake loop
  445.     */
  446.     if (matrixSslEncodeRehandshake(ssl, NULL, NULL, 0,
  447.                    g_cipher, g_ciphers) < 0) {
  448.       goto L_CLOSE_ERR;
  449.     }
  450. #else
  451.     /* We got the Finished SSL message, initiate the HTTP req */
  452.     if (httpWriteRequest(msg_len, message) < 0) {
  453.       goto L_CLOSE_ERR;
  454.     }
  455. #endif
  456.     goto WRITE_MORE;
  457.   case MATRIXSSL_APP_DATA:
  458.   case MATRIXSSL_APP_DATA_COMPRESSED:
  459.     g_bytes_received += len;
  460.     if (true) {
  461.       for (int i = 0 ; i < len; i++) {
  462.     Serial.print((char)g_buf[i]);
  463.       }
  464.       Serial.println();
  465.     }
  466.     if (!g_https_complete) {
  467.       if (strstr((const char *) g_buf, end_header)) {
  468.     g_https_complete = true;
  469.       }
  470.     }
  471.     rc = matrixSslProcessedData(ssl, &g_buf, (uint32*)&len);
  472.     if (true) {
  473.       Serial.print("matrixSslProcessedData: ");
  474.       Serial.println(rc);
  475.     }
  476.     if (rc < 0) {
  477.       goto L_CLOSE_ERR;
  478.     }
  479.     if (g_bytes_requested > 0) {
  480.       if (g_bytes_received >= g_bytes_requested) {
  481.     /* We've received all that was requested, so close */
  482.     if (true)
  483.       Serial.println("Stopping connection for a stupid reason");
  484.     return MATRIXSSL_SUCCESS;
  485.       }
  486.       if (rc == 0) {
  487.     /* We processed a partial HTTP message */
  488.     goto READ_MORE;
  489.       }
  490.     }
  491.     goto PROCESS_MORE;
  492.   case MATRIXSSL_REQUEST_SEND:
  493.     goto WRITE_MORE;
  494.   case MATRIXSSL_REQUEST_RECV:
  495.     goto READ_MORE;
  496.   case MATRIXSSL_RECEIVED_ALERT:
  497.     /* The first byte of the buffer is the level */
  498.     /* The second byte is the description */
  499.     if (*g_buf == SSL_ALERT_LEVEL_FATAL) {
  500.       if (true) Serial.println("Fatal alert: %d, closing connection.");
  501.       goto L_CLOSE_ERR;
  502.     }
  503.     /* Closure alert is normal (and best) way to close */
  504.     if (*(g_buf + 1) == SSL_ALERT_CLOSE_NOTIFY) {
  505.       if (true) Serial.println("Gentle Close");
  506.       // TODO: Do something with this whole parsing stuff
  507.       return MATRIXSSL_SUCCESS;
  508.     }
  509.     if (true) Serial.println("Warning alert");
  510.     if ((rc = matrixSslProcessedData(ssl, &g_buf, (uint32*)&len)) == 0) {
  511.       /* No more data in buffer. Might as well read for more. */
  512.       if (true) Serial.println("Reading more ...");
  513.       goto READ_MORE;
  514.     }
  515.     if (true) Serial.println("rc: %d, Processing more ..");
  516.     goto PROCESS_MORE;
  517.   default:
  518.     /* If rc <= 0 we fall here */
  519.     goto L_CLOSE_ERR;
  520.   }
  521.  L_CLOSE_ERR:
  522.   if (!g_https_complete) {
  523.     if (true) Serial.println("FAIL: No HTTP Response");
  524.   } else {
  525.     if (true) Serial.println("Received something");
  526.   }
  527.   matrixSslDeleteSession(ssl);
  528.   return MATRIXSSL_ERROR;
  529. }
  530.  
  531. void httpsclientCleanUp() {
  532.   matrixSslDeleteSessionId(sid);
  533.   matrixSslDeleteKeys(keys);
  534.   matrixSslClose();
  535. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement