MAXREFDES143#: DeepCover Embedded Security in IoT Authenticated Sensing & Notification

Dependencies:   MaximInterface mbed

The MAXREFDES143# is an Internet of Things (IoT) embedded security reference design, built to protect an industrial sensing node by means of authentication and notification to a web server. The hardware includes a peripheral module representing a protected sensor node monitoring operating temperature and remaining life of a filter (simulated through ambient light sensing) and an mbed shield representing a controller node responsible for monitoring one or more sensor nodes. The design is hierarchical with each controller node communicating data from connected sensor nodes to a web server that maintains a centralized log and dispatches notifications as necessary. The mbed shield contains a Wi-Fi module, a DS2465 coprocessor with 1-Wire® master function, an LCD, LEDs, and pushbuttons. The protected sensor node contains a DS28E15 authenticator, a DS7505 temperature sensor, and a MAX44009 light sensor. The mbed shield communicates to a web server by the onboard Wi-Fi module and to the protected sensor node with I2C and 1-Wire. The MAXREFDES143# is equipped with a standard shield connector for immediate testing using an mbed board such as the MAX32600MBED#. The simplicity of this design enables rapid integration into any star-topology IoT network requiring the heightened security with low overhead provided by the SHA-256 symmetric-key algorithm.

More information about the MAXREFDES143# is available on the Maxim Integrated website.

Committer:
IanBenzMaxim
Date:
Fri Dec 16 10:47:34 2016 -0600
Revision:
25:37ea43ff81be
Parent:
20:cdba71cb5506
Child:
27:81a87d29bedd
Now using unique secret for data signing between mbed node and server. Updated to mbed 5 for better platform support. Updated to latest version of 1-Wire library.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
IanBenzMaxim 1:e1c7c1c636af 1 /*******************************************************************************
IanBenzMaxim 1:e1c7c1c636af 2 * Copyright (C) 2016 Maxim Integrated Products, Inc., All Rights Reserved.
IanBenzMaxim 1:e1c7c1c636af 3 *
IanBenzMaxim 1:e1c7c1c636af 4 * Permission is hereby granted, free of charge, to any person obtaining a
IanBenzMaxim 1:e1c7c1c636af 5 * copy of this software and associated documentation files (the "Software"),
IanBenzMaxim 1:e1c7c1c636af 6 * to deal in the Software without restriction, including without limitation
IanBenzMaxim 1:e1c7c1c636af 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
IanBenzMaxim 1:e1c7c1c636af 8 * and/or sell copies of the Software, and to permit persons to whom the
IanBenzMaxim 1:e1c7c1c636af 9 * Software is furnished to do so, subject to the following conditions:
IanBenzMaxim 1:e1c7c1c636af 10 *
IanBenzMaxim 1:e1c7c1c636af 11 * The above copyright notice and this permission notice shall be included
IanBenzMaxim 1:e1c7c1c636af 12 * in all copies or substantial portions of the Software.
IanBenzMaxim 1:e1c7c1c636af 13 *
IanBenzMaxim 1:e1c7c1c636af 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
IanBenzMaxim 1:e1c7c1c636af 15 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
IanBenzMaxim 1:e1c7c1c636af 16 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IanBenzMaxim 1:e1c7c1c636af 17 * IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES
IanBenzMaxim 1:e1c7c1c636af 18 * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
IanBenzMaxim 1:e1c7c1c636af 19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
IanBenzMaxim 1:e1c7c1c636af 20 * OTHER DEALINGS IN THE SOFTWARE.
IanBenzMaxim 1:e1c7c1c636af 21 *
IanBenzMaxim 1:e1c7c1c636af 22 * Except as contained in this notice, the name of Maxim Integrated
IanBenzMaxim 1:e1c7c1c636af 23 * Products, Inc. shall not be used except as stated in the Maxim Integrated
IanBenzMaxim 1:e1c7c1c636af 24 * Products, Inc. Branding Policy.
IanBenzMaxim 1:e1c7c1c636af 25 *
IanBenzMaxim 1:e1c7c1c636af 26 * The mere transfer of this software does not imply any licenses
IanBenzMaxim 1:e1c7c1c636af 27 * of trade secrets, proprietary technology, copyrights, patents,
IanBenzMaxim 1:e1c7c1c636af 28 * trademarks, maskwork rights, or any other form of intellectual
IanBenzMaxim 1:e1c7c1c636af 29 * property whatsoever. Maxim Integrated Products, Inc. retains all
IanBenzMaxim 1:e1c7c1c636af 30 * ownership rights.
IanBenzMaxim 1:e1c7c1c636af 31 *******************************************************************************
IanBenzMaxim 1:e1c7c1c636af 32 */
IanBenzMaxim 1:e1c7c1c636af 33
IanBenzMaxim 1:e1c7c1c636af 34 #include <vector>
IanBenzMaxim 1:e1c7c1c636af 35 #include "WebServerInterface.hpp"
IanBenzMaxim 1:e1c7c1c636af 36 #include "ESP8266.hpp"
IanBenzMaxim 16:6bce01c1dd90 37 #include "Slaves/Authenticators/ISha256MacCoproc.h"
IanBenzMaxim 25:37ea43ff81be 38 #include "SensorData.hpp"
IanBenzMaxim 25:37ea43ff81be 39 #include "HexConversions.hpp"
IanBenzMaxim 6:b6bafd0a7013 40 #include "Serial.h"
IanBenzMaxim 6:b6bafd0a7013 41 #include "wait_api.h"
IanBenzMaxim 6:b6bafd0a7013 42
IanBenzMaxim 8:594529956266 43 using OneWire::ISha256MacCoproc;
IanBenzMaxim 1:e1c7c1c636af 44
IanBenzMaxim 25:37ea43ff81be 45 const char WebServerInterface::wifiSsid[] = "TWS iPhone";
IanBenzMaxim 25:37ea43ff81be 46 const char WebServerInterface::wifiPassword[] = "maxim1234";
IanBenzMaxim 12:5f8727ba1493 47 const char WebServerInterface::serverAddress[] = "www.mxim-security.us";
IanBenzMaxim 3:ac723be395d9 48 const unsigned int WebServerInterface::serverPort = 80;
IanBenzMaxim 1:e1c7c1c636af 49 const char WebServerInterface::serverPostPath[] = "/post.php";
IanBenzMaxim 1:e1c7c1c636af 50 const char WebServerInterface::serverChallengePath[] = "/challenge.php";
IanBenzMaxim 1:e1c7c1c636af 51
IanBenzMaxim 1:e1c7c1c636af 52 // HTTP formatting constants
IanBenzMaxim 1:e1c7c1c636af 53 static const char keyValSeparator = '=';
IanBenzMaxim 1:e1c7c1c636af 54 static const char fieldSeparator = '&';
IanBenzMaxim 1:e1c7c1c636af 55 static const std::string newline = "\r\n";
IanBenzMaxim 1:e1c7c1c636af 56 static const char sessionIdKey[] = "SessionId";
IanBenzMaxim 1:e1c7c1c636af 57
IanBenzMaxim 1:e1c7c1c636af 58 // Authentication MAC constants
IanBenzMaxim 6:b6bafd0a7013 59 static const size_t challengeLen = 32;
IanBenzMaxim 6:b6bafd0a7013 60 static const uint8_t defaultPaddingByte = 0x00;
IanBenzMaxim 1:e1c7c1c636af 61
IanBenzMaxim 1:e1c7c1c636af 62 /// Select the Transport Secret for the web server in the Controller.
IanBenzMaxim 1:e1c7c1c636af 63 /// @returns True on success.
IanBenzMaxim 25:37ea43ff81be 64 static bool setHttpPostSecret(ISha256MacCoproc & MacCoproc, const OneWire::RomId & sessionId)
IanBenzMaxim 1:e1c7c1c636af 65 {
IanBenzMaxim 25:37ea43ff81be 66 ISha256MacCoproc::DevicePage fillData;
IanBenzMaxim 25:37ea43ff81be 67 fillData.fill(defaultPaddingByte);
IanBenzMaxim 25:37ea43ff81be 68 ISha256MacCoproc::SlaveSecretData secretData;
IanBenzMaxim 25:37ea43ff81be 69 secretData.fill(defaultPaddingByte);
IanBenzMaxim 25:37ea43ff81be 70 std::copy(sessionId.buffer.begin(), sessionId.buffer.end(), secretData.begin());
IanBenzMaxim 25:37ea43ff81be 71 return (MacCoproc.computeSlaveSecret(fillData, fillData, secretData) == ISha256MacCoproc::Success);
IanBenzMaxim 1:e1c7c1c636af 72 }
IanBenzMaxim 1:e1c7c1c636af 73
IanBenzMaxim 1:e1c7c1c636af 74 WebServerInterface::WebServerInterface(ESP8266 & esp8266, mbed::Serial * pc)
IanBenzMaxim 1:e1c7c1c636af 75 : esp8266(esp8266), pc(pc)
IanBenzMaxim 1:e1c7c1c636af 76 {
IanBenzMaxim 1:e1c7c1c636af 77
IanBenzMaxim 1:e1c7c1c636af 78 }
IanBenzMaxim 1:e1c7c1c636af 79
IanBenzMaxim 1:e1c7c1c636af 80 bool WebServerInterface::initialize()
IanBenzMaxim 1:e1c7c1c636af 81 {
IanBenzMaxim 1:e1c7c1c636af 82 esp8266.setPowered(true);
IanBenzMaxim 1:e1c7c1c636af 83 esp8266.reset();
IanBenzMaxim 1:e1c7c1c636af 84 bool result = (esp8266.performSelfTest() == ESP8266::AT_OK);
IanBenzMaxim 25:37ea43ff81be 85 if (result)
IanBenzMaxim 1:e1c7c1c636af 86 {
IanBenzMaxim 25:37ea43ff81be 87 result = (esp8266.setCurrentWifiMode(ESP8266::softAP_station_mode) == ESP8266::AT_OK);
IanBenzMaxim 1:e1c7c1c636af 88 }
IanBenzMaxim 25:37ea43ff81be 89 if (result)
IanBenzMaxim 1:e1c7c1c636af 90 {
IanBenzMaxim 25:37ea43ff81be 91 result = (esp8266.setMaxRFTXPower(10) == ESP8266::AT_OK);
IanBenzMaxim 1:e1c7c1c636af 92 }
IanBenzMaxim 25:37ea43ff81be 93 if (result)
IanBenzMaxim 1:e1c7c1c636af 94 {
IanBenzMaxim 25:37ea43ff81be 95 result = (esp8266.joinCurrentAccessPoint(wifiSsid, wifiPassword) == ESP8266::AT_OK);
IanBenzMaxim 1:e1c7c1c636af 96 }
IanBenzMaxim 25:37ea43ff81be 97 return result;
IanBenzMaxim 1:e1c7c1c636af 98 }
IanBenzMaxim 1:e1c7c1c636af 99
IanBenzMaxim 1:e1c7c1c636af 100 /// Format an HTTP GET request as a string for transmission.
IanBenzMaxim 1:e1c7c1c636af 101 /// @param host Web server address.
IanBenzMaxim 1:e1c7c1c636af 102 /// @param path Web server location to retrieve.
IanBenzMaxim 1:e1c7c1c636af 103 /// @param sessionId Session ID used to identify this controller.
IanBenzMaxim 1:e1c7c1c636af 104 /// @returns GET request string.
IanBenzMaxim 1:e1c7c1c636af 105 static std::string formatHttpGet(const std::string & host, const std::string & path, const std::string & sessionId)
IanBenzMaxim 1:e1c7c1c636af 106 {
IanBenzMaxim 1:e1c7c1c636af 107 std::ostringstream httpGetStream;
IanBenzMaxim 1:e1c7c1c636af 108 httpGetStream << "GET " << path;
IanBenzMaxim 1:e1c7c1c636af 109 if (sessionId.length() > 0)
IanBenzMaxim 1:e1c7c1c636af 110 httpGetStream << '?' << sessionIdKey << keyValSeparator << sessionId;
IanBenzMaxim 1:e1c7c1c636af 111 httpGetStream << " HTTP/1.1" << newline;
IanBenzMaxim 1:e1c7c1c636af 112 httpGetStream << "Host: " << host << newline;
IanBenzMaxim 1:e1c7c1c636af 113 httpGetStream << newline;
IanBenzMaxim 1:e1c7c1c636af 114 return httpGetStream.str();
IanBenzMaxim 1:e1c7c1c636af 115 }
IanBenzMaxim 1:e1c7c1c636af 116
IanBenzMaxim 1:e1c7c1c636af 117 /// Computes a MAC using the Transport Secret to sign HTTP POST requests.
IanBenzMaxim 1:e1c7c1c636af 118 /// @param macCoproc Coprocessor such as the DS2465 used to calculate the authentication MAC.
IanBenzMaxim 1:e1c7c1c636af 119 /// @param input Message array used for MAC calculation.
IanBenzMaxim 1:e1c7c1c636af 120 /// @param ilen Length of array input.
IanBenzMaxim 1:e1c7c1c636af 121 /// @param output Calculated MAC output.
IanBenzMaxim 6:b6bafd0a7013 122 static void calculateHttpPostMac(const ISha256MacCoproc & macCoproc, const uint8_t * input, size_t ilen, ISha256MacCoproc::Mac & output)
IanBenzMaxim 1:e1c7c1c636af 123 {
IanBenzMaxim 6:b6bafd0a7013 124 ISha256MacCoproc::DeviceScratchpad block;
IanBenzMaxim 6:b6bafd0a7013 125 size_t index = 0;
IanBenzMaxim 6:b6bafd0a7013 126 ISha256MacCoproc::AuthMacData padding;
IanBenzMaxim 25:37ea43ff81be 127 padding.fill(defaultPaddingByte);
IanBenzMaxim 25:37ea43ff81be 128 output.fill(defaultPaddingByte); // Set initial hash value
IanBenzMaxim 1:e1c7c1c636af 129 while (index < ilen)
IanBenzMaxim 1:e1c7c1c636af 130 {
IanBenzMaxim 25:37ea43ff81be 131 if ((index + block.size()) <= ilen) // Full block
IanBenzMaxim 1:e1c7c1c636af 132 {
IanBenzMaxim 25:37ea43ff81be 133 std::memcpy(block.data(), &input[index], block.size());
IanBenzMaxim 25:37ea43ff81be 134 index += block.size();
IanBenzMaxim 1:e1c7c1c636af 135 }
IanBenzMaxim 1:e1c7c1c636af 136 else // Partial block with padding
IanBenzMaxim 1:e1c7c1c636af 137 {
IanBenzMaxim 25:37ea43ff81be 138 std::memcpy(block.data(), &input[index], ilen - index);
IanBenzMaxim 25:37ea43ff81be 139 std::memset(&block[ilen - index], defaultPaddingByte, block.size() - (ilen - index));
IanBenzMaxim 1:e1c7c1c636af 140 index = ilen;
IanBenzMaxim 1:e1c7c1c636af 141 }
IanBenzMaxim 1:e1c7c1c636af 142 // Write data to coprocessor and hash block
IanBenzMaxim 1:e1c7c1c636af 143 macCoproc.computeAuthMac(output, block, padding, output);
IanBenzMaxim 1:e1c7c1c636af 144 }
IanBenzMaxim 1:e1c7c1c636af 145 }
IanBenzMaxim 1:e1c7c1c636af 146
IanBenzMaxim 1:e1c7c1c636af 147 /// Format an HTTP POST request as a string for transmission.
IanBenzMaxim 1:e1c7c1c636af 148 /// @param host Web server address.
IanBenzMaxim 1:e1c7c1c636af 149 /// @param path Web server location to receive POST.
IanBenzMaxim 1:e1c7c1c636af 150 /// @param sessionId Session ID used to identify this Controller.
IanBenzMaxim 1:e1c7c1c636af 151 /// @param macCoproc Coprocessor such as the DS2465 used to calculate the authentication MAC.
IanBenzMaxim 1:e1c7c1c636af 152 /// @param event Event message type.
IanBenzMaxim 1:e1c7c1c636af 153 /// @param initialPostBody Message body as determined by the event message type.
IanBenzMaxim 1:e1c7c1c636af 154 /// @param challenge Challenge previously received from web server for use in authentication MAC.
IanBenzMaxim 1:e1c7c1c636af 155 /// @returns POST request string.
IanBenzMaxim 1:e1c7c1c636af 156 static std::string formatHttpPost(const std::string & host, const std::string & path, const std::string & sessionId,
IanBenzMaxim 6:b6bafd0a7013 157 const ISha256MacCoproc & macCoproc, PostEvent event, const std::string & initialPostBody,
IanBenzMaxim 6:b6bafd0a7013 158 const uint8_t (&challenge)[challengeLen])
IanBenzMaxim 1:e1c7c1c636af 159 {
IanBenzMaxim 6:b6bafd0a7013 160 const size_t headerReserve = 115, bodyReserve = 200;
IanBenzMaxim 1:e1c7c1c636af 161
IanBenzMaxim 1:e1c7c1c636af 162 std::string httpPost;
IanBenzMaxim 1:e1c7c1c636af 163 httpPost.reserve(initialPostBody.length() + headerReserve + bodyReserve);
IanBenzMaxim 1:e1c7c1c636af 164
IanBenzMaxim 1:e1c7c1c636af 165 // Add session ID to post body
IanBenzMaxim 1:e1c7c1c636af 166 if (sessionId.length() > 0)
IanBenzMaxim 1:e1c7c1c636af 167 {
IanBenzMaxim 1:e1c7c1c636af 168 httpPost += sessionIdKey;
IanBenzMaxim 1:e1c7c1c636af 169 httpPost += keyValSeparator;
IanBenzMaxim 1:e1c7c1c636af 170 httpPost += sessionId;
IanBenzMaxim 1:e1c7c1c636af 171 }
IanBenzMaxim 1:e1c7c1c636af 172
IanBenzMaxim 1:e1c7c1c636af 173 // Add event to post body
IanBenzMaxim 1:e1c7c1c636af 174 std::string eventString;
IanBenzMaxim 1:e1c7c1c636af 175 switch (event)
IanBenzMaxim 1:e1c7c1c636af 176 {
IanBenzMaxim 1:e1c7c1c636af 177 case SensorDataEvent:
IanBenzMaxim 1:e1c7c1c636af 178 eventString = "SensorData";
IanBenzMaxim 1:e1c7c1c636af 179 break;
IanBenzMaxim 1:e1c7c1c636af 180
IanBenzMaxim 1:e1c7c1c636af 181 case InvalidSensorEvent:
IanBenzMaxim 1:e1c7c1c636af 182 eventString = "InvalidSensor";
IanBenzMaxim 1:e1c7c1c636af 183 break;
IanBenzMaxim 1:e1c7c1c636af 184 }
IanBenzMaxim 1:e1c7c1c636af 185 if (eventString.length() > 0)
IanBenzMaxim 1:e1c7c1c636af 186 {
IanBenzMaxim 1:e1c7c1c636af 187 if (httpPost.length() > 0)
IanBenzMaxim 1:e1c7c1c636af 188 httpPost += fieldSeparator;
IanBenzMaxim 1:e1c7c1c636af 189 httpPost += "Event";
IanBenzMaxim 1:e1c7c1c636af 190 httpPost += keyValSeparator;
IanBenzMaxim 1:e1c7c1c636af 191 httpPost += eventString;
IanBenzMaxim 1:e1c7c1c636af 192 }
IanBenzMaxim 1:e1c7c1c636af 193
IanBenzMaxim 1:e1c7c1c636af 194 // Add initial post body
IanBenzMaxim 1:e1c7c1c636af 195 if (initialPostBody.length() > 0)
IanBenzMaxim 1:e1c7c1c636af 196 {
IanBenzMaxim 1:e1c7c1c636af 197 if (httpPost.length() > 0)
IanBenzMaxim 1:e1c7c1c636af 198 httpPost += fieldSeparator;
IanBenzMaxim 1:e1c7c1c636af 199 httpPost += initialPostBody;
IanBenzMaxim 1:e1c7c1c636af 200 }
IanBenzMaxim 1:e1c7c1c636af 201
IanBenzMaxim 1:e1c7c1c636af 202 // Combine initial post body with initial secret and hash
IanBenzMaxim 6:b6bafd0a7013 203 std::vector<uint8_t> hashInput;
IanBenzMaxim 1:e1c7c1c636af 204 hashInput.reserve(challengeLen + httpPost.length());
IanBenzMaxim 25:37ea43ff81be 205 hashInput.assign(challenge, challenge + challengeLen);
IanBenzMaxim 1:e1c7c1c636af 206 hashInput.insert(hashInput.end(), httpPost.begin(), httpPost.end());
IanBenzMaxim 6:b6bafd0a7013 207 ISha256MacCoproc::Mac mac;
IanBenzMaxim 1:e1c7c1c636af 208 calculateHttpPostMac(macCoproc, &hashInput[0], hashInput.size(), mac);
IanBenzMaxim 1:e1c7c1c636af 209
IanBenzMaxim 1:e1c7c1c636af 210 char contentLen[5];
IanBenzMaxim 25:37ea43ff81be 211 snprintf(contentLen, sizeof(contentLen) / sizeof(contentLen[0]), "%u", (hashInput.size() - challengeLen) + (mac.size() * charsPerByte) + 5 /* &MAC= */);
IanBenzMaxim 1:e1c7c1c636af 212
IanBenzMaxim 1:e1c7c1c636af 213 // Construct full post request
IanBenzMaxim 1:e1c7c1c636af 214 httpPost = "";
IanBenzMaxim 1:e1c7c1c636af 215 httpPost += "POST ";
IanBenzMaxim 1:e1c7c1c636af 216 httpPost += path;
IanBenzMaxim 1:e1c7c1c636af 217 httpPost += " HTTP/1.1";
IanBenzMaxim 1:e1c7c1c636af 218 httpPost += newline;
IanBenzMaxim 1:e1c7c1c636af 219 httpPost += "Host: ";
IanBenzMaxim 1:e1c7c1c636af 220 httpPost += host;
IanBenzMaxim 1:e1c7c1c636af 221 httpPost += newline;
IanBenzMaxim 1:e1c7c1c636af 222 httpPost += "Accept: */*";
IanBenzMaxim 1:e1c7c1c636af 223 httpPost += newline;
IanBenzMaxim 1:e1c7c1c636af 224 httpPost += "Content-Length: ";
IanBenzMaxim 1:e1c7c1c636af 225 httpPost += contentLen;
IanBenzMaxim 1:e1c7c1c636af 226 httpPost += newline;
IanBenzMaxim 1:e1c7c1c636af 227 httpPost += "Content-Type: application/x-www-form-urlencoded";
IanBenzMaxim 1:e1c7c1c636af 228 httpPost += newline;
IanBenzMaxim 1:e1c7c1c636af 229 httpPost += newline;
IanBenzMaxim 1:e1c7c1c636af 230 // Add post body
IanBenzMaxim 1:e1c7c1c636af 231 httpPost.append(reinterpret_cast<char *>(&hashInput[challengeLen]), hashInput.size() - challengeLen);
IanBenzMaxim 1:e1c7c1c636af 232 // Convert hash to hex string and add to post body
IanBenzMaxim 1:e1c7c1c636af 233 httpPost += fieldSeparator;
IanBenzMaxim 1:e1c7c1c636af 234 httpPost += "MAC";
IanBenzMaxim 1:e1c7c1c636af 235 httpPost += keyValSeparator;
IanBenzMaxim 25:37ea43ff81be 236 byteArrayToHexString(mac.data(), mac.size(), httpPost);
IanBenzMaxim 1:e1c7c1c636af 237 httpPost += newline;
IanBenzMaxim 1:e1c7c1c636af 238
IanBenzMaxim 1:e1c7c1c636af 239 return httpPost;
IanBenzMaxim 1:e1c7c1c636af 240 }
IanBenzMaxim 1:e1c7c1c636af 241
IanBenzMaxim 6:b6bafd0a7013 242 bool WebServerInterface::authPostHttpEvent(ISha256MacCoproc & macCoproc, PostEvent event, const std::string & postData, bool setSecret)
IanBenzMaxim 1:e1c7c1c636af 243 {
IanBenzMaxim 1:e1c7c1c636af 244 const std::string challengeSearch(newline + newline);
IanBenzMaxim 1:e1c7c1c636af 245 bool result;
IanBenzMaxim 6:b6bafd0a7013 246 uint8_t challenge[challengeLen];
IanBenzMaxim 1:e1c7c1c636af 247 std::string response;
IanBenzMaxim 1:e1c7c1c636af 248
IanBenzMaxim 1:e1c7c1c636af 249 std::memset(challenge, defaultPaddingByte, challengeLen);
IanBenzMaxim 1:e1c7c1c636af 250 response.reserve(300);
IanBenzMaxim 1:e1c7c1c636af 251
IanBenzMaxim 1:e1c7c1c636af 252 if (setSecret)
IanBenzMaxim 1:e1c7c1c636af 253 {
IanBenzMaxim 25:37ea43ff81be 254 result = setHttpPostSecret(macCoproc, m_sessionId);
IanBenzMaxim 1:e1c7c1c636af 255 if (!result)
IanBenzMaxim 1:e1c7c1c636af 256 return result;
IanBenzMaxim 1:e1c7c1c636af 257 }
IanBenzMaxim 1:e1c7c1c636af 258
IanBenzMaxim 1:e1c7c1c636af 259 // Open connection
IanBenzMaxim 1:e1c7c1c636af 260 esp8266.clearRecvData(); // Clear received data buffer
IanBenzMaxim 1:e1c7c1c636af 261 result = (esp8266.openConnection(ESP8266::TCP, serverAddress, 80) == ESP8266::AT_OK);
IanBenzMaxim 1:e1c7c1c636af 262 if (result)
IanBenzMaxim 1:e1c7c1c636af 263 {
IanBenzMaxim 1:e1c7c1c636af 264 // Request challenge
IanBenzMaxim 25:37ea43ff81be 265 result = (esp8266.sendData(formatHttpGet(serverAddress, serverChallengePath, m_sessionIdString)) == ESP8266::AT_OK);
IanBenzMaxim 1:e1c7c1c636af 266 if (result)
IanBenzMaxim 1:e1c7c1c636af 267 {
IanBenzMaxim 1:e1c7c1c636af 268 // Receive server response
IanBenzMaxim 1:e1c7c1c636af 269 for (int i = 0; i < 10; i++)
IanBenzMaxim 1:e1c7c1c636af 270 {
IanBenzMaxim 1:e1c7c1c636af 271 while (esp8266.recvIpDataReadable())
IanBenzMaxim 1:e1c7c1c636af 272 {
IanBenzMaxim 1:e1c7c1c636af 273 char read = esp8266.getcRecvIpData();
IanBenzMaxim 1:e1c7c1c636af 274 if (pc != NULL)
IanBenzMaxim 1:e1c7c1c636af 275 pc->putc(read);
IanBenzMaxim 1:e1c7c1c636af 276 if (response.length() < response.capacity())
IanBenzMaxim 1:e1c7c1c636af 277 {
IanBenzMaxim 1:e1c7c1c636af 278 response += read;
IanBenzMaxim 1:e1c7c1c636af 279 }
IanBenzMaxim 1:e1c7c1c636af 280 else
IanBenzMaxim 1:e1c7c1c636af 281 {
IanBenzMaxim 1:e1c7c1c636af 282 wait_ms(ESP8266::sendDataRecoveryTimeMs); // Wait for ESP8266 specified recovery time
IanBenzMaxim 1:e1c7c1c636af 283 goto close_get_connection;
IanBenzMaxim 1:e1c7c1c636af 284 }
IanBenzMaxim 1:e1c7c1c636af 285 }
IanBenzMaxim 1:e1c7c1c636af 286 wait_ms(100);
IanBenzMaxim 1:e1c7c1c636af 287 }
IanBenzMaxim 1:e1c7c1c636af 288 // Close connection
IanBenzMaxim 1:e1c7c1c636af 289 close_get_connection:
IanBenzMaxim 1:e1c7c1c636af 290 esp8266.closeConnection();
IanBenzMaxim 1:e1c7c1c636af 291
IanBenzMaxim 1:e1c7c1c636af 292 // Parse challenge from response
IanBenzMaxim 6:b6bafd0a7013 293 size_t challengePos = response.find(challengeSearch);
IanBenzMaxim 1:e1c7c1c636af 294 if ((challengePos != std::string::npos) && ((challengePos + challengeSearch.length() + (challengeLen * charsPerByte)) <= response.length()))
IanBenzMaxim 1:e1c7c1c636af 295 {
IanBenzMaxim 1:e1c7c1c636af 296 challengePos += challengeSearch.length();
IanBenzMaxim 6:b6bafd0a7013 297 for (size_t i = 0; i < challengeLen; i++)
IanBenzMaxim 1:e1c7c1c636af 298 {
IanBenzMaxim 1:e1c7c1c636af 299 std::sscanf(response.substr(challengePos + (i * charsPerByte), charsPerByte).c_str(), "%2hhx", &challenge[i]);
IanBenzMaxim 1:e1c7c1c636af 300 }
IanBenzMaxim 1:e1c7c1c636af 301 }
IanBenzMaxim 1:e1c7c1c636af 302
IanBenzMaxim 1:e1c7c1c636af 303 // Post sensor data
IanBenzMaxim 3:ac723be395d9 304 result = (esp8266.openConnection(ESP8266::TCP, serverAddress, serverPort) == ESP8266::AT_OK);
IanBenzMaxim 1:e1c7c1c636af 305 if (result)
IanBenzMaxim 1:e1c7c1c636af 306 {
IanBenzMaxim 25:37ea43ff81be 307 result = (esp8266.sendData(formatHttpPost(serverAddress, serverPostPath, m_sessionIdString, macCoproc, event, postData, challenge)) == ESP8266::AT_OK);
IanBenzMaxim 1:e1c7c1c636af 308 wait_ms(ESP8266::sendDataRecoveryTimeMs); // Wait for ESP8266 specified recovery time
IanBenzMaxim 1:e1c7c1c636af 309 }
IanBenzMaxim 1:e1c7c1c636af 310 }
IanBenzMaxim 1:e1c7c1c636af 311
IanBenzMaxim 1:e1c7c1c636af 312 // Close connection
IanBenzMaxim 1:e1c7c1c636af 313 esp8266.closeConnection();
IanBenzMaxim 1:e1c7c1c636af 314 }
IanBenzMaxim 1:e1c7c1c636af 315
IanBenzMaxim 1:e1c7c1c636af 316 return result;
IanBenzMaxim 1:e1c7c1c636af 317 }
IanBenzMaxim 1:e1c7c1c636af 318
IanBenzMaxim 1:e1c7c1c636af 319 std::string WebServerInterface::formatSensorDataPostBody(const SensorData & sensorData)
IanBenzMaxim 1:e1c7c1c636af 320 {
IanBenzMaxim 1:e1c7c1c636af 321 // Create initial post body string from input data
IanBenzMaxim 1:e1c7c1c636af 322 std::ostringstream postBodyStream;
IanBenzMaxim 1:e1c7c1c636af 323 postBodyStream << "Temp" << keyValSeparator << static_cast<int>(sensorData.temp);
IanBenzMaxim 1:e1c7c1c636af 324 postBodyStream << fieldSeparator;
IanBenzMaxim 1:e1c7c1c636af 325 postBodyStream << "FilterLife" << keyValSeparator << static_cast<unsigned>(sensorData.filterLife);
IanBenzMaxim 1:e1c7c1c636af 326 postBodyStream << fieldSeparator;
IanBenzMaxim 1:e1c7c1c636af 327 postBodyStream << "TempAlarm" << keyValSeparator << (sensorData.tempAlarm() ? "true" : "false");
IanBenzMaxim 1:e1c7c1c636af 328 postBodyStream << fieldSeparator;
IanBenzMaxim 1:e1c7c1c636af 329 postBodyStream << "FilterLifeAlarm" << keyValSeparator << (sensorData.filterLifeAlarm() ? "true" : "false");
IanBenzMaxim 1:e1c7c1c636af 330 return postBodyStream.str();
IanBenzMaxim 25:37ea43ff81be 331 }
IanBenzMaxim 25:37ea43ff81be 332
IanBenzMaxim 25:37ea43ff81be 333 void WebServerInterface::setSessionId(const OneWire::RomId & sessionId)
IanBenzMaxim 25:37ea43ff81be 334 {
IanBenzMaxim 25:37ea43ff81be 335 m_sessionIdString = byteArrayToHexString(sessionId.buffer.data(), sessionId.buffer.size());
IanBenzMaxim 25:37ea43ff81be 336 m_sessionId = sessionId;
IanBenzMaxim 1:e1c7c1c636af 337 }