Maxim Integrated / Mbed OS MAXREFDES155#

Dependencies:   MaximInterface

Committer:
IanBenzMaxim
Date:
Thu Jun 01 14:21:58 2017 -0500
Revision:
12:46c5974a565f
Parent:
0:33d4e66780c0
Child:
13:6a6225690c2e
Added bidirectional challenge support.

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 #include <string>
IanBenzMaxim 0:33d4e66780c0 34 #include <I2C.h>
IanBenzMaxim 0:33d4e66780c0 35 #include "RomId.h"
IanBenzMaxim 0:33d4e66780c0 36 #include "HexConversions.hpp"
IanBenzMaxim 0:33d4e66780c0 37 #include "DS2476.hpp"
IanBenzMaxim 0:33d4e66780c0 38 #include "Factory.hpp"
IanBenzMaxim 0:33d4e66780c0 39 #include "SensorNode.hpp"
IanBenzMaxim 0:33d4e66780c0 40
IanBenzMaxim 0:33d4e66780c0 41 // I2C address of the MLX90614.
IanBenzMaxim 0:33d4e66780c0 42 static const uint8_t mlx90614Addr = 0xB4;
IanBenzMaxim 0:33d4e66780c0 43
IanBenzMaxim 0:33d4e66780c0 44 /// DS2476 derives the slave secret for a certain DS28C36 from the master secret.
IanBenzMaxim 0:33d4e66780c0 45 /// @param ds2476 DS2476 that will compute slave secret.
IanBenzMaxim 0:33d4e66780c0 46 /// @param ds28c36 DS28C36 containing the slave secret of interest.
IanBenzMaxim 0:33d4e66780c0 47 /// @param[out] message Contains the HMAC input used when computing the slave secret. Output to
IanBenzMaxim 0:33d4e66780c0 48 /// prevent redundant page reads.
IanBenzMaxim 0:33d4e66780c0 49 /// @param print Optional callback for displaying informational messages to the user.
IanBenzMaxim 0:33d4e66780c0 50 /// @returns True if the operation was successful.
IanBenzMaxim 0:33d4e66780c0 51 static bool setSlaveSecret(DS2476 & ds2476, DS28C36 & ds28c36, DS2476::Buffer & message,
IanBenzMaxim 0:33d4e66780c0 52 const SensorNode::PrintHandler & print = SensorNode::PrintHandler())
IanBenzMaxim 0:33d4e66780c0 53 {
IanBenzMaxim 0:33d4e66780c0 54 if (print)
IanBenzMaxim 0:33d4e66780c0 55 {
IanBenzMaxim 0:33d4e66780c0 56 print("Computing slave secret");
IanBenzMaxim 0:33d4e66780c0 57 print("Reading DS28C36 ROM Options page for ROM ID and MAN ID");
IanBenzMaxim 0:33d4e66780c0 58 }
IanBenzMaxim 0:33d4e66780c0 59 DS28C36::Page page;
IanBenzMaxim 0:33d4e66780c0 60 DS28C36::CmdResult result = ds28c36.readMemory(DS28C36::RomOptions, page);
IanBenzMaxim 0:33d4e66780c0 61 if (result != DS28C36::Success)
IanBenzMaxim 0:33d4e66780c0 62 return false;
IanBenzMaxim 0:33d4e66780c0 63 message.clear();
IanBenzMaxim 0:33d4e66780c0 64 message.reserve(75);
IanBenzMaxim 0:33d4e66780c0 65 message.assign(page.begin() + 24, page.end());
IanBenzMaxim 0:33d4e66780c0 66 OneWire::array<uint8_t, 2> manId = { page[22], page[23] };
IanBenzMaxim 0:33d4e66780c0 67 if (print)
IanBenzMaxim 0:33d4e66780c0 68 {
IanBenzMaxim 0:33d4e66780c0 69 print("Reading User Data 0 page");
IanBenzMaxim 0:33d4e66780c0 70 }
IanBenzMaxim 0:33d4e66780c0 71 result = ds28c36.readMemory(DS28C36::UserData0, page);
IanBenzMaxim 0:33d4e66780c0 72 if (result != DS28C36::Success)
IanBenzMaxim 0:33d4e66780c0 73 return false;
IanBenzMaxim 0:33d4e66780c0 74 message.insert(message.end(), page.begin(), page.end());
IanBenzMaxim 0:33d4e66780c0 75 message.insert(message.end(), 32, 0x00);
IanBenzMaxim 0:33d4e66780c0 76 message.insert(message.end(), DS28C36::UserData0);
IanBenzMaxim 0:33d4e66780c0 77 message.insert(message.end(), manId.begin(), manId.end());
IanBenzMaxim 0:33d4e66780c0 78 if (print)
IanBenzMaxim 0:33d4e66780c0 79 {
IanBenzMaxim 0:33d4e66780c0 80 print(("Creating HMAC message (ROM ID | Binding Data (Page Data) | Partial Secret (Buffer) | Page # | MAN ID): " +
IanBenzMaxim 0:33d4e66780c0 81 byteArrayToHexString(&message[0], message.size())).c_str());
IanBenzMaxim 0:33d4e66780c0 82 print("Writing HMAC message to DS2476 buffer");
IanBenzMaxim 0:33d4e66780c0 83 }
IanBenzMaxim 0:33d4e66780c0 84 result = ds2476.writeBuffer(message);
IanBenzMaxim 0:33d4e66780c0 85 if (result != DS2476::Success)
IanBenzMaxim 0:33d4e66780c0 86 return false;
IanBenzMaxim 0:33d4e66780c0 87 if (print)
IanBenzMaxim 0:33d4e66780c0 88 {
IanBenzMaxim 0:33d4e66780c0 89 print("DS2476 computes slave secret from master secret (Secret A) and message in buffer");
IanBenzMaxim 0:33d4e66780c0 90 }
IanBenzMaxim 0:33d4e66780c0 91 result = ds2476.computeSha2UniqueSecret(DS2476::SecretNumA);
IanBenzMaxim 0:33d4e66780c0 92 if (result != DS2476::Success)
IanBenzMaxim 0:33d4e66780c0 93 return false;
IanBenzMaxim 0:33d4e66780c0 94 return true;
IanBenzMaxim 0:33d4e66780c0 95 }
IanBenzMaxim 0:33d4e66780c0 96
IanBenzMaxim 0:33d4e66780c0 97 SensorNode::SensorNode(mbed::I2C & i2c, DS2476 & ds2476) : i2c(i2c), ds28c36(i2c), ds2476(ds2476) { }
IanBenzMaxim 0:33d4e66780c0 98
IanBenzMaxim 0:33d4e66780c0 99 bool SensorNode::detect()
IanBenzMaxim 0:33d4e66780c0 100 {
IanBenzMaxim 0:33d4e66780c0 101 // Read ROM ID
IanBenzMaxim 0:33d4e66780c0 102 OneWire::RomId romId;
IanBenzMaxim 0:33d4e66780c0 103 return (DS28C36::readRomId(ds28c36, romId) == DS28C36::Success) && romId.valid();
IanBenzMaxim 0:33d4e66780c0 104 }
IanBenzMaxim 0:33d4e66780c0 105
IanBenzMaxim 0:33d4e66780c0 106 bool SensorNode::readTemp(TempStyle style, double & temp)
IanBenzMaxim 0:33d4e66780c0 107 {
IanBenzMaxim 0:33d4e66780c0 108 uint8_t data[2];
IanBenzMaxim 0:33d4e66780c0 109 switch (style)
IanBenzMaxim 0:33d4e66780c0 110 {
IanBenzMaxim 0:33d4e66780c0 111 case ObjectTemp:
IanBenzMaxim 0:33d4e66780c0 112 default:
IanBenzMaxim 0:33d4e66780c0 113 data[0] = 0x07;
IanBenzMaxim 0:33d4e66780c0 114 break;
IanBenzMaxim 0:33d4e66780c0 115
IanBenzMaxim 0:33d4e66780c0 116 case AmbientTemp:
IanBenzMaxim 0:33d4e66780c0 117 data[0] = 0x06;
IanBenzMaxim 0:33d4e66780c0 118 break;
IanBenzMaxim 0:33d4e66780c0 119 }
IanBenzMaxim 0:33d4e66780c0 120 int result = i2c.write(mlx90614Addr, reinterpret_cast<const char *>(data), 1, true);
IanBenzMaxim 0:33d4e66780c0 121 if (result != 0)
IanBenzMaxim 0:33d4e66780c0 122 {
IanBenzMaxim 0:33d4e66780c0 123 i2c.stop();
IanBenzMaxim 0:33d4e66780c0 124 return false;
IanBenzMaxim 0:33d4e66780c0 125 }
IanBenzMaxim 0:33d4e66780c0 126 result = i2c.read(mlx90614Addr, reinterpret_cast<char *>(data), 2, false);
IanBenzMaxim 0:33d4e66780c0 127 if (result != 0)
IanBenzMaxim 0:33d4e66780c0 128 {
IanBenzMaxim 0:33d4e66780c0 129 i2c.stop();
IanBenzMaxim 0:33d4e66780c0 130 return false;
IanBenzMaxim 0:33d4e66780c0 131 }
IanBenzMaxim 0:33d4e66780c0 132 temp = ((static_cast<uint_fast16_t>(data[1]) << 8) | data[0]) * 0.02 - 273.15;
IanBenzMaxim 0:33d4e66780c0 133 return true;
IanBenzMaxim 0:33d4e66780c0 134 }
IanBenzMaxim 0:33d4e66780c0 135
IanBenzMaxim 0:33d4e66780c0 136 bool SensorNode::getProvisioned(bool & provisioned)
IanBenzMaxim 0:33d4e66780c0 137 {
IanBenzMaxim 0:33d4e66780c0 138 return checkAuthenticatorProvisioned(ds28c36, provisioned);
IanBenzMaxim 0:33d4e66780c0 139 }
IanBenzMaxim 0:33d4e66780c0 140
IanBenzMaxim 0:33d4e66780c0 141 bool SensorNode::provision()
IanBenzMaxim 0:33d4e66780c0 142 {
IanBenzMaxim 0:33d4e66780c0 143 return provisionAuthenticator(ds28c36);
IanBenzMaxim 0:33d4e66780c0 144 }
IanBenzMaxim 0:33d4e66780c0 145
IanBenzMaxim 0:33d4e66780c0 146 bool SensorNode::authenticate()
IanBenzMaxim 0:33d4e66780c0 147 {
IanBenzMaxim 0:33d4e66780c0 148 // Compute slave secret on coprocessor.
IanBenzMaxim 0:33d4e66780c0 149 DS2476::Buffer message;
IanBenzMaxim 0:33d4e66780c0 150 if (!setSlaveSecret(ds2476, ds28c36, message))
IanBenzMaxim 0:33d4e66780c0 151 return false;
IanBenzMaxim 0:33d4e66780c0 152
IanBenzMaxim 0:33d4e66780c0 153 // Compute HMAC on coprocessor.
IanBenzMaxim 0:33d4e66780c0 154 // ROM ID, Page 0, and MAN ID are already in message.
IanBenzMaxim 0:33d4e66780c0 155 DS2476::Buffer challenge;
IanBenzMaxim 0:33d4e66780c0 156 DS2476::CmdResult result = ds2476.readRng(32, challenge);
IanBenzMaxim 0:33d4e66780c0 157 if (result != DS2476::Success)
IanBenzMaxim 0:33d4e66780c0 158 return false;
IanBenzMaxim 0:33d4e66780c0 159 std::copy(challenge.begin(), challenge.end(), message.begin() + 40);
IanBenzMaxim 0:33d4e66780c0 160 result = ds2476.writeBuffer(message);
IanBenzMaxim 0:33d4e66780c0 161 if (result != DS2476::Success)
IanBenzMaxim 0:33d4e66780c0 162 return false;
IanBenzMaxim 0:33d4e66780c0 163 DS2476::HMAC computedHmac;
IanBenzMaxim 0:33d4e66780c0 164 result = ds2476.computeSha2Hmac(computedHmac);
IanBenzMaxim 0:33d4e66780c0 165 if (result != DS2476::Success)
IanBenzMaxim 0:33d4e66780c0 166 return false;
IanBenzMaxim 0:33d4e66780c0 167
IanBenzMaxim 0:33d4e66780c0 168 // Compute HMAC on device.
IanBenzMaxim 0:33d4e66780c0 169 result = ds28c36.writeBuffer(challenge);
IanBenzMaxim 0:33d4e66780c0 170 if (result != DS28C36::Success)
IanBenzMaxim 0:33d4e66780c0 171 return false;
IanBenzMaxim 0:33d4e66780c0 172 DS28C36::HMAC deviceHmac;
IanBenzMaxim 0:33d4e66780c0 173 result = ds28c36.computeAndReadHmacPageAuthentication(DS28C36::UserData0, DS28C36::SecretNumA, deviceHmac);
IanBenzMaxim 0:33d4e66780c0 174 if (result != DS28C36::Success)
IanBenzMaxim 0:33d4e66780c0 175 return false;
IanBenzMaxim 0:33d4e66780c0 176
IanBenzMaxim 0:33d4e66780c0 177 return computedHmac == deviceHmac;
IanBenzMaxim 0:33d4e66780c0 178 }
IanBenzMaxim 0:33d4e66780c0 179
IanBenzMaxim 0:33d4e66780c0 180 bool SensorNode::setLaserEnabled(bool enabled, const PrintHandler & print)
IanBenzMaxim 0:33d4e66780c0 181 {
IanBenzMaxim 0:33d4e66780c0 182 if (print)
IanBenzMaxim 0:33d4e66780c0 183 {
IanBenzMaxim 0:33d4e66780c0 184 print((std::string(enabled ? "Enabling" : "Disabling") + " laser").c_str());
IanBenzMaxim 0:33d4e66780c0 185 }
IanBenzMaxim 0:33d4e66780c0 186
IanBenzMaxim 0:33d4e66780c0 187 // Compute slave secret on coprocessor.
IanBenzMaxim 0:33d4e66780c0 188 DS2476::Buffer message;
IanBenzMaxim 0:33d4e66780c0 189 if (!setSlaveSecret(ds2476, ds28c36, message, print))
IanBenzMaxim 0:33d4e66780c0 190 return false;
IanBenzMaxim 0:33d4e66780c0 191
IanBenzMaxim 0:33d4e66780c0 192 // Compute write HMAC.
IanBenzMaxim 0:33d4e66780c0 193 // ROM ID and MAN ID are already in message.
IanBenzMaxim 0:33d4e66780c0 194 if (print)
IanBenzMaxim 0:33d4e66780c0 195 {
IanBenzMaxim 0:33d4e66780c0 196 print("Reading GPIO Control page");
IanBenzMaxim 0:33d4e66780c0 197 print((std::string("Modify copy of GPIO Control page to set GPIO B state to ") +
IanBenzMaxim 0:33d4e66780c0 198 (enabled ? "conducting" : "high-impedance")).c_str());
IanBenzMaxim 0:33d4e66780c0 199 }
IanBenzMaxim 0:33d4e66780c0 200 DS28C36::Page page;
IanBenzMaxim 0:33d4e66780c0 201 DS28C36::CmdResult result = ds28c36.readMemory(DS28C36::GpioControl, page);
IanBenzMaxim 0:33d4e66780c0 202 if (result != DS28C36::Success)
IanBenzMaxim 0:33d4e66780c0 203 return false;
IanBenzMaxim 0:33d4e66780c0 204 std::copy(page.begin(), page.end(), message.begin() + 8);
IanBenzMaxim 0:33d4e66780c0 205 page[1] = (enabled ? 0xAA : 0x55);
IanBenzMaxim 0:33d4e66780c0 206 std::copy(page.begin(), page.end(), message.begin() + 40);
IanBenzMaxim 0:33d4e66780c0 207 message[72] = DS28C36::GpioControl;
IanBenzMaxim 0:33d4e66780c0 208 if (print)
IanBenzMaxim 0:33d4e66780c0 209 {
IanBenzMaxim 0:33d4e66780c0 210 print(("Creating HMAC message (ROM ID | Old Page Data | New Page Data | Page # | MAN ID): " +
IanBenzMaxim 0:33d4e66780c0 211 byteArrayToHexString(&message[0], message.size())).c_str());
IanBenzMaxim 0:33d4e66780c0 212 print("Writing HMAC message to DS2476 buffer");
IanBenzMaxim 0:33d4e66780c0 213 }
IanBenzMaxim 0:33d4e66780c0 214 result = ds2476.writeBuffer(message);
IanBenzMaxim 0:33d4e66780c0 215 if (result != DS2476::Success)
IanBenzMaxim 0:33d4e66780c0 216 return false;
IanBenzMaxim 0:33d4e66780c0 217 DS2476::HMAC hmac;
IanBenzMaxim 0:33d4e66780c0 218 result = ds2476.computeSha2Hmac(hmac);
IanBenzMaxim 0:33d4e66780c0 219 if (result != DS2476::Success)
IanBenzMaxim 0:33d4e66780c0 220 return false;
IanBenzMaxim 0:33d4e66780c0 221
IanBenzMaxim 0:33d4e66780c0 222 if (print)
IanBenzMaxim 0:33d4e66780c0 223 {
IanBenzMaxim 0:33d4e66780c0 224 print(("DS2476 computes write authentication HMAC from slave secret (Secret S) and message in buffer: " +
IanBenzMaxim 0:33d4e66780c0 225 byteArrayToHexString(hmac.data(), hmac.size())).c_str());
IanBenzMaxim 0:33d4e66780c0 226 print("Write authentication HMAC is written to DS28C36 buffer");
IanBenzMaxim 0:33d4e66780c0 227 print("DS28C36 computes an HMAC to compare to the write authentication HMAC after receiving Page # and New Page Data");
IanBenzMaxim 0:33d4e66780c0 228 }
IanBenzMaxim 0:33d4e66780c0 229
IanBenzMaxim 0:33d4e66780c0 230 // Write page data.
IanBenzMaxim 0:33d4e66780c0 231 result = ds28c36.writeBuffer(DS28C36::Buffer(hmac.begin(), hmac.end()));
IanBenzMaxim 0:33d4e66780c0 232 if (result != DS28C36::Success)
IanBenzMaxim 0:33d4e66780c0 233 return false;
IanBenzMaxim 0:33d4e66780c0 234 result = ds28c36.authenticatedSha2WriteMemory(DS28C36::GpioControl, DS28C36::SecretNumA, page);
IanBenzMaxim 0:33d4e66780c0 235 if (result != DS28C36::Success)
IanBenzMaxim 0:33d4e66780c0 236 return false;
IanBenzMaxim 0:33d4e66780c0 237 if (print)
IanBenzMaxim 0:33d4e66780c0 238 {
IanBenzMaxim 0:33d4e66780c0 239 print("DS28C36 updates page data which changes GPIO B state");
IanBenzMaxim 0:33d4e66780c0 240 print((std::string("Laser is now ") + (enabled ? "enabled" : "disabled")).c_str());
IanBenzMaxim 0:33d4e66780c0 241 }
IanBenzMaxim 0:33d4e66780c0 242 return true;
IanBenzMaxim 0:33d4e66780c0 243 }
IanBenzMaxim 0:33d4e66780c0 244
IanBenzMaxim 0:33d4e66780c0 245 bool SensorNode::getLaserEnabled(bool & enabled)
IanBenzMaxim 0:33d4e66780c0 246 {
IanBenzMaxim 0:33d4e66780c0 247 DS28C36::Page page;
IanBenzMaxim 0:33d4e66780c0 248 DS28C36::CmdResult result = ds28c36.readMemory(DS28C36::GpioControl, page);
IanBenzMaxim 0:33d4e66780c0 249 if (result != DS28C36::Success)
IanBenzMaxim 0:33d4e66780c0 250 return false;
IanBenzMaxim 0:33d4e66780c0 251 enabled = (page[1] == 0xAA);
IanBenzMaxim 0:33d4e66780c0 252 return true;
IanBenzMaxim 0:33d4e66780c0 253 }