DeepCover Embedded Security in IoT: Public-key Secured Data Paths

Dependencies:   MaximInterface

The MAXREFDES155# is an internet-of-things (IoT) embedded-security reference design, built to authenticate and control a sensing node using elliptic-curve-based public-key cryptography with control and notification from a web server.

The hardware includes an ARM® mbed™ shield and attached sensor endpoint. The shield contains a DS2476 DeepCover® ECDSA/SHA-2 coprocessor, Wifi communication, LCD push-button controls, and status LEDs. The sensor endpoint is attached to the shield using a 300mm cable and contains a DS28C36 DeepCover ECDSA/SHA-2 authenticator, IR-thermal sensor, and aiming laser for the IR sensor. The MAXREFDES155# is equipped with a standard Arduino® form-factor shield connector for immediate testing using an mbed board such as the MAX32600MBED#. The combination of these two devices represent an IoT device. Communication to the web server is accomplished with the shield Wifi circuitry. Communication from the shield to the attached sensor module is accomplished over I2C . The sensor module represents an IoT endpoint that generates small data with a requirement for message authenticity/integrity and secure on/off operational control.

The design is hierarchical with each mbed platform and shield communicating data from the sensor node to a web server that maintains a centralized log and dispatches notifications as necessary. The simplicity of this design enables rapid integration into any star-topology IoT network to provide security with the low overhead and cost provided by the ECDSA-P256 asymmetric-key and SHA-256 symmetric-key algorithms.

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

Committer:
IanBenzMaxim
Date:
Fri Jan 19 10:28:27 2018 -0600
Revision:
15:75404fab3615
Parent:
14:dc839a69379b
Updated MaximInterface revision.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
IanBenzMaxim 0:33d4e66780c0 1 /*******************************************************************************
IanBenzMaxim 0:33d4e66780c0 2 * Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved.
IanBenzMaxim 0:33d4e66780c0 3 *
IanBenzMaxim 0:33d4e66780c0 4 * Permission is hereby granted, free of charge, to any person obtaining a
IanBenzMaxim 0:33d4e66780c0 5 * copy of this software and associated documentation files (the "Software"),
IanBenzMaxim 0:33d4e66780c0 6 * to deal in the Software without restriction, including without limitation
IanBenzMaxim 0:33d4e66780c0 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
IanBenzMaxim 0:33d4e66780c0 8 * and/or sell copies of the Software, and to permit persons to whom the
IanBenzMaxim 0:33d4e66780c0 9 * Software is furnished to do so, subject to the following conditions:
IanBenzMaxim 0:33d4e66780c0 10 *
IanBenzMaxim 0:33d4e66780c0 11 * The above copyright notice and this permission notice shall be included
IanBenzMaxim 0:33d4e66780c0 12 * in all copies or substantial portions of the Software.
IanBenzMaxim 0:33d4e66780c0 13 *
IanBenzMaxim 0:33d4e66780c0 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
IanBenzMaxim 0:33d4e66780c0 15 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
IanBenzMaxim 0:33d4e66780c0 16 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IanBenzMaxim 0:33d4e66780c0 17 * IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES
IanBenzMaxim 0:33d4e66780c0 18 * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
IanBenzMaxim 0:33d4e66780c0 19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
IanBenzMaxim 0:33d4e66780c0 20 * OTHER DEALINGS IN THE SOFTWARE.
IanBenzMaxim 0:33d4e66780c0 21 *
IanBenzMaxim 0:33d4e66780c0 22 * Except as contained in this notice, the name of Maxim Integrated
IanBenzMaxim 0:33d4e66780c0 23 * Products, Inc. shall not be used except as stated in the Maxim Integrated
IanBenzMaxim 0:33d4e66780c0 24 * Products, Inc. Branding Policy.
IanBenzMaxim 0:33d4e66780c0 25 *
IanBenzMaxim 0:33d4e66780c0 26 * The mere transfer of this software does not imply any licenses
IanBenzMaxim 0:33d4e66780c0 27 * of trade secrets, proprietary technology, copyrights, patents,
IanBenzMaxim 0:33d4e66780c0 28 * trademarks, maskwork rights, or any other form of intellectual
IanBenzMaxim 0:33d4e66780c0 29 * property whatsoever. Maxim Integrated Products, Inc. retains all
IanBenzMaxim 0:33d4e66780c0 30 * ownership rights.
IanBenzMaxim 0:33d4e66780c0 31 *******************************************************************************/
IanBenzMaxim 0:33d4e66780c0 32
IanBenzMaxim 0:33d4e66780c0 33 #define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN
IanBenzMaxim 0:33d4e66780c0 34 #include <rapidjson/document.h>
IanBenzMaxim 0:33d4e66780c0 35 #include <rapidjson/writer.h>
IanBenzMaxim 0:33d4e66780c0 36 #include <rapidjson/stringbuffer.h>
IanBenzMaxim 0:33d4e66780c0 37
IanBenzMaxim 0:33d4e66780c0 38 #include <stdint.h>
IanBenzMaxim 4:cd2dc3e7433f 39 #include <stdio.h>
IanBenzMaxim 0:33d4e66780c0 40 #include <cassert>
IanBenzMaxim 3:d2799d8497c0 41 #include <cstdio>
IanBenzMaxim 0:33d4e66780c0 42 #include <string>
IanBenzMaxim 0:33d4e66780c0 43 #include <utility>
IanBenzMaxim 13:6a6225690c2e 44 #include <MaximInterface/Devices/DS28C36_DS2476.hpp>
IanBenzMaxim 13:6a6225690c2e 45 #include <MaximInterface/Utilities/HexConversions.hpp>
IanBenzMaxim 13:6a6225690c2e 46 #include "DisplayGraphicWindow.hpp"
IanBenzMaxim 13:6a6225690c2e 47 #include "DisplayIdWindow.hpp"
IanBenzMaxim 13:6a6225690c2e 48 #include "ErrorWindow.hpp"
IanBenzMaxim 0:33d4e66780c0 49 #include "Image.hpp"
IanBenzMaxim 13:6a6225690c2e 50 #include "MakeFunction.hpp"
IanBenzMaxim 13:6a6225690c2e 51 #include "NormalOperationWindow.hpp"
IanBenzMaxim 0:33d4e66780c0 52 #include "Text.hpp"
IanBenzMaxim 0:33d4e66780c0 53 #include "WindowManager.hpp"
IanBenzMaxim 13:6a6225690c2e 54
IanBenzMaxim 13:6a6225690c2e 55 using namespace MaximInterface;
IanBenzMaxim 0:33d4e66780c0 56
IanBenzMaxim 0:33d4e66780c0 57 extern DS2476 coproc;
IanBenzMaxim 0:33d4e66780c0 58 extern SensorNode sensorNode;
IanBenzMaxim 0:33d4e66780c0 59 extern std::string webId;
IanBenzMaxim 0:33d4e66780c0 60
IanBenzMaxim 0:33d4e66780c0 61 extern "C" {
IanBenzMaxim 13:6a6225690c2e 62 void ComputeSHA256(unsigned char * message, short length,
IanBenzMaxim 13:6a6225690c2e 63 unsigned short skipconst, unsigned short reverse,
IanBenzMaxim 13:6a6225690c2e 64 unsigned char * digest);
IanBenzMaxim 0:33d4e66780c0 65 }
IanBenzMaxim 0:33d4e66780c0 66
IanBenzMaxim 13:6a6225690c2e 67 // Default allocation size for rapidjson.
IanBenzMaxim 13:6a6225690c2e 68 static const size_t defaultChunkSize = 256;
IanBenzMaxim 13:6a6225690c2e 69 // Number of decimal places to use when writing JSON.
IanBenzMaxim 13:6a6225690c2e 70 static const int jsonMaxDecimalPlaces = 2;
IanBenzMaxim 0:33d4e66780c0 71
IanBenzMaxim 0:33d4e66780c0 72 // Separate multiple JSON commands received on the socket.
IanBenzMaxim 0:33d4e66780c0 73 // Returns a list of begin and end iterators within the input message.
IanBenzMaxim 13:6a6225690c2e 74 static std::vector<std::pair<const char *, const char *> >
IanBenzMaxim 13:6a6225690c2e 75 separateCommands(const char * receivedData, size_t receivedDataSize) {
IanBenzMaxim 13:6a6225690c2e 76 std::vector<std::pair<const char *, const char *> > commands;
IanBenzMaxim 13:6a6225690c2e 77 int counter = 0;
IanBenzMaxim 13:6a6225690c2e 78 size_t beginIdx;
IanBenzMaxim 13:6a6225690c2e 79 for (size_t i = 0; i < receivedDataSize; i++) {
IanBenzMaxim 13:6a6225690c2e 80 if (receivedData[i] == '{') {
IanBenzMaxim 13:6a6225690c2e 81 if (counter == 0) {
IanBenzMaxim 13:6a6225690c2e 82 beginIdx = i;
IanBenzMaxim 13:6a6225690c2e 83 }
IanBenzMaxim 13:6a6225690c2e 84 counter++;
IanBenzMaxim 13:6a6225690c2e 85 } else if (receivedData[i] == '}') {
IanBenzMaxim 13:6a6225690c2e 86 if (counter > 0) {
IanBenzMaxim 13:6a6225690c2e 87 counter--;
IanBenzMaxim 13:6a6225690c2e 88 if (counter == 0) {
IanBenzMaxim 13:6a6225690c2e 89 commands.push_back(
IanBenzMaxim 13:6a6225690c2e 90 std::make_pair(&receivedData[beginIdx], &receivedData[i + 1]));
IanBenzMaxim 0:33d4e66780c0 91 }
IanBenzMaxim 13:6a6225690c2e 92 }
IanBenzMaxim 0:33d4e66780c0 93 }
IanBenzMaxim 13:6a6225690c2e 94 }
IanBenzMaxim 13:6a6225690c2e 95 return commands;
IanBenzMaxim 0:33d4e66780c0 96 }
IanBenzMaxim 0:33d4e66780c0 97
IanBenzMaxim 12:46c5974a565f 98 // Creates a new command challenge, and adds it to an existing JSON document.
IanBenzMaxim 13:6a6225690c2e 99 static error_code addCommandChallenge(rapidjson::Document & document,
IanBenzMaxim 13:6a6225690c2e 100 CommandChallenge & commandChallenge) {
IanBenzMaxim 13:6a6225690c2e 101 error_code result =
IanBenzMaxim 14:dc839a69379b 102 coproc.readRng(commandChallenge.data(), commandChallenge.size());
IanBenzMaxim 13:6a6225690c2e 103 if (!result) {
IanBenzMaxim 13:6a6225690c2e 104 document.AddMember(
IanBenzMaxim 13:6a6225690c2e 105 "challenge",
IanBenzMaxim 13:6a6225690c2e 106 rapidjson::Value(byteArrayToHexString(commandChallenge.data(),
IanBenzMaxim 13:6a6225690c2e 107 commandChallenge.size()).c_str(),
IanBenzMaxim 13:6a6225690c2e 108 document.GetAllocator()).Move(),
IanBenzMaxim 13:6a6225690c2e 109 document.GetAllocator());
IanBenzMaxim 13:6a6225690c2e 110 }
IanBenzMaxim 13:6a6225690c2e 111 return result;
IanBenzMaxim 12:46c5974a565f 112 }
IanBenzMaxim 12:46c5974a565f 113
IanBenzMaxim 0:33d4e66780c0 114 // Adds signature information to an existing JSON document.
IanBenzMaxim 13:6a6225690c2e 115 static error_code signData(bool validSignature,
IanBenzMaxim 13:6a6225690c2e 116 const ResponseChallenge & challenge,
IanBenzMaxim 13:6a6225690c2e 117 rapidjson::Document & document) {
IanBenzMaxim 13:6a6225690c2e 118 // Move contents of the document to a new location, and create an empty object
IanBenzMaxim 13:6a6225690c2e 119 // in the document.
IanBenzMaxim 13:6a6225690c2e 120 rapidjson::Value data(rapidjson::kObjectType);
IanBenzMaxim 13:6a6225690c2e 121 data.Swap(document);
IanBenzMaxim 13:6a6225690c2e 122 // Convert data to a string and generate a signature from that string.
IanBenzMaxim 13:6a6225690c2e 123 rapidjson::StringBuffer dataBuffer;
IanBenzMaxim 13:6a6225690c2e 124 rapidjson::Writer<rapidjson::StringBuffer> writer(dataBuffer);
IanBenzMaxim 13:6a6225690c2e 125 writer.SetMaxDecimalPlaces(jsonMaxDecimalPlaces);
IanBenzMaxim 13:6a6225690c2e 126 data.Accept(writer);
IanBenzMaxim 13:6a6225690c2e 127 std::vector<uint8_t> signDataBuffer(
IanBenzMaxim 13:6a6225690c2e 128 dataBuffer.GetString(), dataBuffer.GetString() + dataBuffer.GetLength());
IanBenzMaxim 13:6a6225690c2e 129 signDataBuffer.insert(signDataBuffer.end(), challenge.begin(),
IanBenzMaxim 13:6a6225690c2e 130 challenge.end());
IanBenzMaxim 13:6a6225690c2e 131 Sha256::Hash hash;
IanBenzMaxim 13:6a6225690c2e 132 ComputeSHA256(&signDataBuffer[0], signDataBuffer.size(), false, false,
IanBenzMaxim 13:6a6225690c2e 133 hash.data());
IanBenzMaxim 13:6a6225690c2e 134 error_code result = coproc.writeBuffer(hash.data(), hash.size());
IanBenzMaxim 13:6a6225690c2e 135 if (!result) {
IanBenzMaxim 13:6a6225690c2e 136 Ecc256::Signature signatureBuffer;
IanBenzMaxim 13:6a6225690c2e 137 result = coproc.generateEcdsaSignature(DS2476::KeyNumA, signatureBuffer);
IanBenzMaxim 13:6a6225690c2e 138 if (!result) {
IanBenzMaxim 13:6a6225690c2e 139 if (!validSignature)
IanBenzMaxim 13:6a6225690c2e 140 signatureBuffer.r[0]++;
IanBenzMaxim 13:6a6225690c2e 141 // Construct the final document with the original data and the generated
IanBenzMaxim 13:6a6225690c2e 142 // signature.
IanBenzMaxim 13:6a6225690c2e 143 rapidjson::Value signature(rapidjson::kObjectType);
IanBenzMaxim 13:6a6225690c2e 144 signature.AddMember(
IanBenzMaxim 13:6a6225690c2e 145 "r",
IanBenzMaxim 13:6a6225690c2e 146 rapidjson::Value(byteArrayToHexString(signatureBuffer.r.data(),
IanBenzMaxim 13:6a6225690c2e 147 signatureBuffer.r.size()).c_str(),
IanBenzMaxim 13:6a6225690c2e 148 document.GetAllocator()).Move(),
IanBenzMaxim 13:6a6225690c2e 149 document.GetAllocator());
IanBenzMaxim 13:6a6225690c2e 150 signature.AddMember(
IanBenzMaxim 13:6a6225690c2e 151 "s",
IanBenzMaxim 13:6a6225690c2e 152 rapidjson::Value(byteArrayToHexString(signatureBuffer.s.data(),
IanBenzMaxim 13:6a6225690c2e 153 signatureBuffer.s.size()).c_str(),
IanBenzMaxim 13:6a6225690c2e 154 document.GetAllocator()).Move(),
IanBenzMaxim 13:6a6225690c2e 155 document.GetAllocator());
IanBenzMaxim 13:6a6225690c2e 156 document.AddMember("data", data, document.GetAllocator());
IanBenzMaxim 13:6a6225690c2e 157 document.AddMember("signature", signature, document.GetAllocator());
IanBenzMaxim 0:33d4e66780c0 158 }
IanBenzMaxim 13:6a6225690c2e 159 }
IanBenzMaxim 13:6a6225690c2e 160 return result;
IanBenzMaxim 0:33d4e66780c0 161 }
IanBenzMaxim 0:33d4e66780c0 162
IanBenzMaxim 13:6a6225690c2e 163 // Finalizes a command response to the server by adding the next command
IanBenzMaxim 13:6a6225690c2e 164 // challenge and signing the data.
IanBenzMaxim 13:6a6225690c2e 165 static error_code finalizeResponse(bool validSignature,
IanBenzMaxim 13:6a6225690c2e 166 const ResponseChallenge & responseChallenge,
IanBenzMaxim 13:6a6225690c2e 167 rapidjson::Document & document,
IanBenzMaxim 13:6a6225690c2e 168 CommandChallenge & commandChallenge) {
IanBenzMaxim 13:6a6225690c2e 169 error_code result = addCommandChallenge(document, commandChallenge);
IanBenzMaxim 13:6a6225690c2e 170 if (!result) {
IanBenzMaxim 13:6a6225690c2e 171 result = signData(validSignature, responseChallenge, document);
IanBenzMaxim 13:6a6225690c2e 172 }
IanBenzMaxim 13:6a6225690c2e 173 return result;
IanBenzMaxim 12:46c5974a565f 174 }
IanBenzMaxim 12:46c5974a565f 175
IanBenzMaxim 0:33d4e66780c0 176 // Parse and verify a signed JSON string.
IanBenzMaxim 12:46c5974a565f 177 template <typename VerifyDataIt>
IanBenzMaxim 13:6a6225690c2e 178 static error_code verifySignedData(VerifyDataIt verifyDataBegin,
IanBenzMaxim 13:6a6225690c2e 179 VerifyDataIt verifyDataEnd,
IanBenzMaxim 13:6a6225690c2e 180 const CommandChallenge & commandChallenge,
IanBenzMaxim 13:6a6225690c2e 181 rapidjson::Document & signedData) {
IanBenzMaxim 13:6a6225690c2e 182 using rapidjson::Value;
IanBenzMaxim 13:6a6225690c2e 183 using std::string;
IanBenzMaxim 13:6a6225690c2e 184
IanBenzMaxim 13:6a6225690c2e 185 // Parse string and validate object schema.
IanBenzMaxim 13:6a6225690c2e 186 string verifyData(verifyDataBegin, verifyDataEnd);
IanBenzMaxim 13:6a6225690c2e 187 signedData.Parse(verifyData.c_str());
IanBenzMaxim 13:6a6225690c2e 188 if (!(signedData.IsObject() && signedData.HasMember("data") &&
IanBenzMaxim 13:6a6225690c2e 189 signedData.HasMember("signature"))) {
IanBenzMaxim 13:6a6225690c2e 190 signedData.RemoveAllMembers();
IanBenzMaxim 13:6a6225690c2e 191 return make_error_code(DS2476::AuthenticationError);
IanBenzMaxim 13:6a6225690c2e 192 }
IanBenzMaxim 13:6a6225690c2e 193 Value & data = signedData["data"];
IanBenzMaxim 13:6a6225690c2e 194 const Value & signature = signedData["signature"];
IanBenzMaxim 13:6a6225690c2e 195 if (!(data.IsObject() && signature.IsObject() && signature.HasMember("r") &&
IanBenzMaxim 13:6a6225690c2e 196 signature.HasMember("s"))) {
IanBenzMaxim 13:6a6225690c2e 197 signedData.RemoveAllMembers();
IanBenzMaxim 13:6a6225690c2e 198 return make_error_code(DS2476::AuthenticationError);
IanBenzMaxim 13:6a6225690c2e 199 }
IanBenzMaxim 13:6a6225690c2e 200 const Value & signatureR = signature["r"];
IanBenzMaxim 13:6a6225690c2e 201 const Value & signatureS = signature["s"];
IanBenzMaxim 13:6a6225690c2e 202 if (!(signatureR.IsString() && signatureS.IsString())) {
IanBenzMaxim 13:6a6225690c2e 203 signedData.RemoveAllMembers();
IanBenzMaxim 13:6a6225690c2e 204 return make_error_code(DS2476::AuthenticationError);
IanBenzMaxim 13:6a6225690c2e 205 }
IanBenzMaxim 13:6a6225690c2e 206
IanBenzMaxim 13:6a6225690c2e 207 // Parse signature.
IanBenzMaxim 13:6a6225690c2e 208 std::vector<uint8_t> parsedBytes = hexStringToByteArray(
IanBenzMaxim 13:6a6225690c2e 209 string(signatureR.GetString(), signatureR.GetStringLength()));
IanBenzMaxim 13:6a6225690c2e 210 Ecc256::Signature signatureBuffer;
IanBenzMaxim 13:6a6225690c2e 211 if (parsedBytes.size() != signatureBuffer.r.size()) {
IanBenzMaxim 13:6a6225690c2e 212 signedData.RemoveAllMembers();
IanBenzMaxim 13:6a6225690c2e 213 return make_error_code(DS2476::AuthenticationError);
IanBenzMaxim 13:6a6225690c2e 214 }
IanBenzMaxim 13:6a6225690c2e 215 std::copy(parsedBytes.begin(), parsedBytes.end(), signatureBuffer.r.begin());
IanBenzMaxim 13:6a6225690c2e 216 parsedBytes = hexStringToByteArray(
IanBenzMaxim 13:6a6225690c2e 217 string(signatureS.GetString(), signatureS.GetStringLength()));
IanBenzMaxim 13:6a6225690c2e 218 if (parsedBytes.size() != signatureBuffer.s.size()) {
IanBenzMaxim 13:6a6225690c2e 219 signedData.RemoveAllMembers();
IanBenzMaxim 13:6a6225690c2e 220 return make_error_code(DS2476::AuthenticationError);
IanBenzMaxim 13:6a6225690c2e 221 }
IanBenzMaxim 13:6a6225690c2e 222 std::copy(parsedBytes.begin(), parsedBytes.end(), signatureBuffer.s.begin());
IanBenzMaxim 13:6a6225690c2e 223
IanBenzMaxim 13:6a6225690c2e 224 // Get data to hash.
IanBenzMaxim 13:6a6225690c2e 225 // Need to use string searching here since there isn't currently a way to
IanBenzMaxim 13:6a6225690c2e 226 // access raw elements in rapidjson, and creating another copy of the data
IanBenzMaxim 13:6a6225690c2e 227 // might consume too much memory.
IanBenzMaxim 13:6a6225690c2e 228 const string rawDataSearch("\"data\":");
IanBenzMaxim 13:6a6225690c2e 229 string::size_type rawDataBegin = verifyData.find(rawDataSearch);
IanBenzMaxim 13:6a6225690c2e 230 if ((rawDataBegin == string::npos) ||
IanBenzMaxim 13:6a6225690c2e 231 ((rawDataBegin + rawDataSearch.size()) >= verifyData.size())) {
IanBenzMaxim 13:6a6225690c2e 232 signedData.RemoveAllMembers();
IanBenzMaxim 13:6a6225690c2e 233 return make_error_code(DS2476::AuthenticationError);
IanBenzMaxim 13:6a6225690c2e 234 }
IanBenzMaxim 13:6a6225690c2e 235 rawDataBegin += rawDataSearch.size();
IanBenzMaxim 13:6a6225690c2e 236 string::size_type rawDataEnd =
IanBenzMaxim 13:6a6225690c2e 237 verifyData.find(",\"signature\"", rawDataBegin);
IanBenzMaxim 13:6a6225690c2e 238 if (rawDataEnd == string::npos) {
IanBenzMaxim 13:6a6225690c2e 239 signedData.RemoveAllMembers();
IanBenzMaxim 13:6a6225690c2e 240 return make_error_code(DS2476::AuthenticationError);
IanBenzMaxim 13:6a6225690c2e 241 }
IanBenzMaxim 13:6a6225690c2e 242 verifyData.erase(rawDataEnd);
IanBenzMaxim 13:6a6225690c2e 243 verifyData.erase(0, rawDataBegin);
IanBenzMaxim 13:6a6225690c2e 244 // Add in command challenge to data that will be verified.
IanBenzMaxim 13:6a6225690c2e 245 verifyData.append(commandChallenge.begin(), commandChallenge.end());
IanBenzMaxim 13:6a6225690c2e 246
IanBenzMaxim 13:6a6225690c2e 247 // Compute hash of the data.
IanBenzMaxim 13:6a6225690c2e 248 error_code result = computeMultiblockHash(
IanBenzMaxim 13:6a6225690c2e 249 coproc, reinterpret_cast<const uint_least8_t *>(verifyData.data()),
IanBenzMaxim 13:6a6225690c2e 250 verifyData.size());
IanBenzMaxim 13:6a6225690c2e 251 if (result) {
IanBenzMaxim 13:6a6225690c2e 252 signedData.RemoveAllMembers();
IanBenzMaxim 0:33d4e66780c0 253 return result;
IanBenzMaxim 13:6a6225690c2e 254 }
IanBenzMaxim 13:6a6225690c2e 255 // Verify signature.
IanBenzMaxim 13:6a6225690c2e 256 result = coproc.verifyEcdsaSignature(DS2476::KeyNumC, DS2476::THASH,
IanBenzMaxim 13:6a6225690c2e 257 signatureBuffer);
IanBenzMaxim 13:6a6225690c2e 258 if (result) {
IanBenzMaxim 13:6a6225690c2e 259 signedData.RemoveAllMembers();
IanBenzMaxim 13:6a6225690c2e 260 return result;
IanBenzMaxim 13:6a6225690c2e 261 }
IanBenzMaxim 13:6a6225690c2e 262
IanBenzMaxim 13:6a6225690c2e 263 // Strip signing information from document.
IanBenzMaxim 13:6a6225690c2e 264 rapidjson::Value swapObject(rapidjson::kObjectType);
IanBenzMaxim 13:6a6225690c2e 265 swapObject.Swap(data);
IanBenzMaxim 13:6a6225690c2e 266 swapObject.Swap(signedData);
IanBenzMaxim 13:6a6225690c2e 267 return result;
IanBenzMaxim 0:33d4e66780c0 268 }
IanBenzMaxim 0:33d4e66780c0 269
IanBenzMaxim 0:33d4e66780c0 270 // Send a JSON document to the server.
IanBenzMaxim 13:6a6225690c2e 271 static void sendJson(const rapidjson::Value & document, TCPSocket & socket) {
IanBenzMaxim 13:6a6225690c2e 272 rapidjson::StringBuffer buffer;
IanBenzMaxim 13:6a6225690c2e 273 rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
IanBenzMaxim 13:6a6225690c2e 274 writer.SetMaxDecimalPlaces(jsonMaxDecimalPlaces);
IanBenzMaxim 13:6a6225690c2e 275 document.Accept(writer);
IanBenzMaxim 13:6a6225690c2e 276 socket.send(buffer.GetString(), buffer.GetLength());
IanBenzMaxim 0:33d4e66780c0 277 }
IanBenzMaxim 0:33d4e66780c0 278
IanBenzMaxim 13:6a6225690c2e 279 void NormalOperationWindow::sendMessage(const char * message) {
IanBenzMaxim 13:6a6225690c2e 280 rapidjson::MemoryPoolAllocator<> allocator(defaultChunkSize);
IanBenzMaxim 13:6a6225690c2e 281 rapidjson::Document document(rapidjson::kObjectType, &allocator);
IanBenzMaxim 13:6a6225690c2e 282 document.AddMember("message", rapidjson::StringRef(message),
IanBenzMaxim 13:6a6225690c2e 283 document.GetAllocator());
IanBenzMaxim 13:6a6225690c2e 284 sendJson(document, *socket);
IanBenzMaxim 0:33d4e66780c0 285 }
IanBenzMaxim 0:33d4e66780c0 286
IanBenzMaxim 13:6a6225690c2e 287 static std::string getValidSignatureButtonText(bool validSignature) {
IanBenzMaxim 13:6a6225690c2e 288 return validSignature ? "Use invalid sig." : "Use valid sig.";
IanBenzMaxim 0:33d4e66780c0 289 }
IanBenzMaxim 0:33d4e66780c0 290
IanBenzMaxim 13:6a6225690c2e 291 void NormalOperationWindow::showWebId(Button *) {
IanBenzMaxim 13:6a6225690c2e 292 if (windowManager() != NULL) {
IanBenzMaxim 13:6a6225690c2e 293 std::auto_ptr<Window> window(
IanBenzMaxim 13:6a6225690c2e 294 new DisplayIdWindow(DisplayIdWindow::PopupMode));
IanBenzMaxim 13:6a6225690c2e 295 windowManager()->push(window);
IanBenzMaxim 13:6a6225690c2e 296 }
IanBenzMaxim 13:6a6225690c2e 297 }
IanBenzMaxim 13:6a6225690c2e 298
IanBenzMaxim 13:6a6225690c2e 299 void NormalOperationWindow::toggleValidSignature(Button *) {
IanBenzMaxim 13:6a6225690c2e 300 validSignature = !validSignature;
IanBenzMaxim 13:6a6225690c2e 301 validSignatureButton.setText(getValidSignatureButtonText(validSignature));
IanBenzMaxim 13:6a6225690c2e 302 }
IanBenzMaxim 13:6a6225690c2e 303
IanBenzMaxim 13:6a6225690c2e 304 NormalOperationWindow::NormalOperationWindow(std::auto_ptr<TCPSocket> & socket)
IanBenzMaxim 13:6a6225690c2e 305 : socket(socket) /* Move construct */, sendChallenge(true),
IanBenzMaxim 13:6a6225690c2e 306 validSignature(true), lastSensorNodeState(SensorNode::Disconnected),
IanBenzMaxim 13:6a6225690c2e 307 lastObjectTemp(0), lastAmbientTemp(0) {
IanBenzMaxim 13:6a6225690c2e 308 assert(this->socket.get() != NULL);
IanBenzMaxim 13:6a6225690c2e 309
IanBenzMaxim 13:6a6225690c2e 310 validSignatureButton.setParent(this);
IanBenzMaxim 13:6a6225690c2e 311 validSignatureButton.setText(getValidSignatureButtonText(validSignature));
IanBenzMaxim 13:6a6225690c2e 312 validSignatureButton.setClickedHandler(
IanBenzMaxim 13:6a6225690c2e 313 makeFunction(this, &NormalOperationWindow::toggleValidSignature));
IanBenzMaxim 13:6a6225690c2e 314 showWebIdButton.setParent(this);
IanBenzMaxim 13:6a6225690c2e 315 showWebIdButton.setText("Show web ID");
IanBenzMaxim 13:6a6225690c2e 316 showWebIdButton.setClickedHandler(
IanBenzMaxim 13:6a6225690c2e 317 makeFunction(this, &NormalOperationWindow::showWebId));
IanBenzMaxim 13:6a6225690c2e 318 validSignatureButton.setFocused();
IanBenzMaxim 0:33d4e66780c0 319 }
IanBenzMaxim 0:33d4e66780c0 320
IanBenzMaxim 13:6a6225690c2e 321 NormalOperationWindow::Result
IanBenzMaxim 13:6a6225690c2e 322 NormalOperationWindow::sendStatus(const ResponseChallenge & responseChallenge) {
IanBenzMaxim 13:6a6225690c2e 323 rapidjson::MemoryPoolAllocator<> allocator(defaultChunkSize);
IanBenzMaxim 13:6a6225690c2e 324 rapidjson::Document document(rapidjson::kObjectType, &allocator);
IanBenzMaxim 13:6a6225690c2e 325
IanBenzMaxim 13:6a6225690c2e 326 // Insert Web ID.
IanBenzMaxim 13:6a6225690c2e 327 document.AddMember("id", rapidjson::StringRef(webId.c_str()),
IanBenzMaxim 13:6a6225690c2e 328 document.GetAllocator());
IanBenzMaxim 13:6a6225690c2e 329
IanBenzMaxim 13:6a6225690c2e 330 // Insert device public key.
IanBenzMaxim 13:6a6225690c2e 331 rapidjson::Value publicKey(rapidjson::kObjectType);
IanBenzMaxim 13:6a6225690c2e 332 DS2476::Page page;
IanBenzMaxim 13:6a6225690c2e 333 error_code result = coproc.readMemory(DS2476::PublicKeyAX, page);
IanBenzMaxim 13:6a6225690c2e 334 if (result) {
IanBenzMaxim 13:6a6225690c2e 335 if (windowManager() != NULL) {
IanBenzMaxim 13:6a6225690c2e 336 windowManager()->pop();
IanBenzMaxim 13:6a6225690c2e 337 std::auto_ptr<Window> window(
IanBenzMaxim 13:6a6225690c2e 338 new ErrorWindow("Failed to read PublicKeyAX"));
IanBenzMaxim 13:6a6225690c2e 339 windowManager()->push(window);
IanBenzMaxim 0:33d4e66780c0 340 }
IanBenzMaxim 13:6a6225690c2e 341 return WindowsChanged;
IanBenzMaxim 13:6a6225690c2e 342 }
IanBenzMaxim 13:6a6225690c2e 343 publicKey.AddMember(
IanBenzMaxim 13:6a6225690c2e 344 "x",
IanBenzMaxim 13:6a6225690c2e 345 rapidjson::Value(byteArrayToHexString(page.data(), page.size()).c_str(),
IanBenzMaxim 13:6a6225690c2e 346 document.GetAllocator()).Move(),
IanBenzMaxim 13:6a6225690c2e 347 document.GetAllocator());
IanBenzMaxim 13:6a6225690c2e 348 result = coproc.readMemory(DS2476::PublicKeyAY, page);
IanBenzMaxim 13:6a6225690c2e 349 if (result) {
IanBenzMaxim 13:6a6225690c2e 350 if (windowManager() != NULL) {
IanBenzMaxim 13:6a6225690c2e 351 windowManager()->pop();
IanBenzMaxim 13:6a6225690c2e 352 std::auto_ptr<Window> window(
IanBenzMaxim 13:6a6225690c2e 353 new ErrorWindow("Failed to read PublicKeyAY"));
IanBenzMaxim 13:6a6225690c2e 354 windowManager()->push(window);
IanBenzMaxim 0:33d4e66780c0 355 }
IanBenzMaxim 13:6a6225690c2e 356 return WindowsChanged;
IanBenzMaxim 13:6a6225690c2e 357 }
IanBenzMaxim 13:6a6225690c2e 358 publicKey.AddMember(
IanBenzMaxim 13:6a6225690c2e 359 "y",
IanBenzMaxim 13:6a6225690c2e 360 rapidjson::Value(byteArrayToHexString(page.data(), page.size()).c_str(),
IanBenzMaxim 13:6a6225690c2e 361 document.GetAllocator()).Move(),
IanBenzMaxim 13:6a6225690c2e 362 document.GetAllocator());
IanBenzMaxim 13:6a6225690c2e 363 document.AddMember("publicKey", publicKey, document.GetAllocator());
IanBenzMaxim 0:33d4e66780c0 364
IanBenzMaxim 13:6a6225690c2e 365 // Insert device certificate.
IanBenzMaxim 13:6a6225690c2e 366 rapidjson::Value certificate(rapidjson::kObjectType);
IanBenzMaxim 13:6a6225690c2e 367 result = coproc.readMemory(DS2476::UserData14, page);
IanBenzMaxim 13:6a6225690c2e 368 if (result) {
IanBenzMaxim 13:6a6225690c2e 369 if (windowManager() != NULL) {
IanBenzMaxim 13:6a6225690c2e 370 windowManager()->pop();
IanBenzMaxim 13:6a6225690c2e 371 std::auto_ptr<Window> window(
IanBenzMaxim 13:6a6225690c2e 372 new ErrorWindow("Failed to read UserData14"));
IanBenzMaxim 13:6a6225690c2e 373 windowManager()->push(window);
IanBenzMaxim 0:33d4e66780c0 374 }
IanBenzMaxim 13:6a6225690c2e 375 return WindowsChanged;
IanBenzMaxim 13:6a6225690c2e 376 }
IanBenzMaxim 13:6a6225690c2e 377 certificate.AddMember(
IanBenzMaxim 13:6a6225690c2e 378 "r",
IanBenzMaxim 13:6a6225690c2e 379 rapidjson::Value(byteArrayToHexString(page.data(), page.size()).c_str(),
IanBenzMaxim 13:6a6225690c2e 380 document.GetAllocator()).Move(),
IanBenzMaxim 13:6a6225690c2e 381 document.GetAllocator());
IanBenzMaxim 13:6a6225690c2e 382 result = coproc.readMemory(DS2476::UserData15, page);
IanBenzMaxim 13:6a6225690c2e 383 if (result) {
IanBenzMaxim 13:6a6225690c2e 384 if (windowManager() != NULL) {
IanBenzMaxim 13:6a6225690c2e 385 windowManager()->pop();
IanBenzMaxim 13:6a6225690c2e 386 std::auto_ptr<Window> window(
IanBenzMaxim 13:6a6225690c2e 387 new ErrorWindow("Failed to read UserData15"));
IanBenzMaxim 13:6a6225690c2e 388 windowManager()->push(window);
IanBenzMaxim 0:33d4e66780c0 389 }
IanBenzMaxim 13:6a6225690c2e 390 return WindowsChanged;
IanBenzMaxim 13:6a6225690c2e 391 }
IanBenzMaxim 13:6a6225690c2e 392 certificate.AddMember(
IanBenzMaxim 13:6a6225690c2e 393 "s",
IanBenzMaxim 13:6a6225690c2e 394 rapidjson::Value(byteArrayToHexString(page.data(), page.size()).c_str(),
IanBenzMaxim 13:6a6225690c2e 395 document.GetAllocator()).Move(),
IanBenzMaxim 13:6a6225690c2e 396 document.GetAllocator());
IanBenzMaxim 13:6a6225690c2e 397 document.AddMember("certificate", certificate, document.GetAllocator());
IanBenzMaxim 13:6a6225690c2e 398
IanBenzMaxim 13:6a6225690c2e 399 // Sign data and transmit to server.
IanBenzMaxim 13:6a6225690c2e 400 result = finalizeResponse(validSignature, responseChallenge, document,
IanBenzMaxim 13:6a6225690c2e 401 commandChallenge);
IanBenzMaxim 13:6a6225690c2e 402 if (result) {
IanBenzMaxim 13:6a6225690c2e 403 if (windowManager() != NULL) {
IanBenzMaxim 13:6a6225690c2e 404 windowManager()->pop();
IanBenzMaxim 13:6a6225690c2e 405 std::auto_ptr<Window> window(new ErrorWindow("Failed to sign data"));
IanBenzMaxim 13:6a6225690c2e 406 windowManager()->push(window);
IanBenzMaxim 0:33d4e66780c0 407 }
IanBenzMaxim 13:6a6225690c2e 408 return WindowsChanged;
IanBenzMaxim 13:6a6225690c2e 409 }
IanBenzMaxim 13:6a6225690c2e 410 sendJson(document, *socket);
IanBenzMaxim 13:6a6225690c2e 411 return NoChange;
IanBenzMaxim 0:33d4e66780c0 412 }
IanBenzMaxim 0:33d4e66780c0 413
IanBenzMaxim 13:6a6225690c2e 414 NormalOperationWindow::Result NormalOperationWindow::sendObjectTemp(
IanBenzMaxim 13:6a6225690c2e 415 const ResponseChallenge & responseChallenge) {
IanBenzMaxim 13:6a6225690c2e 416 rapidjson::MemoryPoolAllocator<> allocator(defaultChunkSize);
IanBenzMaxim 13:6a6225690c2e 417 rapidjson::Document document(rapidjson::kObjectType, &allocator);
IanBenzMaxim 13:6a6225690c2e 418
IanBenzMaxim 13:6a6225690c2e 419 // Read object temperature and add to document.
IanBenzMaxim 13:6a6225690c2e 420 double objectTemp;
IanBenzMaxim 13:6a6225690c2e 421 bool sensorResult = sensorNode.readTemp(SensorNode::ObjectTemp, objectTemp);
IanBenzMaxim 13:6a6225690c2e 422 if (!sensorResult) {
IanBenzMaxim 13:6a6225690c2e 423 if (windowManager() != NULL) {
IanBenzMaxim 13:6a6225690c2e 424 windowManager()->pop();
IanBenzMaxim 13:6a6225690c2e 425 std::auto_ptr<Window> window(
IanBenzMaxim 13:6a6225690c2e 426 new ErrorWindow("Failed to read object temperature"));
IanBenzMaxim 13:6a6225690c2e 427 windowManager()->push(window);
IanBenzMaxim 0:33d4e66780c0 428 }
IanBenzMaxim 13:6a6225690c2e 429 return WindowsChanged;
IanBenzMaxim 13:6a6225690c2e 430 }
IanBenzMaxim 13:6a6225690c2e 431 document.AddMember("objectTemp", objectTemp, document.GetAllocator());
IanBenzMaxim 13:6a6225690c2e 432
IanBenzMaxim 13:6a6225690c2e 433 // Sign data and transmit to server.
IanBenzMaxim 13:6a6225690c2e 434 error_code coprocResult = finalizeResponse(validSignature, responseChallenge,
IanBenzMaxim 13:6a6225690c2e 435 document, commandChallenge);
IanBenzMaxim 13:6a6225690c2e 436 if (coprocResult) {
IanBenzMaxim 13:6a6225690c2e 437 if (windowManager() != NULL) {
IanBenzMaxim 13:6a6225690c2e 438 windowManager()->pop();
IanBenzMaxim 13:6a6225690c2e 439 std::auto_ptr<Window> window(new ErrorWindow("Failed to sign data"));
IanBenzMaxim 13:6a6225690c2e 440 windowManager()->push(window);
IanBenzMaxim 0:33d4e66780c0 441 }
IanBenzMaxim 13:6a6225690c2e 442 return WindowsChanged;
IanBenzMaxim 13:6a6225690c2e 443 }
IanBenzMaxim 13:6a6225690c2e 444 sendJson(document, *socket);
IanBenzMaxim 0:33d4e66780c0 445
IanBenzMaxim 13:6a6225690c2e 446 lastObjectTemp = objectTemp;
IanBenzMaxim 13:6a6225690c2e 447 return NoChange;
IanBenzMaxim 0:33d4e66780c0 448 }
IanBenzMaxim 0:33d4e66780c0 449
IanBenzMaxim 13:6a6225690c2e 450 NormalOperationWindow::Result NormalOperationWindow::sendAmbientTemp(
IanBenzMaxim 13:6a6225690c2e 451 const ResponseChallenge & responseChallenge) {
IanBenzMaxim 13:6a6225690c2e 452 rapidjson::MemoryPoolAllocator<> allocator(defaultChunkSize);
IanBenzMaxim 13:6a6225690c2e 453 rapidjson::Document document(rapidjson::kObjectType, &allocator);
IanBenzMaxim 13:6a6225690c2e 454
IanBenzMaxim 13:6a6225690c2e 455 // Read ambient temperature and add to document.
IanBenzMaxim 13:6a6225690c2e 456 double ambientTemp;
IanBenzMaxim 13:6a6225690c2e 457 bool sensorResult = sensorNode.readTemp(SensorNode::AmbientTemp, ambientTemp);
IanBenzMaxim 13:6a6225690c2e 458 if (!sensorResult) {
IanBenzMaxim 13:6a6225690c2e 459 if (windowManager() != NULL) {
IanBenzMaxim 13:6a6225690c2e 460 windowManager()->pop();
IanBenzMaxim 13:6a6225690c2e 461 std::auto_ptr<Window> window(
IanBenzMaxim 13:6a6225690c2e 462 new ErrorWindow("Failed to read ambient temperature"));
IanBenzMaxim 13:6a6225690c2e 463 windowManager()->push(window);
IanBenzMaxim 0:33d4e66780c0 464 }
IanBenzMaxim 13:6a6225690c2e 465 return WindowsChanged;
IanBenzMaxim 13:6a6225690c2e 466 }
IanBenzMaxim 13:6a6225690c2e 467 document.AddMember("ambientTemp", ambientTemp, document.GetAllocator());
IanBenzMaxim 13:6a6225690c2e 468
IanBenzMaxim 13:6a6225690c2e 469 // Sign data and transmit to server.
IanBenzMaxim 13:6a6225690c2e 470 error_code coprocResult = finalizeResponse(validSignature, responseChallenge,
IanBenzMaxim 13:6a6225690c2e 471 document, commandChallenge);
IanBenzMaxim 13:6a6225690c2e 472 if (coprocResult) {
IanBenzMaxim 13:6a6225690c2e 473 if (windowManager() != NULL) {
IanBenzMaxim 13:6a6225690c2e 474 windowManager()->pop();
IanBenzMaxim 13:6a6225690c2e 475 std::auto_ptr<Window> window(new ErrorWindow("Failed to sign data"));
IanBenzMaxim 13:6a6225690c2e 476 windowManager()->push(window);
IanBenzMaxim 0:33d4e66780c0 477 }
IanBenzMaxim 13:6a6225690c2e 478 return WindowsChanged;
IanBenzMaxim 13:6a6225690c2e 479 }
IanBenzMaxim 13:6a6225690c2e 480 sendJson(document, *socket);
IanBenzMaxim 13:6a6225690c2e 481
IanBenzMaxim 13:6a6225690c2e 482 lastAmbientTemp = ambientTemp;
IanBenzMaxim 13:6a6225690c2e 483 return NoChange;
IanBenzMaxim 13:6a6225690c2e 484 }
IanBenzMaxim 13:6a6225690c2e 485
IanBenzMaxim 13:6a6225690c2e 486 void NormalOperationWindow::displayImage(
IanBenzMaxim 13:6a6225690c2e 487 const std::vector<uint8_t> & imageData) {
IanBenzMaxim 13:6a6225690c2e 488 if (windowManager() != NULL) {
IanBenzMaxim 13:6a6225690c2e 489 std::auto_ptr<Graphic> image(
IanBenzMaxim 13:6a6225690c2e 490 new Image(Bitmap(&imageData[0], imageData.size(), 64)));
IanBenzMaxim 13:6a6225690c2e 491 std::auto_ptr<Window> window(new DisplayGraphicWindow(image));
IanBenzMaxim 13:6a6225690c2e 492 windowManager()->push(window);
IanBenzMaxim 13:6a6225690c2e 493 }
IanBenzMaxim 0:33d4e66780c0 494 }
IanBenzMaxim 0:33d4e66780c0 495
IanBenzMaxim 13:6a6225690c2e 496 NormalOperationWindow::Result
IanBenzMaxim 13:6a6225690c2e 497 NormalOperationWindow::processReceivedData(size_t recvBufSize) {
IanBenzMaxim 13:6a6225690c2e 498 // Separate commands and process each one.
IanBenzMaxim 13:6a6225690c2e 499 std::vector<std::pair<const char *, const char *> > commands =
IanBenzMaxim 13:6a6225690c2e 500 separateCommands(recvBuf, recvBufSize);
IanBenzMaxim 13:6a6225690c2e 501 for (std::vector<std::pair<const char *, const char *> >::const_iterator it =
IanBenzMaxim 13:6a6225690c2e 502 commands.begin();
IanBenzMaxim 13:6a6225690c2e 503 it != commands.end(); it++) {
IanBenzMaxim 13:6a6225690c2e 504 rapidjson::MemoryPoolAllocator<> allocator(defaultChunkSize);
IanBenzMaxim 13:6a6225690c2e 505 rapidjson::Document data(&allocator);
IanBenzMaxim 13:6a6225690c2e 506 // Verify command signature.
IanBenzMaxim 13:6a6225690c2e 507 error_code verifySignedResult =
IanBenzMaxim 13:6a6225690c2e 508 verifySignedData(it->first, it->second, commandChallenge, data);
IanBenzMaxim 13:6a6225690c2e 509 if (!verifySignedResult) {
IanBenzMaxim 13:6a6225690c2e 510 // Verify command schema.
IanBenzMaxim 13:6a6225690c2e 511 sendMessage("Received data is authentic");
IanBenzMaxim 13:6a6225690c2e 512 if (data.IsObject() && data.HasMember("command")) {
IanBenzMaxim 13:6a6225690c2e 513 const rapidjson::Value & command = data["command"];
IanBenzMaxim 13:6a6225690c2e 514 if (command.IsString()) {
IanBenzMaxim 13:6a6225690c2e 515 // Parse challenge if included.
IanBenzMaxim 13:6a6225690c2e 516 ResponseChallenge responseChallenge;
IanBenzMaxim 13:6a6225690c2e 517 if (data.HasMember("challenge")) {
IanBenzMaxim 13:6a6225690c2e 518 const rapidjson::Value & challenge = data["challenge"];
IanBenzMaxim 13:6a6225690c2e 519 if (challenge.IsString()) {
IanBenzMaxim 13:6a6225690c2e 520 responseChallenge = hexStringToByteArray(std::string(
IanBenzMaxim 13:6a6225690c2e 521 challenge.GetString(), challenge.GetStringLength()));
IanBenzMaxim 13:6a6225690c2e 522 }
IanBenzMaxim 13:6a6225690c2e 523 }
IanBenzMaxim 13:6a6225690c2e 524
IanBenzMaxim 13:6a6225690c2e 525 // Execute the command.
IanBenzMaxim 13:6a6225690c2e 526 if (command == "getStatus") {
IanBenzMaxim 13:6a6225690c2e 527 Result result = sendStatus(responseChallenge);
IanBenzMaxim 13:6a6225690c2e 528 if (result != NoChange)
IanBenzMaxim 13:6a6225690c2e 529 return result;
IanBenzMaxim 13:6a6225690c2e 530 } else if (command == "readObjectTemp") {
IanBenzMaxim 13:6a6225690c2e 531 if ((lastSensorNodeState == SensorNode::ValidLaserDisabled) ||
IanBenzMaxim 13:6a6225690c2e 532 (lastSensorNodeState == SensorNode::ValidLaserEnabled)) {
IanBenzMaxim 13:6a6225690c2e 533 Result result = sendObjectTemp(responseChallenge);
IanBenzMaxim 13:6a6225690c2e 534 if (result != NoChange)
IanBenzMaxim 13:6a6225690c2e 535 return result;
IanBenzMaxim 13:6a6225690c2e 536 invalidate();
IanBenzMaxim 13:6a6225690c2e 537 }
IanBenzMaxim 13:6a6225690c2e 538 } else if (command == "readAmbientTemp") {
IanBenzMaxim 13:6a6225690c2e 539 if ((lastSensorNodeState == SensorNode::ValidLaserDisabled) ||
IanBenzMaxim 13:6a6225690c2e 540 (lastSensorNodeState == SensorNode::ValidLaserEnabled)) {
IanBenzMaxim 13:6a6225690c2e 541 Result result = sendAmbientTemp(responseChallenge);
IanBenzMaxim 13:6a6225690c2e 542 if (result != NoChange)
IanBenzMaxim 13:6a6225690c2e 543 return result;
IanBenzMaxim 13:6a6225690c2e 544 invalidate();
IanBenzMaxim 13:6a6225690c2e 545 }
IanBenzMaxim 13:6a6225690c2e 546 } else if (command == "enableModule") {
IanBenzMaxim 13:6a6225690c2e 547 if (lastSensorNodeState == SensorNode::ValidLaserDisabled) {
IanBenzMaxim 13:6a6225690c2e 548 const error_code result = sensorNode.setLaserEnabled(
IanBenzMaxim 13:6a6225690c2e 549 true,
IanBenzMaxim 13:6a6225690c2e 550 makeFunction(this, &NormalOperationWindow::sendMessage));
IanBenzMaxim 13:6a6225690c2e 551 if (!result) {
IanBenzMaxim 13:6a6225690c2e 552 lastSensorNodeState = SensorNode::ValidLaserEnabled;
IanBenzMaxim 13:6a6225690c2e 553 invalidate();
IanBenzMaxim 13:6a6225690c2e 554 }
IanBenzMaxim 13:6a6225690c2e 555 }
IanBenzMaxim 13:6a6225690c2e 556 } else if (command == "disableModule") {
IanBenzMaxim 13:6a6225690c2e 557 if (lastSensorNodeState == SensorNode::ValidLaserEnabled) {
IanBenzMaxim 13:6a6225690c2e 558 const error_code result = sensorNode.setLaserEnabled(
IanBenzMaxim 13:6a6225690c2e 559 false,
IanBenzMaxim 13:6a6225690c2e 560 makeFunction(this, &NormalOperationWindow::sendMessage));
IanBenzMaxim 13:6a6225690c2e 561 if (!result) {
IanBenzMaxim 13:6a6225690c2e 562 lastSensorNodeState = SensorNode::ValidLaserDisabled;
IanBenzMaxim 13:6a6225690c2e 563 invalidate();
IanBenzMaxim 13:6a6225690c2e 564 }
IanBenzMaxim 13:6a6225690c2e 565 }
IanBenzMaxim 13:6a6225690c2e 566 } else if (command == "displayImage") {
IanBenzMaxim 13:6a6225690c2e 567 if (data.HasMember("image")) {
IanBenzMaxim 13:6a6225690c2e 568 const rapidjson::Value & image = data["image"];
IanBenzMaxim 13:6a6225690c2e 569 if (image.IsString()) {
IanBenzMaxim 13:6a6225690c2e 570 displayImage(hexStringToByteArray(
IanBenzMaxim 13:6a6225690c2e 571 std::string(image.GetString(), image.GetStringLength())));
IanBenzMaxim 13:6a6225690c2e 572 return WindowsChanged;
IanBenzMaxim 13:6a6225690c2e 573 }
IanBenzMaxim 13:6a6225690c2e 574 }
IanBenzMaxim 13:6a6225690c2e 575 }
IanBenzMaxim 13:6a6225690c2e 576 }
IanBenzMaxim 13:6a6225690c2e 577 }
IanBenzMaxim 13:6a6225690c2e 578 } else if (verifySignedResult ==
IanBenzMaxim 13:6a6225690c2e 579 make_error_code(DS2476::AuthenticationError)) {
IanBenzMaxim 13:6a6225690c2e 580 const char message[] = "Received data is not authentic";
IanBenzMaxim 13:6a6225690c2e 581 sendMessage(message);
IanBenzMaxim 13:6a6225690c2e 582 std::auto_ptr<Graphic> messageText(new Text);
IanBenzMaxim 13:6a6225690c2e 583 Text & messageTextRef = *static_cast<Text *>(messageText.get());
IanBenzMaxim 13:6a6225690c2e 584 messageTextRef.setText(message);
IanBenzMaxim 13:6a6225690c2e 585 messageTextRef.setWordWrap(true);
IanBenzMaxim 13:6a6225690c2e 586 if (windowManager() != NULL) {
IanBenzMaxim 13:6a6225690c2e 587 std::auto_ptr<Window> window(new DisplayGraphicWindow(messageText));
IanBenzMaxim 7:66c5dedc750b 588 windowManager()->push(window);
IanBenzMaxim 13:6a6225690c2e 589 }
IanBenzMaxim 13:6a6225690c2e 590 return WindowsChanged;
IanBenzMaxim 13:6a6225690c2e 591 } else {
IanBenzMaxim 13:6a6225690c2e 592 const char message[] = "Unable to verify received data";
IanBenzMaxim 13:6a6225690c2e 593 sendMessage(message);
IanBenzMaxim 13:6a6225690c2e 594 if (windowManager() != NULL) {
IanBenzMaxim 13:6a6225690c2e 595 std::auto_ptr<Window> window(new ErrorWindow(message));
IanBenzMaxim 13:6a6225690c2e 596 windowManager()->push(window);
IanBenzMaxim 13:6a6225690c2e 597 }
IanBenzMaxim 13:6a6225690c2e 598 return WindowsChanged;
IanBenzMaxim 0:33d4e66780c0 599 }
IanBenzMaxim 13:6a6225690c2e 600 }
IanBenzMaxim 13:6a6225690c2e 601 return NoChange;
IanBenzMaxim 0:33d4e66780c0 602 }
IanBenzMaxim 0:33d4e66780c0 603
IanBenzMaxim 13:6a6225690c2e 604 void NormalOperationWindow::resized() {
IanBenzMaxim 13:6a6225690c2e 605 showWebIdButton.resize(width(), showWebIdButton.preferredHeight());
IanBenzMaxim 13:6a6225690c2e 606 showWebIdButton.move(0, height() - showWebIdButton.height());
IanBenzMaxim 13:6a6225690c2e 607 validSignatureButton.resize(width(), validSignatureButton.preferredHeight());
IanBenzMaxim 13:6a6225690c2e 608 validSignatureButton.move(0, showWebIdButton.y() -
IanBenzMaxim 13:6a6225690c2e 609 validSignatureButton.height() - 1);
IanBenzMaxim 13:6a6225690c2e 610 }
IanBenzMaxim 13:6a6225690c2e 611
IanBenzMaxim 13:6a6225690c2e 612 static std::string doubleToString(double input) {
IanBenzMaxim 13:6a6225690c2e 613 char inputString[8];
IanBenzMaxim 13:6a6225690c2e 614 snprintf(inputString, sizeof(inputString) / sizeof(inputString[0]), "%.2f",
IanBenzMaxim 13:6a6225690c2e 615 input);
IanBenzMaxim 13:6a6225690c2e 616 return std::string(inputString);
IanBenzMaxim 13:6a6225690c2e 617 }
IanBenzMaxim 13:6a6225690c2e 618
IanBenzMaxim 13:6a6225690c2e 619 void NormalOperationWindow::doRender(Bitmap & bitmap, int xOffset,
IanBenzMaxim 13:6a6225690c2e 620 int yOffset) const {
IanBenzMaxim 13:6a6225690c2e 621 // Format current status text.
IanBenzMaxim 13:6a6225690c2e 622 std::string sensorNodeStateText;
IanBenzMaxim 13:6a6225690c2e 623 switch (lastSensorNodeState) {
IanBenzMaxim 13:6a6225690c2e 624 case SensorNode::Disconnected:
IanBenzMaxim 13:6a6225690c2e 625 sensorNodeStateText = "Disconnected";
IanBenzMaxim 13:6a6225690c2e 626 break;
IanBenzMaxim 13:6a6225690c2e 627
IanBenzMaxim 13:6a6225690c2e 628 case SensorNode::Invalid:
IanBenzMaxim 13:6a6225690c2e 629 sensorNodeStateText = "Invalid";
IanBenzMaxim 13:6a6225690c2e 630 break;
IanBenzMaxim 13:6a6225690c2e 631
IanBenzMaxim 13:6a6225690c2e 632 case SensorNode::ValidLaserDisabled:
IanBenzMaxim 13:6a6225690c2e 633 sensorNodeStateText = "Valid, laser disabled";
IanBenzMaxim 13:6a6225690c2e 634 break;
IanBenzMaxim 13:6a6225690c2e 635
IanBenzMaxim 13:6a6225690c2e 636 case SensorNode::ValidLaserEnabled:
IanBenzMaxim 13:6a6225690c2e 637 sensorNodeStateText = "Valid, laser enabled";
IanBenzMaxim 13:6a6225690c2e 638 break;
IanBenzMaxim 13:6a6225690c2e 639
IanBenzMaxim 13:6a6225690c2e 640 case SensorNode::NotProvisioned:
IanBenzMaxim 13:6a6225690c2e 641 break;
IanBenzMaxim 13:6a6225690c2e 642 }
IanBenzMaxim 13:6a6225690c2e 643
IanBenzMaxim 13:6a6225690c2e 644 Text description;
IanBenzMaxim 13:6a6225690c2e 645 description.setText("Object temp: " + doubleToString(lastObjectTemp) +
IanBenzMaxim 13:6a6225690c2e 646 "\nAmbient temp: " + doubleToString(lastAmbientTemp) +
IanBenzMaxim 13:6a6225690c2e 647 "\nSensor node: " + sensorNodeStateText);
IanBenzMaxim 13:6a6225690c2e 648 description.resize(width(), validSignatureButton.y());
IanBenzMaxim 13:6a6225690c2e 649 description.setWordWrap(true);
IanBenzMaxim 13:6a6225690c2e 650 description.render(bitmap, xOffset + x(), yOffset + y());
IanBenzMaxim 13:6a6225690c2e 651 validSignatureButton.render(bitmap, xOffset + x(), yOffset + y());
IanBenzMaxim 13:6a6225690c2e 652 showWebIdButton.render(bitmap, xOffset + x(), yOffset + y());
IanBenzMaxim 0:33d4e66780c0 653 }
IanBenzMaxim 0:33d4e66780c0 654
IanBenzMaxim 13:6a6225690c2e 655 void NormalOperationWindow::updated() {
IanBenzMaxim 13:6a6225690c2e 656 // Detect sensor node.
IanBenzMaxim 13:6a6225690c2e 657 std::pair<SensorNode::State, error_code> sensorNodeState =
IanBenzMaxim 13:6a6225690c2e 658 sensorNode.detect();
IanBenzMaxim 13:6a6225690c2e 659 if (sensorNodeState.first == SensorNode::NotProvisioned) {
IanBenzMaxim 13:6a6225690c2e 660 const error_code result = sensorNode.provision();
IanBenzMaxim 13:6a6225690c2e 661 if (result) {
IanBenzMaxim 13:6a6225690c2e 662 if (windowManager() != NULL) {
IanBenzMaxim 13:6a6225690c2e 663 windowManager()->pop();
IanBenzMaxim 13:6a6225690c2e 664 std::auto_ptr<Window> window(
IanBenzMaxim 13:6a6225690c2e 665 new ErrorWindow("Sensor node provision failed"));
IanBenzMaxim 13:6a6225690c2e 666 windowManager()->push(window);
IanBenzMaxim 13:6a6225690c2e 667 }
IanBenzMaxim 13:6a6225690c2e 668 return;
IanBenzMaxim 13:6a6225690c2e 669 }
IanBenzMaxim 13:6a6225690c2e 670 sensorNodeState = sensorNode.detect();
IanBenzMaxim 13:6a6225690c2e 671 }
IanBenzMaxim 13:6a6225690c2e 672 if (sensorNodeState.first != lastSensorNodeState) {
IanBenzMaxim 13:6a6225690c2e 673 lastSensorNodeState = sensorNodeState.first;
IanBenzMaxim 13:6a6225690c2e 674 invalidate();
IanBenzMaxim 13:6a6225690c2e 675 }
IanBenzMaxim 6:0c9050b02876 676
IanBenzMaxim 13:6a6225690c2e 677 // Send challenge on first connection.
IanBenzMaxim 13:6a6225690c2e 678 if (sendChallenge) {
IanBenzMaxim 13:6a6225690c2e 679 rapidjson::MemoryPoolAllocator<> allocator(defaultChunkSize);
IanBenzMaxim 13:6a6225690c2e 680 rapidjson::Document document(rapidjson::kObjectType, &allocator);
IanBenzMaxim 13:6a6225690c2e 681 error_code result = addCommandChallenge(document, commandChallenge);
IanBenzMaxim 13:6a6225690c2e 682 if (!result) {
IanBenzMaxim 13:6a6225690c2e 683 sendJson(document, *socket);
IanBenzMaxim 13:6a6225690c2e 684 sendChallenge = false;
IanBenzMaxim 0:33d4e66780c0 685 }
IanBenzMaxim 13:6a6225690c2e 686 }
IanBenzMaxim 13:6a6225690c2e 687 // Process socket data.
IanBenzMaxim 13:6a6225690c2e 688 else {
IanBenzMaxim 13:6a6225690c2e 689 int recvResult =
IanBenzMaxim 13:6a6225690c2e 690 socket->recv(recvBuf, sizeof(recvBuf) / sizeof(recvBuf[0]));
IanBenzMaxim 13:6a6225690c2e 691 if (recvResult > 0) {
IanBenzMaxim 13:6a6225690c2e 692 std::printf("%*s\n", recvResult, recvBuf);
IanBenzMaxim 13:6a6225690c2e 693 Result result = processReceivedData(recvResult);
IanBenzMaxim 13:6a6225690c2e 694 if (result != NoChange)
IanBenzMaxim 13:6a6225690c2e 695 return;
IanBenzMaxim 13:6a6225690c2e 696 } else if (recvResult != NSAPI_ERROR_WOULD_BLOCK) {
IanBenzMaxim 13:6a6225690c2e 697 if (windowManager() != NULL) {
IanBenzMaxim 13:6a6225690c2e 698 windowManager()->pop();
IanBenzMaxim 13:6a6225690c2e 699 std::auto_ptr<Window> window(new ErrorWindow("Socket receive failed"));
IanBenzMaxim 13:6a6225690c2e 700 windowManager()->push(window);
IanBenzMaxim 13:6a6225690c2e 701 }
IanBenzMaxim 13:6a6225690c2e 702 return;
IanBenzMaxim 13:6a6225690c2e 703 }
IanBenzMaxim 13:6a6225690c2e 704 }
IanBenzMaxim 0:33d4e66780c0 705 }
IanBenzMaxim 0:33d4e66780c0 706
IanBenzMaxim 13:6a6225690c2e 707 bool NormalOperationWindow::doProcessKey(Key key) {
IanBenzMaxim 13:6a6225690c2e 708 bool handled;
IanBenzMaxim 13:6a6225690c2e 709 switch (key) {
IanBenzMaxim 13:6a6225690c2e 710 case UpKey:
IanBenzMaxim 13:6a6225690c2e 711 validSignatureButton.setFocused();
IanBenzMaxim 13:6a6225690c2e 712 handled = true;
IanBenzMaxim 13:6a6225690c2e 713 break;
IanBenzMaxim 13:6a6225690c2e 714
IanBenzMaxim 13:6a6225690c2e 715 case DownKey:
IanBenzMaxim 13:6a6225690c2e 716 showWebIdButton.setFocused();
IanBenzMaxim 13:6a6225690c2e 717 handled = true;
IanBenzMaxim 13:6a6225690c2e 718 break;
IanBenzMaxim 13:6a6225690c2e 719
IanBenzMaxim 13:6a6225690c2e 720 default:
IanBenzMaxim 13:6a6225690c2e 721 handled = false;
IanBenzMaxim 13:6a6225690c2e 722 break;
IanBenzMaxim 13:6a6225690c2e 723 }
IanBenzMaxim 13:6a6225690c2e 724 return handled;
IanBenzMaxim 0:33d4e66780c0 725 }