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 Jan 19 10:33:16 2018 -0600
Revision:
35:3d414ba9ab6c
Parent:
32:0a09505a656d
Updated MaximInterface revision.

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 32:0a09505a656d 31 *******************************************************************************/
IanBenzMaxim 1:e1c7c1c636af 32
IanBenzMaxim 1:e1c7c1c636af 33 #include <vector>
IanBenzMaxim 32:0a09505a656d 34 #include <Serial.h>
IanBenzMaxim 32:0a09505a656d 35 #include <wait_api.h>
IanBenzMaxim 32:0a09505a656d 36 #include <MaximInterface/Devices/DS2465.hpp>
IanBenzMaxim 32:0a09505a656d 37 #include <MaximInterface/Utilities/HexConversions.hpp>
IanBenzMaxim 1:e1c7c1c636af 38 #include "WebServerInterface.hpp"
IanBenzMaxim 29:590a7561318b 39 #include "ESP8266.hpp"
IanBenzMaxim 25:37ea43ff81be 40 #include "SensorData.hpp"
IanBenzMaxim 6:b6bafd0a7013 41
IanBenzMaxim 32:0a09505a656d 42 using namespace MaximInterface;
IanBenzMaxim 1:e1c7c1c636af 43
IanBenzMaxim 30:0784010d6975 44 const char WebServerInterface::wifiSsid[] = "WifiSsid";
IanBenzMaxim 30:0784010d6975 45 const char WebServerInterface::wifiPassword[] = "WifiPassword";
IanBenzMaxim 31:7b10bcb3e0fc 46 const char WebServerInterface::serverAddress[] = "www.maxim-security.com";
IanBenzMaxim 3:ac723be395d9 47 const unsigned int WebServerInterface::serverPort = 80;
IanBenzMaxim 31:7b10bcb3e0fc 48 const char WebServerInterface::serverPostPath[] = "/maxrefdes143/post.php";
IanBenzMaxim 32:0a09505a656d 49 const char WebServerInterface::serverChallengePath[] =
IanBenzMaxim 32:0a09505a656d 50 "/maxrefdes143/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 32:0a09505a656d 64 static bool setHttpPostSecret(DS2465 & macCoproc, const RomId & sessionId) {
IanBenzMaxim 32:0a09505a656d 65 Sha256::SlaveSecretData data;
IanBenzMaxim 32:0a09505a656d 66 data.fill(defaultPaddingByte);
IanBenzMaxim 32:0a09505a656d 67 std::copy(sessionId.begin(), sessionId.end(), data.begin() + 64);
IanBenzMaxim 32:0a09505a656d 68 return !macCoproc.computeSlaveSecret(data);
IanBenzMaxim 1:e1c7c1c636af 69 }
IanBenzMaxim 1:e1c7c1c636af 70
IanBenzMaxim 32:0a09505a656d 71 bool WebServerInterface::initialize() {
IanBenzMaxim 29:590a7561318b 72 esp8266.setPowered(true);
IanBenzMaxim 29:590a7561318b 73 esp8266.reset();
IanBenzMaxim 29:590a7561318b 74 bool result = (esp8266.performSelfTest() == ESP8266::AT_OK);
IanBenzMaxim 32:0a09505a656d 75 if (result) {
IanBenzMaxim 32:0a09505a656d 76 result = (esp8266.setCurrentWifiMode(ESP8266::softAP_station_mode) ==
IanBenzMaxim 32:0a09505a656d 77 ESP8266::AT_OK);
IanBenzMaxim 29:590a7561318b 78 }
IanBenzMaxim 32:0a09505a656d 79 if (result) {
IanBenzMaxim 29:590a7561318b 80 result = (esp8266.setMaxRFTXPower(10) == ESP8266::AT_OK);
IanBenzMaxim 29:590a7561318b 81 }
IanBenzMaxim 32:0a09505a656d 82 if (result) {
IanBenzMaxim 32:0a09505a656d 83 result = (esp8266.joinCurrentAccessPoint(wifiSsid, wifiPassword) ==
IanBenzMaxim 32:0a09505a656d 84 ESP8266::AT_OK);
IanBenzMaxim 29:590a7561318b 85 }
IanBenzMaxim 29:590a7561318b 86 return result;
IanBenzMaxim 29:590a7561318b 87 }
IanBenzMaxim 29:590a7561318b 88
IanBenzMaxim 1:e1c7c1c636af 89 /// Format an HTTP GET request as a string for transmission.
IanBenzMaxim 1:e1c7c1c636af 90 /// @param host Web server address.
IanBenzMaxim 1:e1c7c1c636af 91 /// @param path Web server location to retrieve.
IanBenzMaxim 1:e1c7c1c636af 92 /// @param sessionId Session ID used to identify this controller.
IanBenzMaxim 1:e1c7c1c636af 93 /// @returns GET request string.
IanBenzMaxim 32:0a09505a656d 94 static std::string formatHttpGet(const std::string & host,
IanBenzMaxim 32:0a09505a656d 95 const std::string & path,
IanBenzMaxim 32:0a09505a656d 96 const std::string & sessionId) {
IanBenzMaxim 1:e1c7c1c636af 97 std::ostringstream httpGetStream;
IanBenzMaxim 1:e1c7c1c636af 98 httpGetStream << "GET " << path;
IanBenzMaxim 1:e1c7c1c636af 99 if (sessionId.length() > 0)
IanBenzMaxim 1:e1c7c1c636af 100 httpGetStream << '?' << sessionIdKey << keyValSeparator << sessionId;
IanBenzMaxim 1:e1c7c1c636af 101 httpGetStream << " HTTP/1.1" << newline;
IanBenzMaxim 1:e1c7c1c636af 102 httpGetStream << "Host: " << host << newline;
IanBenzMaxim 1:e1c7c1c636af 103 httpGetStream << newline;
IanBenzMaxim 1:e1c7c1c636af 104 return httpGetStream.str();
IanBenzMaxim 1:e1c7c1c636af 105 }
IanBenzMaxim 1:e1c7c1c636af 106
IanBenzMaxim 1:e1c7c1c636af 107 /// Computes a MAC using the Transport Secret to sign HTTP POST requests.
IanBenzMaxim 32:0a09505a656d 108 /// @param macCoproc
IanBenzMaxim 32:0a09505a656d 109 /// Coprocessor such as the DS2465 used to calculate the authentication MAC.
IanBenzMaxim 1:e1c7c1c636af 110 /// @param input Message array used for MAC calculation.
IanBenzMaxim 1:e1c7c1c636af 111 /// @param ilen Length of array input.
IanBenzMaxim 1:e1c7c1c636af 112 /// @param output Calculated MAC output.
IanBenzMaxim 32:0a09505a656d 113 static void calculateHttpPostMac(const DS2465 & macCoproc,
IanBenzMaxim 32:0a09505a656d 114 const uint8_t * input, size_t ilen,
IanBenzMaxim 32:0a09505a656d 115 Sha256::Hash & output) {
IanBenzMaxim 32:0a09505a656d 116 const size_t blockSize = 32;
IanBenzMaxim 25:37ea43ff81be 117 output.fill(defaultPaddingByte); // Set initial hash value
IanBenzMaxim 32:0a09505a656d 118 Sha256::AuthMacData macData;
IanBenzMaxim 32:0a09505a656d 119 macData.fill(defaultPaddingByte);
IanBenzMaxim 32:0a09505a656d 120 while (ilen > 0) {
IanBenzMaxim 32:0a09505a656d 121 Sha256::AuthMacData::iterator macDataBegin =
IanBenzMaxim 32:0a09505a656d 122 std::copy(output.begin(), output.end(), macData.begin());
IanBenzMaxim 32:0a09505a656d 123 if (ilen >= blockSize) // Full block
IanBenzMaxim 1:e1c7c1c636af 124 {
IanBenzMaxim 32:0a09505a656d 125 std::copy(input, input + blockSize, macDataBegin);
IanBenzMaxim 32:0a09505a656d 126 input += blockSize;
IanBenzMaxim 32:0a09505a656d 127 ilen -= blockSize;
IanBenzMaxim 32:0a09505a656d 128 } else // Partial block with padding
IanBenzMaxim 1:e1c7c1c636af 129 {
IanBenzMaxim 32:0a09505a656d 130 macDataBegin = std::copy(input, input + ilen, macDataBegin);
IanBenzMaxim 32:0a09505a656d 131 std::fill(macDataBegin, macDataBegin + (blockSize - ilen),
IanBenzMaxim 32:0a09505a656d 132 defaultPaddingByte);
IanBenzMaxim 32:0a09505a656d 133 ilen = 0;
IanBenzMaxim 1:e1c7c1c636af 134 }
IanBenzMaxim 1:e1c7c1c636af 135 // Write data to coprocessor and hash block
IanBenzMaxim 32:0a09505a656d 136 macCoproc.computeAuthMac(macData, output);
IanBenzMaxim 1:e1c7c1c636af 137 }
IanBenzMaxim 1:e1c7c1c636af 138 }
IanBenzMaxim 1:e1c7c1c636af 139
IanBenzMaxim 1:e1c7c1c636af 140 /// Format an HTTP POST request as a string for transmission.
IanBenzMaxim 1:e1c7c1c636af 141 /// @param host Web server address.
IanBenzMaxim 1:e1c7c1c636af 142 /// @param path Web server location to receive POST.
IanBenzMaxim 1:e1c7c1c636af 143 /// @param sessionId Session ID used to identify this Controller.
IanBenzMaxim 32:0a09505a656d 144 /// @param macCoproc
IanBenzMaxim 32:0a09505a656d 145 /// Coprocessor such as the DS2465 used to calculate the authentication MAC.
IanBenzMaxim 1:e1c7c1c636af 146 /// @param event Event message type.
IanBenzMaxim 1:e1c7c1c636af 147 /// @param initialPostBody Message body as determined by the event message type.
IanBenzMaxim 32:0a09505a656d 148 /// @param challenge
IanBenzMaxim 32:0a09505a656d 149 /// Challenge previously received from web server for use in authentication MAC.
IanBenzMaxim 1:e1c7c1c636af 150 /// @returns POST request string.
IanBenzMaxim 32:0a09505a656d 151 static std::string formatHttpPost(const std::string & host,
IanBenzMaxim 32:0a09505a656d 152 const std::string & path,
IanBenzMaxim 32:0a09505a656d 153 const std::string & sessionId,
IanBenzMaxim 32:0a09505a656d 154 const DS2465 & macCoproc, PostEvent event,
IanBenzMaxim 32:0a09505a656d 155 const std::string & initialPostBody,
IanBenzMaxim 32:0a09505a656d 156 const uint8_t (&challenge)[challengeLen]) {
IanBenzMaxim 6:b6bafd0a7013 157 const size_t headerReserve = 115, bodyReserve = 200;
IanBenzMaxim 32:0a09505a656d 158
IanBenzMaxim 1:e1c7c1c636af 159 std::string httpPost;
IanBenzMaxim 1:e1c7c1c636af 160 httpPost.reserve(initialPostBody.length() + headerReserve + bodyReserve);
IanBenzMaxim 32:0a09505a656d 161
IanBenzMaxim 1:e1c7c1c636af 162 // Add session ID to post body
IanBenzMaxim 32:0a09505a656d 163 if (sessionId.length() > 0) {
IanBenzMaxim 1:e1c7c1c636af 164 httpPost += sessionIdKey;
IanBenzMaxim 1:e1c7c1c636af 165 httpPost += keyValSeparator;
IanBenzMaxim 1:e1c7c1c636af 166 httpPost += sessionId;
IanBenzMaxim 1:e1c7c1c636af 167 }
IanBenzMaxim 32:0a09505a656d 168
IanBenzMaxim 1:e1c7c1c636af 169 // Add event to post body
IanBenzMaxim 1:e1c7c1c636af 170 std::string eventString;
IanBenzMaxim 32:0a09505a656d 171 switch (event) {
IanBenzMaxim 1:e1c7c1c636af 172 case SensorDataEvent:
IanBenzMaxim 1:e1c7c1c636af 173 eventString = "SensorData";
IanBenzMaxim 1:e1c7c1c636af 174 break;
IanBenzMaxim 32:0a09505a656d 175
IanBenzMaxim 1:e1c7c1c636af 176 case InvalidSensorEvent:
IanBenzMaxim 1:e1c7c1c636af 177 eventString = "InvalidSensor";
IanBenzMaxim 1:e1c7c1c636af 178 break;
IanBenzMaxim 1:e1c7c1c636af 179 }
IanBenzMaxim 32:0a09505a656d 180 if (eventString.length() > 0) {
IanBenzMaxim 1:e1c7c1c636af 181 if (httpPost.length() > 0)
IanBenzMaxim 1:e1c7c1c636af 182 httpPost += fieldSeparator;
IanBenzMaxim 1:e1c7c1c636af 183 httpPost += "Event";
IanBenzMaxim 1:e1c7c1c636af 184 httpPost += keyValSeparator;
IanBenzMaxim 1:e1c7c1c636af 185 httpPost += eventString;
IanBenzMaxim 1:e1c7c1c636af 186 }
IanBenzMaxim 32:0a09505a656d 187
IanBenzMaxim 1:e1c7c1c636af 188 // Add initial post body
IanBenzMaxim 32:0a09505a656d 189 if (initialPostBody.length() > 0) {
IanBenzMaxim 1:e1c7c1c636af 190 if (httpPost.length() > 0)
IanBenzMaxim 1:e1c7c1c636af 191 httpPost += fieldSeparator;
IanBenzMaxim 1:e1c7c1c636af 192 httpPost += initialPostBody;
IanBenzMaxim 1:e1c7c1c636af 193 }
IanBenzMaxim 32:0a09505a656d 194
IanBenzMaxim 1:e1c7c1c636af 195 // Combine initial post body with initial secret and hash
IanBenzMaxim 6:b6bafd0a7013 196 std::vector<uint8_t> hashInput;
IanBenzMaxim 1:e1c7c1c636af 197 hashInput.reserve(challengeLen + httpPost.length());
IanBenzMaxim 25:37ea43ff81be 198 hashInput.assign(challenge, challenge + challengeLen);
IanBenzMaxim 1:e1c7c1c636af 199 hashInput.insert(hashInput.end(), httpPost.begin(), httpPost.end());
IanBenzMaxim 32:0a09505a656d 200 Sha256::Hash mac;
IanBenzMaxim 1:e1c7c1c636af 201 calculateHttpPostMac(macCoproc, &hashInput[0], hashInput.size(), mac);
IanBenzMaxim 32:0a09505a656d 202
IanBenzMaxim 1:e1c7c1c636af 203 char contentLen[5];
IanBenzMaxim 32:0a09505a656d 204 snprintf(contentLen, sizeof(contentLen) / sizeof(contentLen[0]), "%u",
IanBenzMaxim 32:0a09505a656d 205 (hashInput.size() - challengeLen) + (mac.size() * 2) +
IanBenzMaxim 32:0a09505a656d 206 5 /* &MAC= */);
IanBenzMaxim 32:0a09505a656d 207
IanBenzMaxim 1:e1c7c1c636af 208 // Construct full post request
IanBenzMaxim 1:e1c7c1c636af 209 httpPost = "";
IanBenzMaxim 1:e1c7c1c636af 210 httpPost += "POST ";
IanBenzMaxim 1:e1c7c1c636af 211 httpPost += path;
IanBenzMaxim 1:e1c7c1c636af 212 httpPost += " HTTP/1.1";
IanBenzMaxim 1:e1c7c1c636af 213 httpPost += newline;
IanBenzMaxim 1:e1c7c1c636af 214 httpPost += "Host: ";
IanBenzMaxim 1:e1c7c1c636af 215 httpPost += host;
IanBenzMaxim 1:e1c7c1c636af 216 httpPost += newline;
IanBenzMaxim 1:e1c7c1c636af 217 httpPost += "Accept: */*";
IanBenzMaxim 1:e1c7c1c636af 218 httpPost += newline;
IanBenzMaxim 1:e1c7c1c636af 219 httpPost += "Content-Length: ";
IanBenzMaxim 1:e1c7c1c636af 220 httpPost += contentLen;
IanBenzMaxim 1:e1c7c1c636af 221 httpPost += newline;
IanBenzMaxim 1:e1c7c1c636af 222 httpPost += "Content-Type: application/x-www-form-urlencoded";
IanBenzMaxim 1:e1c7c1c636af 223 httpPost += newline;
IanBenzMaxim 1:e1c7c1c636af 224 httpPost += newline;
IanBenzMaxim 1:e1c7c1c636af 225 // Add post body
IanBenzMaxim 32:0a09505a656d 226 httpPost.append(reinterpret_cast<char *>(&hashInput[challengeLen]),
IanBenzMaxim 32:0a09505a656d 227 hashInput.size() - challengeLen);
IanBenzMaxim 1:e1c7c1c636af 228 // Convert hash to hex string and add to post body
IanBenzMaxim 1:e1c7c1c636af 229 httpPost += fieldSeparator;
IanBenzMaxim 1:e1c7c1c636af 230 httpPost += "MAC";
IanBenzMaxim 1:e1c7c1c636af 231 httpPost += keyValSeparator;
IanBenzMaxim 32:0a09505a656d 232 httpPost += byteArrayToHexString(mac.data(), mac.size());
IanBenzMaxim 1:e1c7c1c636af 233 httpPost += newline;
IanBenzMaxim 32:0a09505a656d 234
IanBenzMaxim 1:e1c7c1c636af 235 return httpPost;
IanBenzMaxim 1:e1c7c1c636af 236 }
IanBenzMaxim 1:e1c7c1c636af 237
IanBenzMaxim 32:0a09505a656d 238 bool WebServerInterface::authPostHttpEvent(DS2465 & macCoproc, PostEvent event,
IanBenzMaxim 32:0a09505a656d 239 const std::string & postData,
IanBenzMaxim 32:0a09505a656d 240 bool setSecret) {
IanBenzMaxim 29:590a7561318b 241 const std::string challengeSearch(newline + newline);
IanBenzMaxim 1:e1c7c1c636af 242 bool result;
IanBenzMaxim 29:590a7561318b 243 uint8_t challenge[challengeLen];
IanBenzMaxim 29:590a7561318b 244 std::string response;
IanBenzMaxim 32:0a09505a656d 245
IanBenzMaxim 29:590a7561318b 246 std::memset(challenge, defaultPaddingByte, challengeLen);
IanBenzMaxim 29:590a7561318b 247 response.reserve(300);
IanBenzMaxim 32:0a09505a656d 248
IanBenzMaxim 32:0a09505a656d 249 if (setSecret) {
IanBenzMaxim 25:37ea43ff81be 250 result = setHttpPostSecret(macCoproc, m_sessionId);
IanBenzMaxim 1:e1c7c1c636af 251 if (!result)
IanBenzMaxim 1:e1c7c1c636af 252 return result;
IanBenzMaxim 1:e1c7c1c636af 253 }
IanBenzMaxim 32:0a09505a656d 254
IanBenzMaxim 1:e1c7c1c636af 255 // Open connection
IanBenzMaxim 29:590a7561318b 256 esp8266.clearRecvData(); // Clear received data buffer
IanBenzMaxim 32:0a09505a656d 257 result = (esp8266.openConnection(ESP8266::TCP, serverAddress, 80) ==
IanBenzMaxim 32:0a09505a656d 258 ESP8266::AT_OK);
IanBenzMaxim 32:0a09505a656d 259 if (result) {
IanBenzMaxim 1:e1c7c1c636af 260 // Request challenge
IanBenzMaxim 32:0a09505a656d 261 result =
IanBenzMaxim 32:0a09505a656d 262 (esp8266.sendData(formatHttpGet(serverAddress, serverChallengePath,
IanBenzMaxim 32:0a09505a656d 263 m_sessionIdString)) == ESP8266::AT_OK);
IanBenzMaxim 32:0a09505a656d 264 if (result) {
IanBenzMaxim 1:e1c7c1c636af 265 // Receive server response
IanBenzMaxim 32:0a09505a656d 266 for (int i = 0; i < 10; i++) {
IanBenzMaxim 32:0a09505a656d 267 while (esp8266.recvIpDataReadable()) {
IanBenzMaxim 29:590a7561318b 268 char read = esp8266.getcRecvIpData();
IanBenzMaxim 32:0a09505a656d 269 if (response.length() < response.capacity()) {
IanBenzMaxim 29:590a7561318b 270 response += read;
IanBenzMaxim 32:0a09505a656d 271 } else {
IanBenzMaxim 32:0a09505a656d 272 // Wait for ESP8266 specified recovery time
IanBenzMaxim 32:0a09505a656d 273 wait_ms(ESP8266::sendDataRecoveryTimeMs);
IanBenzMaxim 29:590a7561318b 274 goto close_get_connection;
IanBenzMaxim 1:e1c7c1c636af 275 }
IanBenzMaxim 1:e1c7c1c636af 276 }
IanBenzMaxim 29:590a7561318b 277 wait_ms(100);
IanBenzMaxim 29:590a7561318b 278 }
IanBenzMaxim 29:590a7561318b 279 // Close connection
IanBenzMaxim 29:590a7561318b 280 close_get_connection:
IanBenzMaxim 29:590a7561318b 281 esp8266.closeConnection();
IanBenzMaxim 32:0a09505a656d 282
IanBenzMaxim 29:590a7561318b 283 // Parse challenge from response
IanBenzMaxim 29:590a7561318b 284 size_t challengePos = response.find(challengeSearch);
IanBenzMaxim 32:0a09505a656d 285 const size_t challengeStringLen = challengeLen * 2;
IanBenzMaxim 32:0a09505a656d 286 if ((challengePos != std::string::npos) &&
IanBenzMaxim 32:0a09505a656d 287 ((challengePos + challengeSearch.length() + challengeStringLen) <=
IanBenzMaxim 32:0a09505a656d 288 response.length())) {
IanBenzMaxim 29:590a7561318b 289 challengePos += challengeSearch.length();
IanBenzMaxim 32:0a09505a656d 290 const std::vector<uint_least8_t> parsedChallenge = hexStringToByteArray(
IanBenzMaxim 32:0a09505a656d 291 response.substr(challengePos, challengeStringLen));
IanBenzMaxim 32:0a09505a656d 292 std::copy(parsedChallenge.begin(), parsedChallenge.end(), challenge);
IanBenzMaxim 29:590a7561318b 293 }
IanBenzMaxim 32:0a09505a656d 294
IanBenzMaxim 29:590a7561318b 295 // Post sensor data
IanBenzMaxim 32:0a09505a656d 296 result = (esp8266.openConnection(ESP8266::TCP, serverAddress,
IanBenzMaxim 32:0a09505a656d 297 serverPort) == ESP8266::AT_OK);
IanBenzMaxim 32:0a09505a656d 298 if (result) {
IanBenzMaxim 32:0a09505a656d 299 result =
IanBenzMaxim 32:0a09505a656d 300 (esp8266.sendData(formatHttpPost(
IanBenzMaxim 32:0a09505a656d 301 serverAddress, serverPostPath, m_sessionIdString, macCoproc,
IanBenzMaxim 32:0a09505a656d 302 event, postData, challenge)) == ESP8266::AT_OK);
IanBenzMaxim 32:0a09505a656d 303 wait_ms(
IanBenzMaxim 32:0a09505a656d 304 ESP8266::
IanBenzMaxim 32:0a09505a656d 305 sendDataRecoveryTimeMs); // Wait for ESP8266 specified recovery time
IanBenzMaxim 1:e1c7c1c636af 306 }
IanBenzMaxim 1:e1c7c1c636af 307 }
IanBenzMaxim 32:0a09505a656d 308
IanBenzMaxim 1:e1c7c1c636af 309 // Close connection
IanBenzMaxim 29:590a7561318b 310 esp8266.closeConnection();
IanBenzMaxim 1:e1c7c1c636af 311 }
IanBenzMaxim 32:0a09505a656d 312
IanBenzMaxim 1:e1c7c1c636af 313 return result;
IanBenzMaxim 1:e1c7c1c636af 314 }
IanBenzMaxim 1:e1c7c1c636af 315
IanBenzMaxim 32:0a09505a656d 316 std::string
IanBenzMaxim 32:0a09505a656d 317 WebServerInterface::formatSensorDataPostBody(const SensorData & sensorData) {
IanBenzMaxim 1:e1c7c1c636af 318 // Create initial post body string from input data
IanBenzMaxim 1:e1c7c1c636af 319 std::ostringstream postBodyStream;
IanBenzMaxim 32:0a09505a656d 320 postBodyStream << "Temp" << keyValSeparator
IanBenzMaxim 32:0a09505a656d 321 << static_cast<int>(sensorData.temp);
IanBenzMaxim 1:e1c7c1c636af 322 postBodyStream << fieldSeparator;
IanBenzMaxim 32:0a09505a656d 323 postBodyStream << "FilterLife" << keyValSeparator
IanBenzMaxim 32:0a09505a656d 324 << static_cast<unsigned>(sensorData.filterLife);
IanBenzMaxim 1:e1c7c1c636af 325 postBodyStream << fieldSeparator;
IanBenzMaxim 32:0a09505a656d 326 postBodyStream << "TempAlarm" << keyValSeparator
IanBenzMaxim 32:0a09505a656d 327 << (sensorData.tempAlarm() ? "true" : "false");
IanBenzMaxim 1:e1c7c1c636af 328 postBodyStream << fieldSeparator;
IanBenzMaxim 32:0a09505a656d 329 postBodyStream << "FilterLifeAlarm" << keyValSeparator
IanBenzMaxim 32:0a09505a656d 330 << (sensorData.filterLifeAlarm() ? "true" : "false");
IanBenzMaxim 1:e1c7c1c636af 331 return postBodyStream.str();
IanBenzMaxim 25:37ea43ff81be 332 }
IanBenzMaxim 25:37ea43ff81be 333
IanBenzMaxim 32:0a09505a656d 334 void WebServerInterface::setSessionId(const RomId & sessionId) {
IanBenzMaxim 32:0a09505a656d 335 m_sessionIdString = byteArrayToHexString(sessionId.data(), sessionId.size());
IanBenzMaxim 32:0a09505a656d 336 m_sessionId = sessionId;
IanBenzMaxim 1:e1c7c1c636af 337 }