Device interface library for multiple platforms including Mbed.

Dependents:   DeepCover Embedded Security in IoT MaximInterface MAXREFDES155#

Maxim Interface is a library framework focused on providing flexible and expressive hardware interfaces. Both communication interfaces such as I2C and 1-Wire and device interfaces such as DS18B20 are supported. Modern C++ concepts are used extensively while keeping compatibility with C++98/C++03 and requiring no external dependencies. The embedded-friendly design does not depend on exceptions or RTTI.

The full version of the project is hosted on GitLab: https://gitlab.com/iabenz/MaximInterface

Committer:
IanBenzMaxim
Date:
Fri May 29 16:19:22 2020 -0500
Revision:
12:7eb41621ba22
Parent:
11:3f3bf6bf5e6c
Updated to version 2.2.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
IanBenzMaxim 7:9cd16581b578 1 /*******************************************************************************
IanBenzMaxim 8:5ea891c7d1a1 2 * Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved.
IanBenzMaxim 7:9cd16581b578 3 *
IanBenzMaxim 7:9cd16581b578 4 * Permission is hereby granted, free of charge, to any person obtaining a
IanBenzMaxim 7:9cd16581b578 5 * copy of this software and associated documentation files (the "Software"),
IanBenzMaxim 7:9cd16581b578 6 * to deal in the Software without restriction, including without limitation
IanBenzMaxim 7:9cd16581b578 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
IanBenzMaxim 7:9cd16581b578 8 * and/or sell copies of the Software, and to permit persons to whom the
IanBenzMaxim 7:9cd16581b578 9 * Software is furnished to do so, subject to the following conditions:
IanBenzMaxim 7:9cd16581b578 10 *
IanBenzMaxim 7:9cd16581b578 11 * The above copyright notice and this permission notice shall be included
IanBenzMaxim 7:9cd16581b578 12 * in all copies or substantial portions of the Software.
IanBenzMaxim 7:9cd16581b578 13 *
IanBenzMaxim 7:9cd16581b578 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
IanBenzMaxim 7:9cd16581b578 15 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
IanBenzMaxim 7:9cd16581b578 16 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IanBenzMaxim 7:9cd16581b578 17 * IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES
IanBenzMaxim 7:9cd16581b578 18 * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
IanBenzMaxim 7:9cd16581b578 19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
IanBenzMaxim 7:9cd16581b578 20 * OTHER DEALINGS IN THE SOFTWARE.
IanBenzMaxim 7:9cd16581b578 21 *
IanBenzMaxim 7:9cd16581b578 22 * Except as contained in this notice, the name of Maxim Integrated
IanBenzMaxim 7:9cd16581b578 23 * Products, Inc. shall not be used except as stated in the Maxim Integrated
IanBenzMaxim 7:9cd16581b578 24 * Products, Inc. Branding Policy.
IanBenzMaxim 7:9cd16581b578 25 *
IanBenzMaxim 7:9cd16581b578 26 * The mere transfer of this software does not imply any licenses
IanBenzMaxim 7:9cd16581b578 27 * of trade secrets, proprietary technology, copyrights, patents,
IanBenzMaxim 7:9cd16581b578 28 * trademarks, maskwork rights, or any other form of intellectual
IanBenzMaxim 7:9cd16581b578 29 * property whatsoever. Maxim Integrated Products, Inc. retains all
IanBenzMaxim 7:9cd16581b578 30 * ownership rights.
IanBenzMaxim 7:9cd16581b578 31 *******************************************************************************/
IanBenzMaxim 7:9cd16581b578 32
IanBenzMaxim 7:9cd16581b578 33 #include <algorithm>
IanBenzMaxim 7:9cd16581b578 34 #include <MaximInterfaceCore/Error.hpp>
IanBenzMaxim 7:9cd16581b578 35 #include <MaximInterfaceCore/I2CMaster.hpp>
IanBenzMaxim 7:9cd16581b578 36 #include <MaximInterfaceCore/RomId.hpp>
IanBenzMaxim 7:9cd16581b578 37 #include "DS28C36_DS2476.hpp"
IanBenzMaxim 7:9cd16581b578 38
IanBenzMaxim 8:5ea891c7d1a1 39 #define TRY MaximInterfaceCore_TRY
IanBenzMaxim 8:5ea891c7d1a1 40 #define TRY_VALUE MaximInterfaceCore_TRY_VALUE
IanBenzMaxim 8:5ea891c7d1a1 41
IanBenzMaxim 7:9cd16581b578 42 namespace MaximInterfaceDevices {
IanBenzMaxim 7:9cd16581b578 43
IanBenzMaxim 7:9cd16581b578 44 using namespace Core;
IanBenzMaxim 7:9cd16581b578 45 using namespace Ecc256;
IanBenzMaxim 7:9cd16581b578 46 using std::copy;
IanBenzMaxim 7:9cd16581b578 47
IanBenzMaxim 8:5ea891c7d1a1 48 static Result<void> convertResultByte(uint_least8_t resultByte) {
IanBenzMaxim 8:5ea891c7d1a1 49 return (resultByte == 0xAA)
IanBenzMaxim 8:5ea891c7d1a1 50 ? makeResult(none)
IanBenzMaxim 8:5ea891c7d1a1 51 : error_code((resultByte == 0x00)
IanBenzMaxim 8:5ea891c7d1a1 52 ? static_cast<int>(DS28C36::AuthenticationError)
IanBenzMaxim 8:5ea891c7d1a1 53 : resultByte,
IanBenzMaxim 8:5ea891c7d1a1 54 DS28C36::errorCategory());
IanBenzMaxim 7:9cd16581b578 55 }
IanBenzMaxim 7:9cd16581b578 56
IanBenzMaxim 7:9cd16581b578 57 const int DS28C36::publicKeyAxPage;
IanBenzMaxim 7:9cd16581b578 58 const int DS28C36::publicKeyAyPage;
IanBenzMaxim 7:9cd16581b578 59 const int DS28C36::publicKeyBxPage;
IanBenzMaxim 7:9cd16581b578 60 const int DS28C36::publicKeyByPage;
IanBenzMaxim 7:9cd16581b578 61 const int DS28C36::publicKeyCxPage;
IanBenzMaxim 7:9cd16581b578 62 const int DS28C36::publicKeyCyPage;
IanBenzMaxim 7:9cd16581b578 63 const int DS28C36::privateKeyAPage;
IanBenzMaxim 7:9cd16581b578 64 const int DS28C36::privateKeyBPage;
IanBenzMaxim 7:9cd16581b578 65 const int DS28C36::privateKeyCPage;
IanBenzMaxim 7:9cd16581b578 66 const int DS28C36::secretAPage;
IanBenzMaxim 7:9cd16581b578 67 const int DS28C36::secretBPage;
IanBenzMaxim 7:9cd16581b578 68 const int DS28C36::decrementCounterPage;
IanBenzMaxim 7:9cd16581b578 69 const int DS28C36::romOptionsPage;
IanBenzMaxim 7:9cd16581b578 70 const int DS28C36::gpioControlPage;
IanBenzMaxim 7:9cd16581b578 71 const int DS28C36::publicKeySxPage;
IanBenzMaxim 7:9cd16581b578 72 const int DS28C36::publicKeySyPage;
IanBenzMaxim 7:9cd16581b578 73 const int DS28C36::memoryPages;
IanBenzMaxim 7:9cd16581b578 74
IanBenzMaxim 8:5ea891c7d1a1 75 Result<void> DS28C36::writeMemory(int pageNum, Page::const_span page) {
IanBenzMaxim 7:9cd16581b578 76 if (pageNum < 0 || pageNum >= memoryPages) {
IanBenzMaxim 8:5ea891c7d1a1 77 return InvalidParameterError;
IanBenzMaxim 7:9cd16581b578 78 }
IanBenzMaxim 7:9cd16581b578 79
IanBenzMaxim 7:9cd16581b578 80 uint_least8_t buffer[1 + Page::size];
IanBenzMaxim 7:9cd16581b578 81 buffer[0] = pageNum;
IanBenzMaxim 7:9cd16581b578 82 copy(page.begin(), page.end(), buffer + 1);
IanBenzMaxim 8:5ea891c7d1a1 83 Result<void> result = writeCommand(0x96, buffer);
IanBenzMaxim 7:9cd16581b578 84 if (!result) {
IanBenzMaxim 8:5ea891c7d1a1 85 return result;
IanBenzMaxim 7:9cd16581b578 86 }
IanBenzMaxim 8:5ea891c7d1a1 87 sleep(writeMemoryTimeMs);
IanBenzMaxim 8:5ea891c7d1a1 88 result = readFixedLengthResponse(make_span(buffer, 1));
IanBenzMaxim 8:5ea891c7d1a1 89 if (!result) {
IanBenzMaxim 8:5ea891c7d1a1 90 return result;
IanBenzMaxim 8:5ea891c7d1a1 91 }
IanBenzMaxim 8:5ea891c7d1a1 92 result = convertResultByte(buffer[0]);
IanBenzMaxim 7:9cd16581b578 93 return result;
IanBenzMaxim 7:9cd16581b578 94 }
IanBenzMaxim 7:9cd16581b578 95
IanBenzMaxim 8:5ea891c7d1a1 96 Result<DS28C36::Page::array> DS28C36::readMemory(int pageNum) const {
IanBenzMaxim 7:9cd16581b578 97 if (pageNum < 0 || pageNum >= memoryPages) {
IanBenzMaxim 8:5ea891c7d1a1 98 return InvalidParameterError;
IanBenzMaxim 7:9cd16581b578 99 }
IanBenzMaxim 7:9cd16581b578 100
IanBenzMaxim 7:9cd16581b578 101 const uint_least8_t parameter = pageNum;
IanBenzMaxim 8:5ea891c7d1a1 102 Result<void> result = writeCommand(0x69, make_span(&parameter, 1));
IanBenzMaxim 8:5ea891c7d1a1 103 if (!result) {
IanBenzMaxim 8:5ea891c7d1a1 104 return result.error();
IanBenzMaxim 8:5ea891c7d1a1 105 }
IanBenzMaxim 8:5ea891c7d1a1 106 sleep(readMemoryTimeMs);
IanBenzMaxim 8:5ea891c7d1a1 107 array<uint_least8_t, 1 + Page::size> response;
IanBenzMaxim 8:5ea891c7d1a1 108 result = readFixedLengthResponse(response);
IanBenzMaxim 7:9cd16581b578 109 if (!result) {
IanBenzMaxim 8:5ea891c7d1a1 110 return result.error();
IanBenzMaxim 7:9cd16581b578 111 }
IanBenzMaxim 8:5ea891c7d1a1 112 result = convertResultByte(response[0]);
IanBenzMaxim 8:5ea891c7d1a1 113 if (!result) {
IanBenzMaxim 8:5ea891c7d1a1 114 return result.error();
IanBenzMaxim 8:5ea891c7d1a1 115 }
IanBenzMaxim 8:5ea891c7d1a1 116 Page::array page;
IanBenzMaxim 8:5ea891c7d1a1 117 copy(response.begin() + 1, response.end(), page.begin());
IanBenzMaxim 8:5ea891c7d1a1 118 return page;
IanBenzMaxim 7:9cd16581b578 119 }
IanBenzMaxim 7:9cd16581b578 120
IanBenzMaxim 8:5ea891c7d1a1 121 Result<void> DS28C36::writeBuffer(span<const uint_least8_t> data) {
IanBenzMaxim 7:9cd16581b578 122 return writeCommand(0x87, data);
IanBenzMaxim 7:9cd16581b578 123 }
IanBenzMaxim 7:9cd16581b578 124
IanBenzMaxim 8:5ea891c7d1a1 125 Result<std::vector<uint_least8_t> > DS28C36::readBuffer() const {
IanBenzMaxim 8:5ea891c7d1a1 126 TRY(writeCommand(0x5A));
IanBenzMaxim 8:5ea891c7d1a1 127 std::vector<uint_least8_t> buffer(80);
IanBenzMaxim 8:5ea891c7d1a1 128 span<uint_least8_t>::index_type bufferLength;
IanBenzMaxim 8:5ea891c7d1a1 129 TRY_VALUE(bufferLength, readVariableLengthResponse(buffer));
IanBenzMaxim 8:5ea891c7d1a1 130 buffer.resize(bufferLength);
IanBenzMaxim 8:5ea891c7d1a1 131 return buffer;
IanBenzMaxim 7:9cd16581b578 132 }
IanBenzMaxim 7:9cd16581b578 133
IanBenzMaxim 8:5ea891c7d1a1 134 Result<DS28C36::PageProtection> DS28C36::readPageProtection(int pageNum) const {
IanBenzMaxim 7:9cd16581b578 135 if (pageNum < 0 || pageNum >= memoryPages) {
IanBenzMaxim 8:5ea891c7d1a1 136 return InvalidParameterError;
IanBenzMaxim 7:9cd16581b578 137 }
IanBenzMaxim 7:9cd16581b578 138
IanBenzMaxim 7:9cd16581b578 139 uint_least8_t buffer = pageNum;
IanBenzMaxim 8:5ea891c7d1a1 140 Result<void> result = writeCommand(0xAA, make_span(&buffer, 1));
IanBenzMaxim 7:9cd16581b578 141 if (!result) {
IanBenzMaxim 8:5ea891c7d1a1 142 return result.error();
IanBenzMaxim 7:9cd16581b578 143 }
IanBenzMaxim 8:5ea891c7d1a1 144 sleep(readMemoryTimeMs);
IanBenzMaxim 8:5ea891c7d1a1 145 result = readFixedLengthResponse(make_span(&buffer, 1));
IanBenzMaxim 8:5ea891c7d1a1 146 if (!result) {
IanBenzMaxim 8:5ea891c7d1a1 147 return result.error();
IanBenzMaxim 8:5ea891c7d1a1 148 }
IanBenzMaxim 8:5ea891c7d1a1 149 return PageProtection(buffer);
IanBenzMaxim 7:9cd16581b578 150 }
IanBenzMaxim 7:9cd16581b578 151
IanBenzMaxim 8:5ea891c7d1a1 152 Result<void> DS28C36::setPageProtection(int pageNum,
IanBenzMaxim 8:5ea891c7d1a1 153 const PageProtection & protection) {
IanBenzMaxim 7:9cd16581b578 154 if (pageNum < 0 || pageNum >= memoryPages) {
IanBenzMaxim 8:5ea891c7d1a1 155 return InvalidParameterError;
IanBenzMaxim 7:9cd16581b578 156 }
IanBenzMaxim 7:9cd16581b578 157
IanBenzMaxim 7:9cd16581b578 158 uint_least8_t buffer[] = {static_cast<uint_least8_t>(pageNum),
IanBenzMaxim 7:9cd16581b578 159 static_cast<uint_least8_t>(protection.to_ulong())};
IanBenzMaxim 8:5ea891c7d1a1 160 Result<void> result = writeCommand(0xC3, buffer);
IanBenzMaxim 7:9cd16581b578 161 if (!result) {
IanBenzMaxim 8:5ea891c7d1a1 162 return result;
IanBenzMaxim 7:9cd16581b578 163 }
IanBenzMaxim 8:5ea891c7d1a1 164 sleep(writeMemoryTimeMs);
IanBenzMaxim 8:5ea891c7d1a1 165 result = readFixedLengthResponse(make_span(buffer, 1));
IanBenzMaxim 8:5ea891c7d1a1 166 if (!result) {
IanBenzMaxim 8:5ea891c7d1a1 167 return result;
IanBenzMaxim 8:5ea891c7d1a1 168 }
IanBenzMaxim 8:5ea891c7d1a1 169 result = convertResultByte(buffer[0]);
IanBenzMaxim 7:9cd16581b578 170 return result;
IanBenzMaxim 7:9cd16581b578 171 }
IanBenzMaxim 7:9cd16581b578 172
IanBenzMaxim 8:5ea891c7d1a1 173 Result<void> DS28C36::decrementCounter() {
IanBenzMaxim 8:5ea891c7d1a1 174 Result<void> result = writeCommand(0xC9);
IanBenzMaxim 7:9cd16581b578 175 if (!result) {
IanBenzMaxim 8:5ea891c7d1a1 176 return result;
IanBenzMaxim 7:9cd16581b578 177 }
IanBenzMaxim 8:5ea891c7d1a1 178 sleep(writeMemoryTimeMs);
IanBenzMaxim 8:5ea891c7d1a1 179 uint_least8_t response;
IanBenzMaxim 8:5ea891c7d1a1 180 result = readFixedLengthResponse(make_span(&response, 1));
IanBenzMaxim 8:5ea891c7d1a1 181 if (!result) {
IanBenzMaxim 8:5ea891c7d1a1 182 return result;
IanBenzMaxim 8:5ea891c7d1a1 183 }
IanBenzMaxim 8:5ea891c7d1a1 184 result = convertResultByte(response);
IanBenzMaxim 7:9cd16581b578 185 return result;
IanBenzMaxim 7:9cd16581b578 186 }
IanBenzMaxim 7:9cd16581b578 187
IanBenzMaxim 8:5ea891c7d1a1 188 Result<void> DS28C36::readRng(span<uint_least8_t> data) const {
IanBenzMaxim 7:9cd16581b578 189 if ((data.size() < 1) || (data.size() > 64)) {
IanBenzMaxim 8:5ea891c7d1a1 190 return InvalidParameterError;
IanBenzMaxim 7:9cd16581b578 191 }
IanBenzMaxim 7:9cd16581b578 192
IanBenzMaxim 7:9cd16581b578 193 data[0] = static_cast<uint_least8_t>(data.size() - 1);
IanBenzMaxim 8:5ea891c7d1a1 194 Result<void> result = writeCommand(0xD2, data.first(1));
IanBenzMaxim 7:9cd16581b578 195 if (!result) {
IanBenzMaxim 8:5ea891c7d1a1 196 return result;
IanBenzMaxim 7:9cd16581b578 197 }
IanBenzMaxim 8:5ea891c7d1a1 198 sleep(sha256ComputationTimeMs);
IanBenzMaxim 8:5ea891c7d1a1 199 result = readFixedLengthResponse(data);
IanBenzMaxim 7:9cd16581b578 200 return result;
IanBenzMaxim 7:9cd16581b578 201 }
IanBenzMaxim 7:9cd16581b578 202
IanBenzMaxim 8:5ea891c7d1a1 203 Result<std::pair<DS28C36::EncryptionChallenge::array, DS28C36::Page::array> >
IanBenzMaxim 8:5ea891c7d1a1 204 DS28C36::encryptedReadMemory(int pageNum, SecretNum secretNum) const {
IanBenzMaxim 7:9cd16581b578 205 if (pageNum < 0 || pageNum >= memoryPages) {
IanBenzMaxim 8:5ea891c7d1a1 206 return InvalidParameterError;
IanBenzMaxim 7:9cd16581b578 207 }
IanBenzMaxim 7:9cd16581b578 208
IanBenzMaxim 7:9cd16581b578 209 const uint_least8_t parameter = (secretNum << 6) | pageNum;
IanBenzMaxim 8:5ea891c7d1a1 210 Result<void> result = writeCommand(0x4B, make_span(&parameter, 1));
IanBenzMaxim 8:5ea891c7d1a1 211 if (!result) {
IanBenzMaxim 8:5ea891c7d1a1 212 return result.error();
IanBenzMaxim 8:5ea891c7d1a1 213 }
IanBenzMaxim 8:5ea891c7d1a1 214 sleep(readMemoryTimeMs + sha256ComputationTimeMs);
IanBenzMaxim 8:5ea891c7d1a1 215 uint_least8_t response[1 + EncryptionChallenge::size + Page::size];
IanBenzMaxim 8:5ea891c7d1a1 216 result = readFixedLengthResponse(response);
IanBenzMaxim 7:9cd16581b578 217 if (!result) {
IanBenzMaxim 8:5ea891c7d1a1 218 return result.error();
IanBenzMaxim 8:5ea891c7d1a1 219 }
IanBenzMaxim 8:5ea891c7d1a1 220 result = convertResultByte(response[0]);
IanBenzMaxim 8:5ea891c7d1a1 221 if (!result) {
IanBenzMaxim 8:5ea891c7d1a1 222 return result.error();
IanBenzMaxim 7:9cd16581b578 223 }
IanBenzMaxim 8:5ea891c7d1a1 224 std::pair<DS28C36::EncryptionChallenge::array, DS28C36::Page::array> data;
IanBenzMaxim 8:5ea891c7d1a1 225 const uint_least8_t * begin = response + 1;
IanBenzMaxim 8:5ea891c7d1a1 226 const uint_least8_t * end = begin + data.first.size();
IanBenzMaxim 8:5ea891c7d1a1 227 copy(begin, end, data.first.begin());
IanBenzMaxim 8:5ea891c7d1a1 228 begin = end;
IanBenzMaxim 8:5ea891c7d1a1 229 end = begin + data.second.size();
IanBenzMaxim 8:5ea891c7d1a1 230 copy(begin, end, data.second.begin());
IanBenzMaxim 8:5ea891c7d1a1 231 return data;
IanBenzMaxim 7:9cd16581b578 232 }
IanBenzMaxim 7:9cd16581b578 233
IanBenzMaxim 8:5ea891c7d1a1 234 Result<void>
IanBenzMaxim 8:5ea891c7d1a1 235 DS28C36::computeAndReadPageAuthentication(int pageNum,
IanBenzMaxim 8:5ea891c7d1a1 236 AuthType authType) const {
IanBenzMaxim 7:9cd16581b578 237 if (pageNum < 0 || pageNum >= memoryPages) {
IanBenzMaxim 8:5ea891c7d1a1 238 return InvalidParameterError;
IanBenzMaxim 7:9cd16581b578 239 }
IanBenzMaxim 7:9cd16581b578 240
IanBenzMaxim 7:9cd16581b578 241 const uint_least8_t parameter = (authType << 5) | pageNum;
IanBenzMaxim 7:9cd16581b578 242 return writeCommand(0xA5, make_span(&parameter, 1));
IanBenzMaxim 7:9cd16581b578 243 }
IanBenzMaxim 7:9cd16581b578 244
IanBenzMaxim 8:5ea891c7d1a1 245 Result<Signature::array>
IanBenzMaxim 8:5ea891c7d1a1 246 DS28C36::computeAndReadPageAuthentication(int pageNum, KeyNum keyNum) const {
IanBenzMaxim 7:9cd16581b578 247 AuthType authType;
IanBenzMaxim 7:9cd16581b578 248 switch (keyNum) {
IanBenzMaxim 7:9cd16581b578 249 case KeyNumA:
IanBenzMaxim 7:9cd16581b578 250 authType = EcdsaWithKeyA;
IanBenzMaxim 7:9cd16581b578 251 break;
IanBenzMaxim 7:9cd16581b578 252 case KeyNumB:
IanBenzMaxim 7:9cd16581b578 253 authType = EcdsaWithKeyB;
IanBenzMaxim 7:9cd16581b578 254 break;
IanBenzMaxim 7:9cd16581b578 255 case KeyNumC:
IanBenzMaxim 7:9cd16581b578 256 authType = EcdsaWithKeyC;
IanBenzMaxim 7:9cd16581b578 257 break;
IanBenzMaxim 7:9cd16581b578 258 default:
IanBenzMaxim 8:5ea891c7d1a1 259 return InvalidParameterError;
IanBenzMaxim 7:9cd16581b578 260 }
IanBenzMaxim 8:5ea891c7d1a1 261 Result<void> result = computeAndReadPageAuthentication(pageNum, authType);
IanBenzMaxim 8:5ea891c7d1a1 262 if (!result) {
IanBenzMaxim 8:5ea891c7d1a1 263 return result.error();
IanBenzMaxim 8:5ea891c7d1a1 264 }
IanBenzMaxim 8:5ea891c7d1a1 265 sleep(readMemoryTimeMs + generateEcdsaSignatureTimeMs);
IanBenzMaxim 8:5ea891c7d1a1 266 uint_least8_t response[1 + 2 * Scalar::size];
IanBenzMaxim 8:5ea891c7d1a1 267 result = readFixedLengthResponse(response);
IanBenzMaxim 7:9cd16581b578 268 if (!result) {
IanBenzMaxim 8:5ea891c7d1a1 269 return result.error();
IanBenzMaxim 8:5ea891c7d1a1 270 }
IanBenzMaxim 8:5ea891c7d1a1 271 result = convertResultByte(response[0]);
IanBenzMaxim 8:5ea891c7d1a1 272 if (!result) {
IanBenzMaxim 8:5ea891c7d1a1 273 return result.error();
IanBenzMaxim 7:9cd16581b578 274 }
IanBenzMaxim 8:5ea891c7d1a1 275 Signature::array signature;
IanBenzMaxim 8:5ea891c7d1a1 276 const uint_least8_t * begin = response + 1;
IanBenzMaxim 8:5ea891c7d1a1 277 const uint_least8_t * end = begin + signature.s.size();
IanBenzMaxim 8:5ea891c7d1a1 278 copy(begin, end, signature.s.begin());
IanBenzMaxim 8:5ea891c7d1a1 279 begin = end;
IanBenzMaxim 8:5ea891c7d1a1 280 end = begin + signature.r.size();
IanBenzMaxim 8:5ea891c7d1a1 281 copy(begin, end, signature.r.begin());
IanBenzMaxim 8:5ea891c7d1a1 282 return signature;
IanBenzMaxim 7:9cd16581b578 283 }
IanBenzMaxim 7:9cd16581b578 284
IanBenzMaxim 8:5ea891c7d1a1 285 Result<DS28C36::Page::array>
IanBenzMaxim 8:5ea891c7d1a1 286 DS28C36::computeAndReadPageAuthentication(int pageNum,
IanBenzMaxim 8:5ea891c7d1a1 287 SecretNum secretNum) const {
IanBenzMaxim 7:9cd16581b578 288 AuthType authType;
IanBenzMaxim 7:9cd16581b578 289 switch (secretNum) {
IanBenzMaxim 7:9cd16581b578 290 case SecretNumA:
IanBenzMaxim 7:9cd16581b578 291 authType = HmacWithSecretA;
IanBenzMaxim 7:9cd16581b578 292 break;
IanBenzMaxim 7:9cd16581b578 293 case SecretNumB:
IanBenzMaxim 7:9cd16581b578 294 authType = HmacWithSecretB;
IanBenzMaxim 7:9cd16581b578 295 break;
IanBenzMaxim 7:9cd16581b578 296 case SecretNumS:
IanBenzMaxim 7:9cd16581b578 297 authType = HmacWithSecretS;
IanBenzMaxim 7:9cd16581b578 298 break;
IanBenzMaxim 7:9cd16581b578 299 default:
IanBenzMaxim 8:5ea891c7d1a1 300 return InvalidParameterError;
IanBenzMaxim 7:9cd16581b578 301 }
IanBenzMaxim 8:5ea891c7d1a1 302 Result<void> result = computeAndReadPageAuthentication(pageNum, authType);
IanBenzMaxim 8:5ea891c7d1a1 303 if (!result) {
IanBenzMaxim 8:5ea891c7d1a1 304 return result.error();
IanBenzMaxim 8:5ea891c7d1a1 305 }
IanBenzMaxim 8:5ea891c7d1a1 306 sleep(readMemoryTimeMs + sha256ComputationTimeMs);
IanBenzMaxim 8:5ea891c7d1a1 307 array<uint_least8_t, 1 + Page::size> response;
IanBenzMaxim 8:5ea891c7d1a1 308 result = readFixedLengthResponse(response);
IanBenzMaxim 7:9cd16581b578 309 if (!result) {
IanBenzMaxim 8:5ea891c7d1a1 310 return result.error();
IanBenzMaxim 7:9cd16581b578 311 }
IanBenzMaxim 8:5ea891c7d1a1 312 result = convertResultByte(response[0]);
IanBenzMaxim 8:5ea891c7d1a1 313 if (!result) {
IanBenzMaxim 8:5ea891c7d1a1 314 return result.error();
IanBenzMaxim 8:5ea891c7d1a1 315 }
IanBenzMaxim 8:5ea891c7d1a1 316 Page::array hmac;
IanBenzMaxim 8:5ea891c7d1a1 317 copy(response.begin() + 1, response.end(), hmac.begin());
IanBenzMaxim 8:5ea891c7d1a1 318 return hmac;
IanBenzMaxim 7:9cd16581b578 319 }
IanBenzMaxim 7:9cd16581b578 320
IanBenzMaxim 8:5ea891c7d1a1 321 Result<void> DS28C36::authenticatedSha2WriteMemory(int pageNum,
IanBenzMaxim 8:5ea891c7d1a1 322 SecretNum secretNum,
IanBenzMaxim 8:5ea891c7d1a1 323 Page::const_span page) {
IanBenzMaxim 7:9cd16581b578 324 if (pageNum < 0 || pageNum >= memoryPages) {
IanBenzMaxim 8:5ea891c7d1a1 325 return InvalidParameterError;
IanBenzMaxim 7:9cd16581b578 326 }
IanBenzMaxim 7:9cd16581b578 327
IanBenzMaxim 7:9cd16581b578 328 uint_least8_t buffer[1 + Page::size];
IanBenzMaxim 7:9cd16581b578 329 buffer[0] = (secretNum << 6) | pageNum;
IanBenzMaxim 7:9cd16581b578 330 copy(page.begin(), page.end(), buffer + 1);
IanBenzMaxim 8:5ea891c7d1a1 331 Result<void> result = writeCommand(0x99, buffer);
IanBenzMaxim 7:9cd16581b578 332 if (!result) {
IanBenzMaxim 8:5ea891c7d1a1 333 return result;
IanBenzMaxim 7:9cd16581b578 334 }
IanBenzMaxim 8:5ea891c7d1a1 335 sleep(writeMemoryTimeMs + (2 * sha256ComputationTimeMs));
IanBenzMaxim 8:5ea891c7d1a1 336 result = readFixedLengthResponse(make_span(buffer, 1));
IanBenzMaxim 8:5ea891c7d1a1 337 if (!result) {
IanBenzMaxim 8:5ea891c7d1a1 338 return result;
IanBenzMaxim 8:5ea891c7d1a1 339 }
IanBenzMaxim 8:5ea891c7d1a1 340 result = convertResultByte(buffer[0]);
IanBenzMaxim 7:9cd16581b578 341 return result;
IanBenzMaxim 7:9cd16581b578 342 }
IanBenzMaxim 7:9cd16581b578 343
IanBenzMaxim 8:5ea891c7d1a1 344 Result<void> DS28C36::computeAndLockSha2Secret(int pageNum,
IanBenzMaxim 8:5ea891c7d1a1 345 SecretNum msecretNum,
IanBenzMaxim 8:5ea891c7d1a1 346 SecretNum dsecretNum,
IanBenzMaxim 8:5ea891c7d1a1 347 bool writeProtectEnable) {
IanBenzMaxim 7:9cd16581b578 348 // User pages only
IanBenzMaxim 7:9cd16581b578 349 if (pageNum < 0 || pageNum > 15) {
IanBenzMaxim 8:5ea891c7d1a1 350 return InvalidParameterError;
IanBenzMaxim 7:9cd16581b578 351 }
IanBenzMaxim 7:9cd16581b578 352
IanBenzMaxim 7:9cd16581b578 353 uint_least8_t buffer[] = {
IanBenzMaxim 7:9cd16581b578 354 static_cast<uint_least8_t>((dsecretNum << 6) | (msecretNum << 4) |
IanBenzMaxim 7:9cd16581b578 355 pageNum),
IanBenzMaxim 7:9cd16581b578 356 static_cast<uint_least8_t>(writeProtectEnable ? 0x80 : 0x00)};
IanBenzMaxim 8:5ea891c7d1a1 357 Result<void> result = writeCommand(0x3C, buffer);
IanBenzMaxim 7:9cd16581b578 358 if (!result) {
IanBenzMaxim 8:5ea891c7d1a1 359 return result;
IanBenzMaxim 7:9cd16581b578 360 }
IanBenzMaxim 8:5ea891c7d1a1 361 sleep(sha256ComputationTimeMs +
IanBenzMaxim 8:5ea891c7d1a1 362 ((writeProtectEnable ? 2 : 1) * writeMemoryTimeMs));
IanBenzMaxim 8:5ea891c7d1a1 363 result = readFixedLengthResponse(make_span(buffer, 1));
IanBenzMaxim 8:5ea891c7d1a1 364 if (!result) {
IanBenzMaxim 8:5ea891c7d1a1 365 return result;
IanBenzMaxim 8:5ea891c7d1a1 366 }
IanBenzMaxim 8:5ea891c7d1a1 367 result = convertResultByte(buffer[0]);
IanBenzMaxim 7:9cd16581b578 368 return result;
IanBenzMaxim 7:9cd16581b578 369 }
IanBenzMaxim 7:9cd16581b578 370
IanBenzMaxim 8:5ea891c7d1a1 371 Result<void> DS28C36::generateEcc256KeyPair(KeyNum keyNum,
IanBenzMaxim 8:5ea891c7d1a1 372 bool writeProtectEnable) {
IanBenzMaxim 7:9cd16581b578 373 if (keyNum == KeyNumS) {
IanBenzMaxim 8:5ea891c7d1a1 374 return InvalidParameterError;
IanBenzMaxim 7:9cd16581b578 375 }
IanBenzMaxim 7:9cd16581b578 376
IanBenzMaxim 7:9cd16581b578 377 uint_least8_t buffer = keyNum;
IanBenzMaxim 7:9cd16581b578 378 if (writeProtectEnable) {
IanBenzMaxim 7:9cd16581b578 379 buffer |= 0x80;
IanBenzMaxim 7:9cd16581b578 380 }
IanBenzMaxim 8:5ea891c7d1a1 381 Result<void> result = writeCommand(0xCB, make_span(&buffer, 1));
IanBenzMaxim 7:9cd16581b578 382 if (!result) {
IanBenzMaxim 8:5ea891c7d1a1 383 return result;
IanBenzMaxim 7:9cd16581b578 384 }
IanBenzMaxim 8:5ea891c7d1a1 385 sleep(generateEccKeyPairTimeMs);
IanBenzMaxim 8:5ea891c7d1a1 386 result = readFixedLengthResponse(make_span(&buffer, 1));
IanBenzMaxim 8:5ea891c7d1a1 387 if (!result) {
IanBenzMaxim 8:5ea891c7d1a1 388 return result;
IanBenzMaxim 8:5ea891c7d1a1 389 }
IanBenzMaxim 8:5ea891c7d1a1 390 result = convertResultByte(buffer);
IanBenzMaxim 7:9cd16581b578 391 return result;
IanBenzMaxim 7:9cd16581b578 392 }
IanBenzMaxim 7:9cd16581b578 393
IanBenzMaxim 8:5ea891c7d1a1 394 Result<void> DS28C36::computeMultiblockHash(bool firstBlock, bool lastBlock,
IanBenzMaxim 8:5ea891c7d1a1 395 span<const uint_least8_t> data) {
IanBenzMaxim 7:9cd16581b578 396 const span<const uint_least8_t>::index_type maxDataSize = 64;
IanBenzMaxim 7:9cd16581b578 397
IanBenzMaxim 7:9cd16581b578 398 if (data.size() < 1 || data.size() > maxDataSize) {
IanBenzMaxim 8:5ea891c7d1a1 399 return InvalidParameterError;
IanBenzMaxim 7:9cd16581b578 400 }
IanBenzMaxim 7:9cd16581b578 401
IanBenzMaxim 7:9cd16581b578 402 uint_least8_t buffer[1 + maxDataSize];
IanBenzMaxim 7:9cd16581b578 403 buffer[0] = 0;
IanBenzMaxim 7:9cd16581b578 404 if (firstBlock) {
IanBenzMaxim 7:9cd16581b578 405 buffer[0] |= 0x40;
IanBenzMaxim 7:9cd16581b578 406 }
IanBenzMaxim 7:9cd16581b578 407 if (lastBlock) {
IanBenzMaxim 7:9cd16581b578 408 buffer[0] |= 0x80;
IanBenzMaxim 7:9cd16581b578 409 }
IanBenzMaxim 7:9cd16581b578 410 copy(data.begin(), data.end(), buffer + 1);
IanBenzMaxim 8:5ea891c7d1a1 411 Result<void> result = writeCommand(0x33, make_span(buffer, data.size() + 1));
IanBenzMaxim 7:9cd16581b578 412 if (!result) {
IanBenzMaxim 8:5ea891c7d1a1 413 return result;
IanBenzMaxim 7:9cd16581b578 414 }
IanBenzMaxim 8:5ea891c7d1a1 415 sleep(sha256ComputationTimeMs);
IanBenzMaxim 8:5ea891c7d1a1 416 result = readFixedLengthResponse(make_span(buffer, 1));
IanBenzMaxim 8:5ea891c7d1a1 417 if (!result) {
IanBenzMaxim 8:5ea891c7d1a1 418 return result;
IanBenzMaxim 8:5ea891c7d1a1 419 }
IanBenzMaxim 8:5ea891c7d1a1 420 result = convertResultByte(buffer[0]);
IanBenzMaxim 7:9cd16581b578 421 return result;
IanBenzMaxim 7:9cd16581b578 422 }
IanBenzMaxim 7:9cd16581b578 423
IanBenzMaxim 8:5ea891c7d1a1 424 Result<void> DS28C36::verifyEcdsaSignature(KeyNum keyNum, HashType hashType,
IanBenzMaxim 8:5ea891c7d1a1 425 Signature::const_span signature,
IanBenzMaxim 8:5ea891c7d1a1 426 PioState pioa, PioState piob) {
IanBenzMaxim 7:9cd16581b578 427 uint_least8_t buffer[1 + 2 * Scalar::size];
IanBenzMaxim 7:9cd16581b578 428 buffer[0] = keyNum | (hashType << 2);
IanBenzMaxim 7:9cd16581b578 429 if (pioa != Unchanged) {
IanBenzMaxim 7:9cd16581b578 430 buffer[0] |= 0x20;
IanBenzMaxim 7:9cd16581b578 431 }
IanBenzMaxim 7:9cd16581b578 432 if (pioa == Conducting) {
IanBenzMaxim 7:9cd16581b578 433 buffer[0] |= 0x10;
IanBenzMaxim 7:9cd16581b578 434 }
IanBenzMaxim 7:9cd16581b578 435 if (piob != Unchanged) {
IanBenzMaxim 7:9cd16581b578 436 buffer[0] |= 0x80;
IanBenzMaxim 7:9cd16581b578 437 }
IanBenzMaxim 7:9cd16581b578 438 if (piob == Conducting) {
IanBenzMaxim 7:9cd16581b578 439 buffer[0] |= 0x40;
IanBenzMaxim 7:9cd16581b578 440 }
IanBenzMaxim 7:9cd16581b578 441 uint_least8_t * bufferIt =
IanBenzMaxim 7:9cd16581b578 442 copy(signature.r.begin(), signature.r.end(), buffer + 1);
IanBenzMaxim 7:9cd16581b578 443 copy(signature.s.begin(), signature.s.end(), bufferIt);
IanBenzMaxim 8:5ea891c7d1a1 444 Result<void> result = writeCommand(0x59, buffer);
IanBenzMaxim 7:9cd16581b578 445 if (!result) {
IanBenzMaxim 8:5ea891c7d1a1 446 return result;
IanBenzMaxim 7:9cd16581b578 447 }
IanBenzMaxim 8:5ea891c7d1a1 448 sleep(verifyEsdsaSignatureOrComputeEcdhTimeMs +
IanBenzMaxim 8:5ea891c7d1a1 449 ((hashType == DataInBuffer) ? sha256ComputationTimeMs : 0));
IanBenzMaxim 8:5ea891c7d1a1 450 result = readFixedLengthResponse(make_span(buffer, 1));
IanBenzMaxim 8:5ea891c7d1a1 451 if (!result) {
IanBenzMaxim 8:5ea891c7d1a1 452 return result;
IanBenzMaxim 8:5ea891c7d1a1 453 }
IanBenzMaxim 8:5ea891c7d1a1 454 result = convertResultByte(buffer[0]);
IanBenzMaxim 7:9cd16581b578 455 return result;
IanBenzMaxim 7:9cd16581b578 456 }
IanBenzMaxim 7:9cd16581b578 457
IanBenzMaxim 8:5ea891c7d1a1 458 Result<void>
IanBenzMaxim 7:9cd16581b578 459 DS28C36::authenticateEcdsaPublicKey(bool authWrites, bool ecdh, KeyNum keyNum,
IanBenzMaxim 7:9cd16581b578 460 int csOffset,
IanBenzMaxim 7:9cd16581b578 461 Signature::const_span signature) {
IanBenzMaxim 7:9cd16581b578 462 if (((keyNum != KeyNumA) && (keyNum != KeyNumB)) || (csOffset < 0) ||
IanBenzMaxim 7:9cd16581b578 463 (csOffset > 31)) {
IanBenzMaxim 8:5ea891c7d1a1 464 return InvalidParameterError;
IanBenzMaxim 7:9cd16581b578 465 }
IanBenzMaxim 7:9cd16581b578 466
IanBenzMaxim 7:9cd16581b578 467 uint_least8_t buffer[1 + 2 * Scalar::size];
IanBenzMaxim 7:9cd16581b578 468 buffer[0] = (csOffset << 3) | (keyNum << 2);
IanBenzMaxim 7:9cd16581b578 469 if (ecdh) {
IanBenzMaxim 7:9cd16581b578 470 buffer[0] |= 0x02;
IanBenzMaxim 7:9cd16581b578 471 }
IanBenzMaxim 7:9cd16581b578 472 if (authWrites) {
IanBenzMaxim 7:9cd16581b578 473 buffer[0] |= 0x01;
IanBenzMaxim 7:9cd16581b578 474 }
IanBenzMaxim 7:9cd16581b578 475 uint_least8_t * bufferIt =
IanBenzMaxim 7:9cd16581b578 476 copy(signature.r.begin(), signature.r.end(), buffer + 1);
IanBenzMaxim 7:9cd16581b578 477 copy(signature.s.begin(), signature.s.end(), bufferIt);
IanBenzMaxim 8:5ea891c7d1a1 478 Result<void> result = writeCommand(0xA8, buffer);
IanBenzMaxim 7:9cd16581b578 479 if (!result) {
IanBenzMaxim 8:5ea891c7d1a1 480 return result;
IanBenzMaxim 7:9cd16581b578 481 }
IanBenzMaxim 8:5ea891c7d1a1 482 sleep((ecdh ? 2 : 1) * verifyEsdsaSignatureOrComputeEcdhTimeMs);
IanBenzMaxim 8:5ea891c7d1a1 483 result = readFixedLengthResponse(make_span(buffer, 1));
IanBenzMaxim 8:5ea891c7d1a1 484 if (!result) {
IanBenzMaxim 8:5ea891c7d1a1 485 return result;
IanBenzMaxim 8:5ea891c7d1a1 486 }
IanBenzMaxim 8:5ea891c7d1a1 487 result = convertResultByte(buffer[0]);
IanBenzMaxim 7:9cd16581b578 488 return result;
IanBenzMaxim 7:9cd16581b578 489 }
IanBenzMaxim 7:9cd16581b578 490
IanBenzMaxim 8:5ea891c7d1a1 491 Result<void> DS28C36::authenticatedEcdsaWriteMemory(int pageNum,
IanBenzMaxim 8:5ea891c7d1a1 492 Page::const_span page) {
IanBenzMaxim 7:9cd16581b578 493 if (pageNum < 0 || pageNum >= memoryPages) {
IanBenzMaxim 8:5ea891c7d1a1 494 return InvalidParameterError;
IanBenzMaxim 7:9cd16581b578 495 }
IanBenzMaxim 7:9cd16581b578 496
IanBenzMaxim 7:9cd16581b578 497 uint_least8_t buffer[1 + Page::size];
IanBenzMaxim 7:9cd16581b578 498 buffer[0] = pageNum;
IanBenzMaxim 7:9cd16581b578 499 copy(page.begin(), page.end(), buffer + 1);
IanBenzMaxim 8:5ea891c7d1a1 500 Result<void> result = writeCommand(0x89, buffer);
IanBenzMaxim 7:9cd16581b578 501 if (!result) {
IanBenzMaxim 8:5ea891c7d1a1 502 return result;
IanBenzMaxim 7:9cd16581b578 503 }
IanBenzMaxim 8:5ea891c7d1a1 504 sleep(verifyEsdsaSignatureOrComputeEcdhTimeMs + writeMemoryTimeMs +
IanBenzMaxim 8:5ea891c7d1a1 505 sha256ComputationTimeMs);
IanBenzMaxim 8:5ea891c7d1a1 506 result = readFixedLengthResponse(make_span(buffer, 1));
IanBenzMaxim 8:5ea891c7d1a1 507 if (!result) {
IanBenzMaxim 8:5ea891c7d1a1 508 return result;
IanBenzMaxim 8:5ea891c7d1a1 509 }
IanBenzMaxim 8:5ea891c7d1a1 510 result = convertResultByte(buffer[0]);
IanBenzMaxim 7:9cd16581b578 511 return result;
IanBenzMaxim 7:9cd16581b578 512 }
IanBenzMaxim 7:9cd16581b578 513
IanBenzMaxim 8:5ea891c7d1a1 514 Result<void> DS28C36::writeCommand(uint_least8_t command,
IanBenzMaxim 8:5ea891c7d1a1 515 span<const uint_least8_t> parameters) const {
IanBenzMaxim 8:5ea891c7d1a1 516 Result<void> result = master->start(address_);
IanBenzMaxim 8:5ea891c7d1a1 517 if (!result) {
IanBenzMaxim 7:9cd16581b578 518 master->stop();
IanBenzMaxim 7:9cd16581b578 519 return result;
IanBenzMaxim 7:9cd16581b578 520 }
IanBenzMaxim 7:9cd16581b578 521 result = master->writeByte(command);
IanBenzMaxim 8:5ea891c7d1a1 522 if (!result) {
IanBenzMaxim 7:9cd16581b578 523 master->stop();
IanBenzMaxim 7:9cd16581b578 524 return result;
IanBenzMaxim 7:9cd16581b578 525 }
IanBenzMaxim 7:9cd16581b578 526 if (!parameters.empty()) {
IanBenzMaxim 7:9cd16581b578 527 result = master->writeByte(static_cast<uint_least8_t>(parameters.size()));
IanBenzMaxim 8:5ea891c7d1a1 528 if (!result) {
IanBenzMaxim 7:9cd16581b578 529 master->stop();
IanBenzMaxim 7:9cd16581b578 530 return result;
IanBenzMaxim 7:9cd16581b578 531 }
IanBenzMaxim 7:9cd16581b578 532 result = master->writeBlock(parameters);
IanBenzMaxim 8:5ea891c7d1a1 533 if (!result) {
IanBenzMaxim 7:9cd16581b578 534 master->stop();
IanBenzMaxim 7:9cd16581b578 535 return result;
IanBenzMaxim 7:9cd16581b578 536 }
IanBenzMaxim 7:9cd16581b578 537 }
IanBenzMaxim 7:9cd16581b578 538 result = master->stop();
IanBenzMaxim 7:9cd16581b578 539 return result;
IanBenzMaxim 7:9cd16581b578 540 }
IanBenzMaxim 7:9cd16581b578 541
IanBenzMaxim 8:5ea891c7d1a1 542 Result<span<uint_least8_t>::index_type>
IanBenzMaxim 8:5ea891c7d1a1 543 DS28C36::readVariableLengthResponse(span<uint_least8_t> response) const {
IanBenzMaxim 8:5ea891c7d1a1 544 Result<void> result = master->start(address_ | 1);
IanBenzMaxim 8:5ea891c7d1a1 545 if (!result) {
IanBenzMaxim 7:9cd16581b578 546 master->stop();
IanBenzMaxim 8:5ea891c7d1a1 547 return result.error();
IanBenzMaxim 7:9cd16581b578 548 }
IanBenzMaxim 7:9cd16581b578 549 uint_least8_t length;
IanBenzMaxim 8:5ea891c7d1a1 550 if (const Result<uint_least8_t> result = master->readByte(I2CMaster::Ack)) {
IanBenzMaxim 8:5ea891c7d1a1 551 length = result.value();
IanBenzMaxim 8:5ea891c7d1a1 552 } else {
IanBenzMaxim 7:9cd16581b578 553 master->stop();
IanBenzMaxim 8:5ea891c7d1a1 554 return result.error();
IanBenzMaxim 7:9cd16581b578 555 }
IanBenzMaxim 7:9cd16581b578 556 if (length > response.size()) {
IanBenzMaxim 7:9cd16581b578 557 master->stop();
IanBenzMaxim 8:5ea891c7d1a1 558 return InvalidResponseError;
IanBenzMaxim 7:9cd16581b578 559 }
IanBenzMaxim 8:5ea891c7d1a1 560 if (length > 0) {
IanBenzMaxim 8:5ea891c7d1a1 561 result = master->readBlock(response.first(length), I2CMaster::Nack);
IanBenzMaxim 8:5ea891c7d1a1 562 if (!result) {
IanBenzMaxim 7:9cd16581b578 563 master->stop();
IanBenzMaxim 8:5ea891c7d1a1 564 return result.error();
IanBenzMaxim 7:9cd16581b578 565 }
IanBenzMaxim 7:9cd16581b578 566 }
IanBenzMaxim 7:9cd16581b578 567 result = master->stop();
IanBenzMaxim 8:5ea891c7d1a1 568 if (!result) {
IanBenzMaxim 8:5ea891c7d1a1 569 return result.error();
IanBenzMaxim 8:5ea891c7d1a1 570 }
IanBenzMaxim 8:5ea891c7d1a1 571 return length;
IanBenzMaxim 7:9cd16581b578 572 }
IanBenzMaxim 7:9cd16581b578 573
IanBenzMaxim 8:5ea891c7d1a1 574 Result<void>
IanBenzMaxim 8:5ea891c7d1a1 575 DS28C36::readFixedLengthResponse(span<uint_least8_t> response) const {
IanBenzMaxim 8:5ea891c7d1a1 576 span<uint_least8_t>::index_type responseLength;
IanBenzMaxim 8:5ea891c7d1a1 577 TRY_VALUE(responseLength, readVariableLengthResponse(response));
IanBenzMaxim 8:5ea891c7d1a1 578 return (responseLength == response.size()) ? makeResult(none)
IanBenzMaxim 8:5ea891c7d1a1 579 : InvalidResponseError;
IanBenzMaxim 7:9cd16581b578 580 }
IanBenzMaxim 7:9cd16581b578 581
IanBenzMaxim 7:9cd16581b578 582 const error_category & DS28C36::errorCategory() {
IanBenzMaxim 7:9cd16581b578 583 static class : public error_category {
IanBenzMaxim 7:9cd16581b578 584 public:
IanBenzMaxim 11:3f3bf6bf5e6c 585 virtual const char * name() const {
IanBenzMaxim 11:3f3bf6bf5e6c 586 return "MaximInterfaceDevices.DS28C36_DS2476";
IanBenzMaxim 11:3f3bf6bf5e6c 587 }
IanBenzMaxim 7:9cd16581b578 588
IanBenzMaxim 7:9cd16581b578 589 virtual std::string message(int condition) const {
IanBenzMaxim 7:9cd16581b578 590 switch (condition) {
IanBenzMaxim 7:9cd16581b578 591 case ProtectionError:
IanBenzMaxim 7:9cd16581b578 592 return "Protection Error";
IanBenzMaxim 7:9cd16581b578 593
IanBenzMaxim 7:9cd16581b578 594 case InvalidParameterError:
IanBenzMaxim 7:9cd16581b578 595 return "Invalid Parameter Error";
IanBenzMaxim 7:9cd16581b578 596
IanBenzMaxim 7:9cd16581b578 597 case InvalidSequenceError:
IanBenzMaxim 7:9cd16581b578 598 return "Invalid Sequence Error";
IanBenzMaxim 7:9cd16581b578 599
IanBenzMaxim 7:9cd16581b578 600 case InvalidEcdsaInputOrResultError:
IanBenzMaxim 7:9cd16581b578 601 return "Invalid ECDSA Input or Result Error";
IanBenzMaxim 7:9cd16581b578 602
IanBenzMaxim 7:9cd16581b578 603 case AuthenticationError:
IanBenzMaxim 7:9cd16581b578 604 return "Authentication Error";
IanBenzMaxim 7:9cd16581b578 605
IanBenzMaxim 7:9cd16581b578 606 case InvalidResponseError:
IanBenzMaxim 7:9cd16581b578 607 return "Invalid Response Error";
IanBenzMaxim 7:9cd16581b578 608 }
IanBenzMaxim 8:5ea891c7d1a1 609 return defaultErrorMessage(condition);
IanBenzMaxim 7:9cd16581b578 610 }
IanBenzMaxim 7:9cd16581b578 611 } instance;
IanBenzMaxim 7:9cd16581b578 612 return instance;
IanBenzMaxim 7:9cd16581b578 613 }
IanBenzMaxim 7:9cd16581b578 614
IanBenzMaxim 8:5ea891c7d1a1 615 Result<Signature::array> DS2476::generateEcdsaSignature(KeyNum keyNum) const {
IanBenzMaxim 7:9cd16581b578 616 if (keyNum == KeyNumS) {
IanBenzMaxim 8:5ea891c7d1a1 617 return InvalidParameterError;
IanBenzMaxim 7:9cd16581b578 618 }
IanBenzMaxim 7:9cd16581b578 619
IanBenzMaxim 7:9cd16581b578 620 const uint_least8_t parameter = keyNum;
IanBenzMaxim 8:5ea891c7d1a1 621 Result<void> result = writeCommand(0x1E, make_span(&parameter, 1));
IanBenzMaxim 8:5ea891c7d1a1 622 if (!result) {
IanBenzMaxim 8:5ea891c7d1a1 623 return result.error();
IanBenzMaxim 8:5ea891c7d1a1 624 }
IanBenzMaxim 8:5ea891c7d1a1 625 sleep(generateEcdsaSignatureTimeMs);
IanBenzMaxim 8:5ea891c7d1a1 626 uint_least8_t response[1 + 2 * Scalar::size];
IanBenzMaxim 8:5ea891c7d1a1 627 result = readFixedLengthResponse(response);
IanBenzMaxim 8:5ea891c7d1a1 628 if (!result) {
IanBenzMaxim 8:5ea891c7d1a1 629 return result.error();
IanBenzMaxim 8:5ea891c7d1a1 630 }
IanBenzMaxim 8:5ea891c7d1a1 631 result = convertResultByte(response[0]);
IanBenzMaxim 7:9cd16581b578 632 if (!result) {
IanBenzMaxim 8:5ea891c7d1a1 633 return result.error();
IanBenzMaxim 7:9cd16581b578 634 }
IanBenzMaxim 8:5ea891c7d1a1 635 Signature::array signature;
IanBenzMaxim 8:5ea891c7d1a1 636 const uint_least8_t * begin = response + 1;
IanBenzMaxim 8:5ea891c7d1a1 637 const uint_least8_t * end = begin + signature.s.size();
IanBenzMaxim 8:5ea891c7d1a1 638 copy(begin, end, signature.s.begin());
IanBenzMaxim 8:5ea891c7d1a1 639 begin = end;
IanBenzMaxim 8:5ea891c7d1a1 640 end = begin + signature.r.size();
IanBenzMaxim 8:5ea891c7d1a1 641 copy(begin, end, signature.r.begin());
IanBenzMaxim 8:5ea891c7d1a1 642 return signature;
IanBenzMaxim 8:5ea891c7d1a1 643 }
IanBenzMaxim 8:5ea891c7d1a1 644
IanBenzMaxim 8:5ea891c7d1a1 645 Result<void> DS2476::computeSha2UniqueSecret(SecretNum msecretNum) {
IanBenzMaxim 8:5ea891c7d1a1 646 uint_least8_t buffer = msecretNum << 4;
IanBenzMaxim 8:5ea891c7d1a1 647 Result<void> result = writeCommand(0x55, make_span(&buffer, 1));
IanBenzMaxim 8:5ea891c7d1a1 648 if (!result) {
IanBenzMaxim 8:5ea891c7d1a1 649 return result;
IanBenzMaxim 8:5ea891c7d1a1 650 }
IanBenzMaxim 8:5ea891c7d1a1 651 sleep(sha256ComputationTimeMs);
IanBenzMaxim 8:5ea891c7d1a1 652 result = readFixedLengthResponse(make_span(&buffer, 1));
IanBenzMaxim 8:5ea891c7d1a1 653 if (!result) {
IanBenzMaxim 8:5ea891c7d1a1 654 return result;
IanBenzMaxim 8:5ea891c7d1a1 655 }
IanBenzMaxim 8:5ea891c7d1a1 656 result = convertResultByte(buffer);
IanBenzMaxim 7:9cd16581b578 657 return result;
IanBenzMaxim 7:9cd16581b578 658 }
IanBenzMaxim 7:9cd16581b578 659
IanBenzMaxim 8:5ea891c7d1a1 660 Result<DS2476::Page::array> DS2476::computeSha2Hmac() const {
IanBenzMaxim 8:5ea891c7d1a1 661 Result<void> result = writeCommand(0x2D);
IanBenzMaxim 8:5ea891c7d1a1 662 if (!result) {
IanBenzMaxim 8:5ea891c7d1a1 663 return result.error();
IanBenzMaxim 8:5ea891c7d1a1 664 }
IanBenzMaxim 8:5ea891c7d1a1 665 sleep(sha256ComputationTimeMs);
IanBenzMaxim 8:5ea891c7d1a1 666 array<uint_least8_t, 1 + Page::size> response;
IanBenzMaxim 8:5ea891c7d1a1 667 result = readFixedLengthResponse(response);
IanBenzMaxim 7:9cd16581b578 668 if (!result) {
IanBenzMaxim 8:5ea891c7d1a1 669 return result.error();
IanBenzMaxim 7:9cd16581b578 670 }
IanBenzMaxim 8:5ea891c7d1a1 671 result = convertResultByte(response[0]);
IanBenzMaxim 8:5ea891c7d1a1 672 if (!result) {
IanBenzMaxim 8:5ea891c7d1a1 673 return result.error();
IanBenzMaxim 8:5ea891c7d1a1 674 }
IanBenzMaxim 8:5ea891c7d1a1 675 Page::array hmac;
IanBenzMaxim 8:5ea891c7d1a1 676 copy(response.begin() + 1, response.end(), hmac.begin());
IanBenzMaxim 8:5ea891c7d1a1 677 return hmac;
IanBenzMaxim 7:9cd16581b578 678 }
IanBenzMaxim 7:9cd16581b578 679
IanBenzMaxim 8:5ea891c7d1a1 680 Result<void> computeMultiblockHash(DS28C36 & ds28c36,
IanBenzMaxim 8:5ea891c7d1a1 681 span<const uint_least8_t> data) {
IanBenzMaxim 7:9cd16581b578 682 span<const uint_least8_t>::index_type dataIdx = 0;
IanBenzMaxim 8:5ea891c7d1a1 683 while (dataIdx < data.size()) {
IanBenzMaxim 7:9cd16581b578 684 const span<const uint_least8_t>::index_type remainingSize =
IanBenzMaxim 7:9cd16581b578 685 data.size() - dataIdx;
IanBenzMaxim 7:9cd16581b578 686 const span<const uint_least8_t>::index_type chunkSize =
IanBenzMaxim 7:9cd16581b578 687 std::min<span<const uint_least8_t>::index_type>(remainingSize, 64);
IanBenzMaxim 8:5ea891c7d1a1 688 TRY(ds28c36.computeMultiblockHash(dataIdx == 0, remainingSize == chunkSize,
IanBenzMaxim 8:5ea891c7d1a1 689 data.subspan(dataIdx, chunkSize)));
IanBenzMaxim 7:9cd16581b578 690 dataIdx += chunkSize;
IanBenzMaxim 7:9cd16581b578 691 }
IanBenzMaxim 8:5ea891c7d1a1 692 return none;
IanBenzMaxim 7:9cd16581b578 693 }
IanBenzMaxim 7:9cd16581b578 694
IanBenzMaxim 8:5ea891c7d1a1 695 Result<void> verifyEcdsaSignature(DS28C36 & ds28c36, DS28C36::KeyNum publicKey,
IanBenzMaxim 8:5ea891c7d1a1 696 span<const uint_least8_t> data,
IanBenzMaxim 8:5ea891c7d1a1 697 Signature::const_span signature,
IanBenzMaxim 8:5ea891c7d1a1 698 DS28C36::PioState pioa,
IanBenzMaxim 8:5ea891c7d1a1 699 DS28C36::PioState piob) {
IanBenzMaxim 8:5ea891c7d1a1 700 Result<void> result = computeMultiblockHash(ds28c36, data);
IanBenzMaxim 8:5ea891c7d1a1 701 if (result) {
IanBenzMaxim 7:9cd16581b578 702 result = ds28c36.verifyEcdsaSignature(publicKey, DS28C36::THASH, signature,
IanBenzMaxim 7:9cd16581b578 703 pioa, piob);
IanBenzMaxim 7:9cd16581b578 704 }
IanBenzMaxim 7:9cd16581b578 705 return result;
IanBenzMaxim 7:9cd16581b578 706 }
IanBenzMaxim 7:9cd16581b578 707
IanBenzMaxim 8:5ea891c7d1a1 708 Result<void> verifyEcdsaSignature(DS28C36 & ds28c36,
IanBenzMaxim 8:5ea891c7d1a1 709 PublicKey::const_span publicKey,
IanBenzMaxim 8:5ea891c7d1a1 710 span<const uint_least8_t> data,
IanBenzMaxim 8:5ea891c7d1a1 711 Signature::const_span signature,
IanBenzMaxim 8:5ea891c7d1a1 712 DS28C36::PioState pioa,
IanBenzMaxim 8:5ea891c7d1a1 713 DS28C36::PioState piob) {
IanBenzMaxim 8:5ea891c7d1a1 714 Result<void> result =
IanBenzMaxim 7:9cd16581b578 715 ds28c36.writeMemory(DS28C36::publicKeySxPage, publicKey.x);
IanBenzMaxim 7:9cd16581b578 716 if (!result) {
IanBenzMaxim 8:5ea891c7d1a1 717 return result;
IanBenzMaxim 7:9cd16581b578 718 }
IanBenzMaxim 8:5ea891c7d1a1 719 result = ds28c36.writeMemory(DS28C36::publicKeySyPage, publicKey.y);
IanBenzMaxim 7:9cd16581b578 720 if (!result) {
IanBenzMaxim 8:5ea891c7d1a1 721 return result;
IanBenzMaxim 7:9cd16581b578 722 }
IanBenzMaxim 8:5ea891c7d1a1 723 result = verifyEcdsaSignature(ds28c36, DS28C36::KeyNumS, data, signature,
IanBenzMaxim 8:5ea891c7d1a1 724 pioa, piob);
IanBenzMaxim 7:9cd16581b578 725 return result;
IanBenzMaxim 7:9cd16581b578 726 }
IanBenzMaxim 7:9cd16581b578 727
IanBenzMaxim 8:5ea891c7d1a1 728 Result<void> enableCoprocessor(DS2476 & ds2476) {
IanBenzMaxim 8:5ea891c7d1a1 729 DS2476::Page::array page;
IanBenzMaxim 8:5ea891c7d1a1 730 TRY_VALUE(page, ds2476.readMemory(DS2476::gpioControlPage));
IanBenzMaxim 8:5ea891c7d1a1 731 DS2476::GpioControl gpioControl(page);
IanBenzMaxim 8:5ea891c7d1a1 732 if (!gpioControl.pioaConducting()) {
IanBenzMaxim 8:5ea891c7d1a1 733 gpioControl.setPioaConducting(true);
IanBenzMaxim 8:5ea891c7d1a1 734 TRY(ds2476.writeMemory(DS2476::gpioControlPage, page));
IanBenzMaxim 7:9cd16581b578 735 }
IanBenzMaxim 8:5ea891c7d1a1 736 return none;
IanBenzMaxim 7:9cd16581b578 737 }
IanBenzMaxim 7:9cd16581b578 738
IanBenzMaxim 8:5ea891c7d1a1 739 Result<void> enableRomId(DS2476 & ds2476) {
IanBenzMaxim 7:9cd16581b578 740 DS2476::Page::array page;
IanBenzMaxim 8:5ea891c7d1a1 741 TRY_VALUE(page, ds2476.readMemory(DS2476::romOptionsPage));
IanBenzMaxim 8:5ea891c7d1a1 742 DS2476::RomOptions romOptions(page);
IanBenzMaxim 8:5ea891c7d1a1 743 if (!romOptions.romBlockDisable()) {
IanBenzMaxim 8:5ea891c7d1a1 744 romOptions.setRomBlockDisable(true);
IanBenzMaxim 8:5ea891c7d1a1 745 TRY(ds2476.writeMemory(DS2476::romOptionsPage, page));
IanBenzMaxim 7:9cd16581b578 746 }
IanBenzMaxim 8:5ea891c7d1a1 747 return none;
IanBenzMaxim 7:9cd16581b578 748 }
IanBenzMaxim 7:9cd16581b578 749
IanBenzMaxim 7:9cd16581b578 750 static void setAnonymous(RomId::span romId) {
IanBenzMaxim 7:9cd16581b578 751 std::fill(romId.begin(), romId.end(), 0xFF);
IanBenzMaxim 7:9cd16581b578 752 }
IanBenzMaxim 7:9cd16581b578 753
IanBenzMaxim 7:9cd16581b578 754 DS28C36::PageAuthenticationData &
IanBenzMaxim 7:9cd16581b578 755 DS28C36::PageAuthenticationData::setAnonymousRomId() {
IanBenzMaxim 7:9cd16581b578 756 setAnonymous(romId());
IanBenzMaxim 7:9cd16581b578 757 return *this;
IanBenzMaxim 7:9cd16581b578 758 }
IanBenzMaxim 7:9cd16581b578 759
IanBenzMaxim 7:9cd16581b578 760 DS28C36::EncryptionHmacData & DS28C36::EncryptionHmacData::setAnonymousRomId() {
IanBenzMaxim 7:9cd16581b578 761 setAnonymous(romId());
IanBenzMaxim 7:9cd16581b578 762 return *this;
IanBenzMaxim 7:9cd16581b578 763 }
IanBenzMaxim 7:9cd16581b578 764
IanBenzMaxim 7:9cd16581b578 765 } // namespace MaximInterfaceDevices