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 20:14:05 2016 +0000
Revision:
27:81a87d29bedd
Parent:
25:37ea43ff81be
Child:
28:e5cdaf13d299
Temporarily moved to a fork of mbed-os due to issues with the implementation of mutexes. Stripped mutex implementation for armcc which should not affect this project since it does not use RTOS features.

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 27:81a87d29bedd 45 const char WebServerInterface::wifiSsid[] = "WifiSsid";
IanBenzMaxim 27:81a87d29bedd 46 const char WebServerInterface::wifiPassword[] = "WifiPassword";
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 }