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.
WebServerInterface.cpp@27:81a87d29bedd, 2016-12-16 (annotated)
- 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?
User | Revision | Line number | New 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 | } |