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 <stddef.h>
IanBenzMaxim 7:9cd16581b578 34 #include <algorithm>
IanBenzMaxim 7:9cd16581b578 35 #include <MaximInterfaceCore/Error.hpp>
IanBenzMaxim 7:9cd16581b578 36 #include "DS28C40.hpp"
IanBenzMaxim 7:9cd16581b578 37
IanBenzMaxim 7:9cd16581b578 38 namespace MaximInterfaceDevices {
IanBenzMaxim 7:9cd16581b578 39
IanBenzMaxim 7:9cd16581b578 40 using namespace Core;
IanBenzMaxim 7:9cd16581b578 41 using std::copy;
IanBenzMaxim 8:5ea891c7d1a1 42 using std::pair;
IanBenzMaxim 7:9cd16581b578 43
IanBenzMaxim 7:9cd16581b578 44 static const int readMemoryTimeMs = 2;
IanBenzMaxim 7:9cd16581b578 45 static const int writeMemoryTimeMs = 150;
IanBenzMaxim 7:9cd16581b578 46 static const int writeStateTimeMs = 15;
IanBenzMaxim 7:9cd16581b578 47 static const int generateEccKeyPairTimeMs = 500;
IanBenzMaxim 7:9cd16581b578 48 static const int generateEcdsaSignatureTimeMs = 50;
IanBenzMaxim 7:9cd16581b578 49 static const int computeTimeMs = 4;
IanBenzMaxim 7:9cd16581b578 50 static const int verifyEcdsaTimeMs = 160;
IanBenzMaxim 7:9cd16581b578 51 static const int trngGenerationTimeMs = 50;
IanBenzMaxim 7:9cd16581b578 52 static const int trngOnDemandCheckTimeMs = 50;
IanBenzMaxim 7:9cd16581b578 53
IanBenzMaxim 7:9cd16581b578 54 static const uint_least8_t computeAndReadPageAuthenticationCmd = 0xA5;
IanBenzMaxim 7:9cd16581b578 55 static const uint_least8_t readRngCmd = 0xD2;
IanBenzMaxim 7:9cd16581b578 56
IanBenzMaxim 7:9cd16581b578 57 const int DS28C40::publicKeyAxPage;
IanBenzMaxim 7:9cd16581b578 58 const int DS28C40::publicKeyAyPage;
IanBenzMaxim 7:9cd16581b578 59 const int DS28C40::publicKeyBxPage;
IanBenzMaxim 7:9cd16581b578 60 const int DS28C40::publicKeyByPage;
IanBenzMaxim 7:9cd16581b578 61 const int DS28C40::authorityPublicKeyAxPage;
IanBenzMaxim 7:9cd16581b578 62 const int DS28C40::authorityPublicKeyAyPage;
IanBenzMaxim 7:9cd16581b578 63 const int DS28C40::authorityPublicKeyBxPage;
IanBenzMaxim 7:9cd16581b578 64 const int DS28C40::authorityPublicKeyByPage;
IanBenzMaxim 7:9cd16581b578 65 const int DS28C40::privateKeyAPage;
IanBenzMaxim 7:9cd16581b578 66 const int DS28C40::privateKeyBPage;
IanBenzMaxim 7:9cd16581b578 67 const int DS28C40::secretAPage;
IanBenzMaxim 7:9cd16581b578 68 const int DS28C40::secretBPage;
IanBenzMaxim 7:9cd16581b578 69 const int DS28C40::romOptionsPage;
IanBenzMaxim 7:9cd16581b578 70 const int DS28C40::gpioControlPage;
IanBenzMaxim 7:9cd16581b578 71 const int DS28C40::publicKeySxPage;
IanBenzMaxim 7:9cd16581b578 72 const int DS28C40::publicKeySyPage;
IanBenzMaxim 7:9cd16581b578 73
IanBenzMaxim 7:9cd16581b578 74 const int DS28C40::memoryPages;
IanBenzMaxim 7:9cd16581b578 75 const int DS28C40::protectionBlocks;
IanBenzMaxim 7:9cd16581b578 76
IanBenzMaxim 8:5ea891c7d1a1 77 Result<void> DS28C40::writeMemory(int pageNum, Page::const_span page) {
IanBenzMaxim 7:9cd16581b578 78 if (pageNum < 0 || pageNum >= memoryPages) {
IanBenzMaxim 8:5ea891c7d1a1 79 return InvalidParameterError;
IanBenzMaxim 7:9cd16581b578 80 }
IanBenzMaxim 7:9cd16581b578 81
IanBenzMaxim 7:9cd16581b578 82 uint_least8_t request[2 + Page::size];
IanBenzMaxim 7:9cd16581b578 83 request[0] = 0x96;
IanBenzMaxim 7:9cd16581b578 84 request[1] = pageNum;
IanBenzMaxim 7:9cd16581b578 85 copy(page.begin(), page.end(), request + 2);
IanBenzMaxim 7:9cd16581b578 86 return runCommand(request, writeMemoryTimeMs);
IanBenzMaxim 7:9cd16581b578 87 }
IanBenzMaxim 7:9cd16581b578 88
IanBenzMaxim 8:5ea891c7d1a1 89 Result<DS28C40::Page::array> DS28C40::readMemory(int pageNum) const {
IanBenzMaxim 7:9cd16581b578 90 if (pageNum < 0 || pageNum >= memoryPages) {
IanBenzMaxim 8:5ea891c7d1a1 91 return InvalidParameterError;
IanBenzMaxim 7:9cd16581b578 92 }
IanBenzMaxim 7:9cd16581b578 93
IanBenzMaxim 7:9cd16581b578 94 uint_least8_t buffer[1 + Page::size];
IanBenzMaxim 7:9cd16581b578 95 buffer[0] = 0x44;
IanBenzMaxim 7:9cd16581b578 96 buffer[1] = pageNum;
IanBenzMaxim 8:5ea891c7d1a1 97 const Result<span<uint_least8_t> > response =
IanBenzMaxim 8:5ea891c7d1a1 98 runCommand(make_span(buffer, 2), readMemoryTimeMs, buffer);
IanBenzMaxim 8:5ea891c7d1a1 99 if (!response) {
IanBenzMaxim 8:5ea891c7d1a1 100 return response.error();
IanBenzMaxim 7:9cd16581b578 101 }
IanBenzMaxim 8:5ea891c7d1a1 102 Page::array page;
IanBenzMaxim 8:5ea891c7d1a1 103 copy(response.value().begin(), response.value().end(), page.begin());
IanBenzMaxim 8:5ea891c7d1a1 104 return page;
IanBenzMaxim 7:9cd16581b578 105 }
IanBenzMaxim 7:9cd16581b578 106
IanBenzMaxim 8:5ea891c7d1a1 107 Result<pair<DS28C40::EncryptionChallenge::array, DS28C40::Page::array> >
IanBenzMaxim 8:5ea891c7d1a1 108 DS28C40::encryptedReadMemory(int pageNum, KeySecret secret) const {
IanBenzMaxim 7:9cd16581b578 109 if (pageNum < 0 || pageNum >= memoryPages) {
IanBenzMaxim 8:5ea891c7d1a1 110 return InvalidParameterError;
IanBenzMaxim 7:9cd16581b578 111 }
IanBenzMaxim 7:9cd16581b578 112
IanBenzMaxim 7:9cd16581b578 113 const size_t requestSize = 3;
IanBenzMaxim 7:9cd16581b578 114 const size_t responseSize = 1 + EncryptionChallenge::size + Page::size;
IanBenzMaxim 7:9cd16581b578 115 uint_least8_t buffer[MaximInterfaceCore_MAX(requestSize, responseSize)];
IanBenzMaxim 7:9cd16581b578 116 buffer[0] = 0x4B;
IanBenzMaxim 7:9cd16581b578 117 buffer[1] = pageNum;
IanBenzMaxim 7:9cd16581b578 118 buffer[2] = secret;
IanBenzMaxim 8:5ea891c7d1a1 119 const Result<span<uint_least8_t> > response = runCommand(
IanBenzMaxim 8:5ea891c7d1a1 120 make_span(buffer, requestSize), readMemoryTimeMs + computeTimeMs,
IanBenzMaxim 8:5ea891c7d1a1 121 make_span(buffer, responseSize));
IanBenzMaxim 8:5ea891c7d1a1 122 if (!response) {
IanBenzMaxim 8:5ea891c7d1a1 123 return response.error();
IanBenzMaxim 7:9cd16581b578 124 }
IanBenzMaxim 8:5ea891c7d1a1 125 pair<EncryptionChallenge::array, Page::array> data;
IanBenzMaxim 8:5ea891c7d1a1 126 span<uint_least8_t>::const_iterator begin = response.value().begin();
IanBenzMaxim 8:5ea891c7d1a1 127 span<uint_least8_t>::const_iterator end = begin + data.first.size();
IanBenzMaxim 8:5ea891c7d1a1 128 copy(begin, end, data.first.begin());
IanBenzMaxim 8:5ea891c7d1a1 129 begin = end;
IanBenzMaxim 8:5ea891c7d1a1 130 end = begin + data.second.size();
IanBenzMaxim 8:5ea891c7d1a1 131 copy(begin, end, data.second.begin());
IanBenzMaxim 8:5ea891c7d1a1 132 return data;
IanBenzMaxim 7:9cd16581b578 133 }
IanBenzMaxim 7:9cd16581b578 134
IanBenzMaxim 8:5ea891c7d1a1 135 Result<pair<Optional<DS28C40::KeySecret>, DS28C40::BlockProtection> >
IanBenzMaxim 8:5ea891c7d1a1 136 DS28C40::readBlockProtection(int blockNumber) const {
IanBenzMaxim 7:9cd16581b578 137 if (blockNumber < 0 || blockNumber >= protectionBlocks) {
IanBenzMaxim 8:5ea891c7d1a1 138 return InvalidParameterError;
IanBenzMaxim 7:9cd16581b578 139 }
IanBenzMaxim 7:9cd16581b578 140
IanBenzMaxim 7:9cd16581b578 141 const size_t requestSize = 2;
IanBenzMaxim 7:9cd16581b578 142 const size_t responseSize = 3;
IanBenzMaxim 7:9cd16581b578 143 uint_least8_t buffer[MaximInterfaceCore_MAX(requestSize, responseSize)];
IanBenzMaxim 7:9cd16581b578 144 buffer[0] = 0xAA;
IanBenzMaxim 7:9cd16581b578 145 buffer[1] = blockNumber;
IanBenzMaxim 8:5ea891c7d1a1 146 const Result<span<uint_least8_t> > response =
IanBenzMaxim 8:5ea891c7d1a1 147 runCommand(make_span(buffer, requestSize), readMemoryTimeMs,
IanBenzMaxim 8:5ea891c7d1a1 148 make_span(buffer, responseSize));
IanBenzMaxim 8:5ea891c7d1a1 149 if (!response) {
IanBenzMaxim 8:5ea891c7d1a1 150 return response.error();
IanBenzMaxim 7:9cd16581b578 151 }
IanBenzMaxim 8:5ea891c7d1a1 152 if ((response.value()[0] & 0x3F) != blockNumber) {
IanBenzMaxim 8:5ea891c7d1a1 153 return InvalidResponseError;
IanBenzMaxim 7:9cd16581b578 154 }
IanBenzMaxim 8:5ea891c7d1a1 155 pair<Optional<KeySecret>, BlockProtection> data;
IanBenzMaxim 8:5ea891c7d1a1 156 switch (response.value()[0] >> 6) {
IanBenzMaxim 7:9cd16581b578 157 case 0:
IanBenzMaxim 8:5ea891c7d1a1 158 data.first = none;
IanBenzMaxim 7:9cd16581b578 159 break;
IanBenzMaxim 7:9cd16581b578 160 case 1:
IanBenzMaxim 8:5ea891c7d1a1 161 data.first = KeySecretA;
IanBenzMaxim 7:9cd16581b578 162 break;
IanBenzMaxim 7:9cd16581b578 163 case 2:
IanBenzMaxim 8:5ea891c7d1a1 164 data.first = KeySecretB;
IanBenzMaxim 7:9cd16581b578 165 break;
IanBenzMaxim 7:9cd16581b578 166 default:
IanBenzMaxim 8:5ea891c7d1a1 167 return InvalidResponseError;
IanBenzMaxim 7:9cd16581b578 168 }
IanBenzMaxim 8:5ea891c7d1a1 169 if ((response.value()[1] & 0x20) != 0) {
IanBenzMaxim 8:5ea891c7d1a1 170 return InvalidResponseError;
IanBenzMaxim 7:9cd16581b578 171 }
IanBenzMaxim 8:5ea891c7d1a1 172 data.second = response.value()[1];
IanBenzMaxim 8:5ea891c7d1a1 173 return data;
IanBenzMaxim 7:9cd16581b578 174 }
IanBenzMaxim 7:9cd16581b578 175
IanBenzMaxim 8:5ea891c7d1a1 176 Result<void> DS28C40::setBlockProtection(int blockNum, KeySecret keySecret,
IanBenzMaxim 8:5ea891c7d1a1 177 const BlockProtection & protection) {
IanBenzMaxim 7:9cd16581b578 178 if (blockNum < 0 || blockNum >= protectionBlocks || keySecret == KeySecretS) {
IanBenzMaxim 8:5ea891c7d1a1 179 return InvalidParameterError;
IanBenzMaxim 7:9cd16581b578 180 }
IanBenzMaxim 7:9cd16581b578 181
IanBenzMaxim 7:9cd16581b578 182 const uint_least8_t request[] = {
IanBenzMaxim 7:9cd16581b578 183 0xC3,
IanBenzMaxim 7:9cd16581b578 184 static_cast<uint_least8_t>((keySecret == KeySecretB ? 0x80 : 0x40) |
IanBenzMaxim 7:9cd16581b578 185 blockNum),
IanBenzMaxim 7:9cd16581b578 186 static_cast<uint_least8_t>(protection.to_ulong())};
IanBenzMaxim 7:9cd16581b578 187 return runCommand(request, writeStateTimeMs);
IanBenzMaxim 7:9cd16581b578 188 }
IanBenzMaxim 7:9cd16581b578 189
IanBenzMaxim 8:5ea891c7d1a1 190 Result<Ecc256::Signature::array> DS28C40::computeAndReadEcdsaPageAuthentication(
IanBenzMaxim 8:5ea891c7d1a1 191 int pageNum, KeySecret key, Page::const_span challenge) const {
IanBenzMaxim 7:9cd16581b578 192 if (pageNum < 0 || pageNum >= memoryPages || key == KeySecretS) {
IanBenzMaxim 8:5ea891c7d1a1 193 return InvalidParameterError;
IanBenzMaxim 7:9cd16581b578 194 }
IanBenzMaxim 7:9cd16581b578 195
IanBenzMaxim 7:9cd16581b578 196 const size_t requestSize = 3 + Page::size;
IanBenzMaxim 7:9cd16581b578 197 const size_t responseSize = 1 + 2 * Ecc256::Scalar::size;
IanBenzMaxim 7:9cd16581b578 198 uint_least8_t buffer[MaximInterfaceCore_MAX(requestSize, responseSize)];
IanBenzMaxim 7:9cd16581b578 199 buffer[0] = computeAndReadPageAuthenticationCmd;
IanBenzMaxim 7:9cd16581b578 200 buffer[1] = pageNum;
IanBenzMaxim 7:9cd16581b578 201 buffer[2] = key + 3;
IanBenzMaxim 7:9cd16581b578 202 copy(challenge.begin(), challenge.end(), buffer + 3);
IanBenzMaxim 8:5ea891c7d1a1 203 const Result<span<uint_least8_t> > response =
IanBenzMaxim 8:5ea891c7d1a1 204 runCommand(make_span(buffer, requestSize), generateEcdsaSignatureTimeMs,
IanBenzMaxim 8:5ea891c7d1a1 205 make_span(buffer, responseSize));
IanBenzMaxim 8:5ea891c7d1a1 206 if (!response) {
IanBenzMaxim 8:5ea891c7d1a1 207 return response.error();
IanBenzMaxim 7:9cd16581b578 208 }
IanBenzMaxim 8:5ea891c7d1a1 209 Ecc256::Signature::array signature;
IanBenzMaxim 8:5ea891c7d1a1 210 span<uint_least8_t>::const_iterator begin = response.value().begin();
IanBenzMaxim 8:5ea891c7d1a1 211 span<uint_least8_t>::const_iterator end = begin + signature.s.size();
IanBenzMaxim 8:5ea891c7d1a1 212 copy(begin, end, signature.s.begin());
IanBenzMaxim 8:5ea891c7d1a1 213 begin = end;
IanBenzMaxim 8:5ea891c7d1a1 214 end = begin + signature.r.size();
IanBenzMaxim 8:5ea891c7d1a1 215 copy(begin, end, signature.r.begin());
IanBenzMaxim 8:5ea891c7d1a1 216 return signature;
IanBenzMaxim 7:9cd16581b578 217 }
IanBenzMaxim 7:9cd16581b578 218
IanBenzMaxim 8:5ea891c7d1a1 219 Result<DS28C40::Page::array> DS28C40::computeAndReadSha256PageAuthentication(
IanBenzMaxim 8:5ea891c7d1a1 220 int pageNum, KeySecret secret, Page::const_span challenge) const {
IanBenzMaxim 7:9cd16581b578 221 if (pageNum < 0 || pageNum >= memoryPages) {
IanBenzMaxim 8:5ea891c7d1a1 222 return InvalidParameterError;
IanBenzMaxim 7:9cd16581b578 223 }
IanBenzMaxim 7:9cd16581b578 224
IanBenzMaxim 7:9cd16581b578 225 const size_t requestSize = 3 + Page::size;
IanBenzMaxim 7:9cd16581b578 226 const size_t responseSize = 1 + Page::size;
IanBenzMaxim 7:9cd16581b578 227 uint_least8_t buffer[MaximInterfaceCore_MAX(requestSize, responseSize)];
IanBenzMaxim 7:9cd16581b578 228 buffer[0] = computeAndReadPageAuthenticationCmd;
IanBenzMaxim 7:9cd16581b578 229 buffer[1] = pageNum;
IanBenzMaxim 7:9cd16581b578 230 buffer[2] = secret;
IanBenzMaxim 7:9cd16581b578 231 copy(challenge.begin(), challenge.end(), buffer + 3);
IanBenzMaxim 8:5ea891c7d1a1 232 const Result<span<uint_least8_t> > response =
IanBenzMaxim 8:5ea891c7d1a1 233 runCommand(make_span(buffer, requestSize), computeTimeMs,
IanBenzMaxim 8:5ea891c7d1a1 234 make_span(buffer, responseSize));
IanBenzMaxim 8:5ea891c7d1a1 235 if (!response) {
IanBenzMaxim 8:5ea891c7d1a1 236 return response.error();
IanBenzMaxim 7:9cd16581b578 237 }
IanBenzMaxim 8:5ea891c7d1a1 238 Page::array hmac;
IanBenzMaxim 8:5ea891c7d1a1 239 copy(response.value().begin(), response.value().end(), hmac.begin());
IanBenzMaxim 8:5ea891c7d1a1 240 return hmac;
IanBenzMaxim 7:9cd16581b578 241 }
IanBenzMaxim 7:9cd16581b578 242
IanBenzMaxim 8:5ea891c7d1a1 243 Result<void> DS28C40::computeMultiblockHash(bool firstBlock, bool lastBlock,
IanBenzMaxim 8:5ea891c7d1a1 244 span<const uint_least8_t> data) {
IanBenzMaxim 7:9cd16581b578 245 const span<const uint_least8_t>::index_type maxDataSize = 64;
IanBenzMaxim 7:9cd16581b578 246
IanBenzMaxim 7:9cd16581b578 247 if (data.size() < 1 || data.size() > maxDataSize) {
IanBenzMaxim 8:5ea891c7d1a1 248 return InvalidParameterError;
IanBenzMaxim 7:9cd16581b578 249 }
IanBenzMaxim 7:9cd16581b578 250
IanBenzMaxim 7:9cd16581b578 251 uint_least8_t buffer[2 + maxDataSize];
IanBenzMaxim 7:9cd16581b578 252 buffer[0] = 0x33;
IanBenzMaxim 7:9cd16581b578 253 buffer[1] = 0;
IanBenzMaxim 7:9cd16581b578 254 if (firstBlock) {
IanBenzMaxim 7:9cd16581b578 255 buffer[1] |= 0x40;
IanBenzMaxim 7:9cd16581b578 256 }
IanBenzMaxim 7:9cd16581b578 257 if (lastBlock) {
IanBenzMaxim 7:9cd16581b578 258 buffer[1] |= 0x80;
IanBenzMaxim 7:9cd16581b578 259 }
IanBenzMaxim 7:9cd16581b578 260 copy(data.begin(), data.end(), buffer + 2);
IanBenzMaxim 7:9cd16581b578 261 return runCommand(make_span(buffer, 2 + data.size()), computeTimeMs);
IanBenzMaxim 7:9cd16581b578 262 }
IanBenzMaxim 7:9cd16581b578 263
IanBenzMaxim 8:5ea891c7d1a1 264 Result<void> DS28C40::verifyEcdsaSignature(
IanBenzMaxim 7:9cd16581b578 265 KeySecret key, bool authorityKey, GpioState gpioState,
IanBenzMaxim 7:9cd16581b578 266 Ecc256::Signature::const_span signature, span<const uint_least8_t> data) {
IanBenzMaxim 7:9cd16581b578 267 return verifyEcdsaSignature(key, authorityKey, DataInput, gpioState,
IanBenzMaxim 7:9cd16581b578 268 signature, data);
IanBenzMaxim 7:9cd16581b578 269 }
IanBenzMaxim 7:9cd16581b578 270
IanBenzMaxim 8:5ea891c7d1a1 271 Result<void> DS28C40::verifyEcdsaSignature(
IanBenzMaxim 7:9cd16581b578 272 KeySecret key, bool authorityKey, GpioState gpioState,
IanBenzMaxim 7:9cd16581b578 273 Ecc256::Signature::const_span signature, Page::const_span hash) {
IanBenzMaxim 7:9cd16581b578 274 return verifyEcdsaSignature(key, authorityKey, HashInput, gpioState,
IanBenzMaxim 7:9cd16581b578 275 signature, hash);
IanBenzMaxim 7:9cd16581b578 276 }
IanBenzMaxim 7:9cd16581b578 277
IanBenzMaxim 8:5ea891c7d1a1 278 Result<void>
IanBenzMaxim 7:9cd16581b578 279 DS28C40::verifyEcdsaSignature(KeySecret key, bool authorityKey,
IanBenzMaxim 7:9cd16581b578 280 GpioState gpioState,
IanBenzMaxim 7:9cd16581b578 281 Ecc256::Signature::const_span signature) {
IanBenzMaxim 7:9cd16581b578 282 return verifyEcdsaSignature(key, authorityKey, THASH, gpioState, signature,
IanBenzMaxim 7:9cd16581b578 283 span<const uint_least8_t>());
IanBenzMaxim 7:9cd16581b578 284 }
IanBenzMaxim 7:9cd16581b578 285
IanBenzMaxim 8:5ea891c7d1a1 286 Result<void> DS28C40::verifyEcdsaSignature(
IanBenzMaxim 7:9cd16581b578 287 KeySecret key, bool authorityKey, HashType hashType, GpioState gpioState,
IanBenzMaxim 7:9cd16581b578 288 Ecc256::Signature::const_span signature, span<const uint_least8_t> buffer) {
IanBenzMaxim 7:9cd16581b578 289 const span<const uint_least8_t>::index_type maxBufferSize = 61;
IanBenzMaxim 7:9cd16581b578 290
IanBenzMaxim 7:9cd16581b578 291 if (buffer.size() > maxBufferSize) {
IanBenzMaxim 8:5ea891c7d1a1 292 return InvalidParameterError;
IanBenzMaxim 7:9cd16581b578 293 }
IanBenzMaxim 7:9cd16581b578 294
IanBenzMaxim 7:9cd16581b578 295 uint_least8_t request[2 + 2 * Ecc256::Scalar::size + maxBufferSize];
IanBenzMaxim 7:9cd16581b578 296 uint_least8_t * requestIt = request;
IanBenzMaxim 7:9cd16581b578 297 *requestIt++ = 0x59;
IanBenzMaxim 7:9cd16581b578 298 switch (key) {
IanBenzMaxim 7:9cd16581b578 299 case KeySecretA:
IanBenzMaxim 7:9cd16581b578 300 if (authorityKey) {
IanBenzMaxim 7:9cd16581b578 301 *requestIt = 2;
IanBenzMaxim 7:9cd16581b578 302 } else {
IanBenzMaxim 7:9cd16581b578 303 *requestIt = 0;
IanBenzMaxim 7:9cd16581b578 304 }
IanBenzMaxim 7:9cd16581b578 305 break;
IanBenzMaxim 7:9cd16581b578 306 case KeySecretB:
IanBenzMaxim 7:9cd16581b578 307 if (authorityKey) {
IanBenzMaxim 7:9cd16581b578 308 *requestIt = 3;
IanBenzMaxim 7:9cd16581b578 309 } else {
IanBenzMaxim 7:9cd16581b578 310 *requestIt = 1;
IanBenzMaxim 7:9cd16581b578 311 }
IanBenzMaxim 7:9cd16581b578 312 break;
IanBenzMaxim 7:9cd16581b578 313 case KeySecretS:
IanBenzMaxim 7:9cd16581b578 314 if (!authorityKey) {
IanBenzMaxim 7:9cd16581b578 315 *requestIt = 4;
IanBenzMaxim 7:9cd16581b578 316 break;
IanBenzMaxim 7:9cd16581b578 317 }
IanBenzMaxim 7:9cd16581b578 318 // else: Go to default case.
IanBenzMaxim 7:9cd16581b578 319 default:
IanBenzMaxim 8:5ea891c7d1a1 320 return InvalidParameterError;
IanBenzMaxim 7:9cd16581b578 321 }
IanBenzMaxim 7:9cd16581b578 322 *requestIt |= hashType << 3;
IanBenzMaxim 7:9cd16581b578 323 if (gpioState != Unchanged) {
IanBenzMaxim 7:9cd16581b578 324 *requestIt |= 0x40;
IanBenzMaxim 7:9cd16581b578 325 }
IanBenzMaxim 7:9cd16581b578 326 if (gpioState == Conducting) {
IanBenzMaxim 7:9cd16581b578 327 *requestIt |= 0x20;
IanBenzMaxim 7:9cd16581b578 328 }
IanBenzMaxim 7:9cd16581b578 329 requestIt = copy(signature.r.begin(), signature.r.end(), ++requestIt);
IanBenzMaxim 7:9cd16581b578 330 requestIt = copy(signature.s.begin(), signature.s.end(), requestIt);
IanBenzMaxim 7:9cd16581b578 331 requestIt = copy(buffer.begin(), buffer.end(), requestIt);
IanBenzMaxim 7:9cd16581b578 332 return runCommand(make_span(request, requestIt),
IanBenzMaxim 7:9cd16581b578 333 verifyEcdsaTimeMs +
IanBenzMaxim 7:9cd16581b578 334 (hashType == DataInput ? computeTimeMs : 0));
IanBenzMaxim 7:9cd16581b578 335 }
IanBenzMaxim 7:9cd16581b578 336
IanBenzMaxim 8:5ea891c7d1a1 337 Result<void> DS28C40::authenticateEcdsaPublicKey(
IanBenzMaxim 7:9cd16581b578 338 KeySecret key, Ecc256::Signature::const_span cert,
IanBenzMaxim 7:9cd16581b578 339 span<const uint_least8_t> certCustomization) {
IanBenzMaxim 7:9cd16581b578 340 return authenticateEcdsaPublicKey(key, true, cert, certCustomization, NULL);
IanBenzMaxim 7:9cd16581b578 341 }
IanBenzMaxim 7:9cd16581b578 342
IanBenzMaxim 8:5ea891c7d1a1 343 Result<void> DS28C40::authenticateEcdsaPublicKey(
IanBenzMaxim 7:9cd16581b578 344 KeySecret key, bool authWrites, Ecc256::Signature::const_span cert,
IanBenzMaxim 7:9cd16581b578 345 span<const uint_least8_t> certCustomization,
IanBenzMaxim 7:9cd16581b578 346 span<const uint_least8_t> ecdhCustomization) {
IanBenzMaxim 7:9cd16581b578 347 return authenticateEcdsaPublicKey(key, authWrites, cert, certCustomization,
IanBenzMaxim 7:9cd16581b578 348 &ecdhCustomization);
IanBenzMaxim 7:9cd16581b578 349 }
IanBenzMaxim 7:9cd16581b578 350
IanBenzMaxim 8:5ea891c7d1a1 351 Result<void> DS28C40::authenticateEcdsaPublicKey(
IanBenzMaxim 7:9cd16581b578 352 KeySecret key, bool authWrites, Ecc256::Signature::const_span cert,
IanBenzMaxim 7:9cd16581b578 353 span<const uint_least8_t> certCustomization,
IanBenzMaxim 7:9cd16581b578 354 const span<const uint_least8_t> * ecdhCustomization) {
IanBenzMaxim 7:9cd16581b578 355 const span<const uint_least8_t>::index_type minCustomizationSize = 1;
IanBenzMaxim 7:9cd16581b578 356 const span<const uint_least8_t>::index_type maxCertCustomizationSize = 32;
IanBenzMaxim 7:9cd16581b578 357 const span<const uint_least8_t>::index_type maxEcdhCustomizationSize = 48;
IanBenzMaxim 7:9cd16581b578 358 const span<const uint_least8_t>::index_type maxTotalCustomizationSize = 60;
IanBenzMaxim 7:9cd16581b578 359
IanBenzMaxim 7:9cd16581b578 360 if (!(certCustomization.size() >= minCustomizationSize &&
IanBenzMaxim 7:9cd16581b578 361 certCustomization.size() <= maxCertCustomizationSize &&
IanBenzMaxim 7:9cd16581b578 362 (!ecdhCustomization ||
IanBenzMaxim 7:9cd16581b578 363 (ecdhCustomization->size() >= minCustomizationSize &&
IanBenzMaxim 7:9cd16581b578 364 ecdhCustomization->size() <= maxEcdhCustomizationSize &&
IanBenzMaxim 7:9cd16581b578 365 certCustomization.size() + ecdhCustomization->size() <=
IanBenzMaxim 7:9cd16581b578 366 maxTotalCustomizationSize)))) {
IanBenzMaxim 8:5ea891c7d1a1 367 return InvalidParameterError;
IanBenzMaxim 7:9cd16581b578 368 }
IanBenzMaxim 7:9cd16581b578 369
IanBenzMaxim 7:9cd16581b578 370 if (key == KeySecretS) {
IanBenzMaxim 8:5ea891c7d1a1 371 return InvalidParameterError;
IanBenzMaxim 7:9cd16581b578 372 }
IanBenzMaxim 7:9cd16581b578 373
IanBenzMaxim 7:9cd16581b578 374 uint_least8_t
IanBenzMaxim 7:9cd16581b578 375 request[2 + 2 * Ecc256::Scalar::size + maxTotalCustomizationSize];
IanBenzMaxim 7:9cd16581b578 376 uint_least8_t * requestIt = request;
IanBenzMaxim 7:9cd16581b578 377 *requestIt++ = 0xA8;
IanBenzMaxim 7:9cd16581b578 378 *requestIt++ = static_cast<uint_least8_t>(
IanBenzMaxim 7:9cd16581b578 379 ((certCustomization.size() - 1) << 3) | (key << 2) |
IanBenzMaxim 7:9cd16581b578 380 ((ecdhCustomization != NULL) << 1) | (authWrites << 0));
IanBenzMaxim 7:9cd16581b578 381 requestIt = copy(cert.r.begin(), cert.r.end(), requestIt);
IanBenzMaxim 7:9cd16581b578 382 requestIt = copy(cert.s.begin(), cert.s.end(), requestIt);
IanBenzMaxim 7:9cd16581b578 383 requestIt =
IanBenzMaxim 7:9cd16581b578 384 copy(certCustomization.begin(), certCustomization.end(), requestIt);
IanBenzMaxim 7:9cd16581b578 385 int delay = verifyEcdsaTimeMs;
IanBenzMaxim 7:9cd16581b578 386 if (ecdhCustomization) {
IanBenzMaxim 7:9cd16581b578 387 const span<const uint_least8_t>::index_type certCustomizationPaddingSize =
IanBenzMaxim 7:9cd16581b578 388 maxCertCustomizationSize - certCustomization.size();
IanBenzMaxim 7:9cd16581b578 389 std::fill_n(requestIt, certCustomizationPaddingSize, 0);
IanBenzMaxim 7:9cd16581b578 390 requestIt += certCustomizationPaddingSize;
IanBenzMaxim 7:9cd16581b578 391 requestIt =
IanBenzMaxim 7:9cd16581b578 392 copy(ecdhCustomization->begin(), ecdhCustomization->end(), requestIt);
IanBenzMaxim 7:9cd16581b578 393 delay += verifyEcdsaTimeMs;
IanBenzMaxim 7:9cd16581b578 394 }
IanBenzMaxim 7:9cd16581b578 395 return runCommand(make_span(request, requestIt), delay);
IanBenzMaxim 7:9cd16581b578 396 }
IanBenzMaxim 7:9cd16581b578 397
IanBenzMaxim 8:5ea891c7d1a1 398 Result<void> DS28C40::authenticatedEcdsaWriteMemory(
IanBenzMaxim 7:9cd16581b578 399 int pageNum, bool useKeyS, Page::const_span newPageData,
IanBenzMaxim 7:9cd16581b578 400 Ecc256::Signature::const_span signature) {
IanBenzMaxim 7:9cd16581b578 401 return authenticatedEcdsaWriteMemory(pageNum, useKeyS, newPageData, signature,
IanBenzMaxim 7:9cd16581b578 402 NULL);
IanBenzMaxim 7:9cd16581b578 403 }
IanBenzMaxim 7:9cd16581b578 404
IanBenzMaxim 8:5ea891c7d1a1 405 Result<void> DS28C40::authenticatedEcdsaWriteMemory(
IanBenzMaxim 7:9cd16581b578 406 int pageNum, bool useKeyS, Page::const_span newPageData,
IanBenzMaxim 7:9cd16581b578 407 Ecc256::Signature::const_span signature,
IanBenzMaxim 7:9cd16581b578 408 EncryptionChallenge::const_span challenge) {
IanBenzMaxim 7:9cd16581b578 409 return authenticatedEcdsaWriteMemory(pageNum, useKeyS, newPageData, signature,
IanBenzMaxim 7:9cd16581b578 410 &challenge);
IanBenzMaxim 7:9cd16581b578 411 }
IanBenzMaxim 7:9cd16581b578 412
IanBenzMaxim 8:5ea891c7d1a1 413 Result<void> DS28C40::authenticatedEcdsaWriteMemory(
IanBenzMaxim 7:9cd16581b578 414 int pageNum, bool useKeyS, Page::const_span newPageData,
IanBenzMaxim 7:9cd16581b578 415 Ecc256::Signature::const_span signature,
IanBenzMaxim 7:9cd16581b578 416 const EncryptionChallenge::const_span * challenge) {
IanBenzMaxim 7:9cd16581b578 417 if (pageNum < 0 || pageNum >= memoryPages) {
IanBenzMaxim 8:5ea891c7d1a1 418 return InvalidParameterError;
IanBenzMaxim 7:9cd16581b578 419 }
IanBenzMaxim 7:9cd16581b578 420
IanBenzMaxim 7:9cd16581b578 421 uint_least8_t request[2 + Page::size + 2 * Ecc256::Scalar::size +
IanBenzMaxim 7:9cd16581b578 422 EncryptionChallenge::size];
IanBenzMaxim 7:9cd16581b578 423 uint_least8_t * requestIt = request;
IanBenzMaxim 7:9cd16581b578 424 *requestIt++ = 0x89;
IanBenzMaxim 7:9cd16581b578 425 *requestIt = pageNum;
IanBenzMaxim 7:9cd16581b578 426 if (useKeyS) {
IanBenzMaxim 7:9cd16581b578 427 *requestIt |= 0x80;
IanBenzMaxim 7:9cd16581b578 428 }
IanBenzMaxim 7:9cd16581b578 429 requestIt = copy(newPageData.begin(), newPageData.end(), ++requestIt);
IanBenzMaxim 7:9cd16581b578 430 requestIt = copy(signature.r.begin(), signature.r.end(), requestIt);
IanBenzMaxim 7:9cd16581b578 431 requestIt = copy(signature.s.begin(), signature.s.end(), requestIt);
IanBenzMaxim 7:9cd16581b578 432 int delay = verifyEcdsaTimeMs + writeMemoryTimeMs;
IanBenzMaxim 7:9cd16581b578 433 if (challenge) {
IanBenzMaxim 7:9cd16581b578 434 requestIt = copy(challenge->begin(), challenge->end(), requestIt);
IanBenzMaxim 7:9cd16581b578 435 delay += computeTimeMs;
IanBenzMaxim 7:9cd16581b578 436 }
IanBenzMaxim 7:9cd16581b578 437 return runCommand(make_span(request, requestIt), delay);
IanBenzMaxim 7:9cd16581b578 438 }
IanBenzMaxim 7:9cd16581b578 439
IanBenzMaxim 8:5ea891c7d1a1 440 Result<void>
IanBenzMaxim 8:5ea891c7d1a1 441 DS28C40::authenticatedSha256WriteMemory(int pageNum, bool useSecretS,
IanBenzMaxim 8:5ea891c7d1a1 442 Page::const_span newPageData,
IanBenzMaxim 8:5ea891c7d1a1 443 Page::const_span hmac) {
IanBenzMaxim 7:9cd16581b578 444 return authenticatedSha256WriteMemory(pageNum, useSecretS, newPageData, hmac,
IanBenzMaxim 7:9cd16581b578 445 NULL);
IanBenzMaxim 7:9cd16581b578 446 }
IanBenzMaxim 7:9cd16581b578 447
IanBenzMaxim 8:5ea891c7d1a1 448 Result<void> DS28C40::authenticatedSha256WriteMemory(
IanBenzMaxim 7:9cd16581b578 449 int pageNum, bool useSecretS, Page::const_span newPageData,
IanBenzMaxim 7:9cd16581b578 450 Page::const_span hmac, EncryptionChallenge::const_span challenge) {
IanBenzMaxim 7:9cd16581b578 451 return authenticatedSha256WriteMemory(pageNum, useSecretS, newPageData, hmac,
IanBenzMaxim 7:9cd16581b578 452 &challenge);
IanBenzMaxim 7:9cd16581b578 453 }
IanBenzMaxim 7:9cd16581b578 454
IanBenzMaxim 8:5ea891c7d1a1 455 Result<void> DS28C40::authenticatedSha256WriteMemory(
IanBenzMaxim 7:9cd16581b578 456 int pageNum, bool useSecretS, Page::const_span newPageData,
IanBenzMaxim 7:9cd16581b578 457 Page::const_span hmac, const EncryptionChallenge::const_span * challenge) {
IanBenzMaxim 7:9cd16581b578 458 if (pageNum < 0 || pageNum >= memoryPages) {
IanBenzMaxim 8:5ea891c7d1a1 459 return InvalidParameterError;
IanBenzMaxim 7:9cd16581b578 460 }
IanBenzMaxim 7:9cd16581b578 461
IanBenzMaxim 7:9cd16581b578 462 uint_least8_t request[3 + 2 * Page::size + EncryptionChallenge::size];
IanBenzMaxim 7:9cd16581b578 463 uint_least8_t * requestIt = request;
IanBenzMaxim 7:9cd16581b578 464 *requestIt++ = 0x99;
IanBenzMaxim 7:9cd16581b578 465 *requestIt++ = pageNum;
IanBenzMaxim 7:9cd16581b578 466 *requestIt++ = useSecretS ? 2 : 0;
IanBenzMaxim 7:9cd16581b578 467 requestIt = copy(newPageData.begin(), newPageData.end(), requestIt);
IanBenzMaxim 7:9cd16581b578 468 requestIt = copy(hmac.begin(), hmac.end(), requestIt);
IanBenzMaxim 7:9cd16581b578 469 int delay = writeMemoryTimeMs + computeTimeMs;
IanBenzMaxim 7:9cd16581b578 470 if (challenge) {
IanBenzMaxim 7:9cd16581b578 471 requestIt = copy(challenge->begin(), challenge->end(), requestIt);
IanBenzMaxim 7:9cd16581b578 472 delay += computeTimeMs;
IanBenzMaxim 7:9cd16581b578 473 }
IanBenzMaxim 7:9cd16581b578 474 return runCommand(make_span(request, requestIt), delay);
IanBenzMaxim 7:9cd16581b578 475 }
IanBenzMaxim 7:9cd16581b578 476
IanBenzMaxim 8:5ea891c7d1a1 477 Result<void>
IanBenzMaxim 7:9cd16581b578 478 DS28C40::computeAndWriteSha256Secret(int pageNum, KeySecret masterSecret,
IanBenzMaxim 7:9cd16581b578 479 KeySecret destinationSecret,
IanBenzMaxim 7:9cd16581b578 480 Page::const_span partialSecret) {
IanBenzMaxim 7:9cd16581b578 481 if (pageNum < 0 || pageNum >= memoryPages) {
IanBenzMaxim 8:5ea891c7d1a1 482 return InvalidParameterError;
IanBenzMaxim 7:9cd16581b578 483 }
IanBenzMaxim 7:9cd16581b578 484
IanBenzMaxim 7:9cd16581b578 485 uint_least8_t request[3 + Page::size];
IanBenzMaxim 7:9cd16581b578 486 request[0] = 0x3C;
IanBenzMaxim 7:9cd16581b578 487 request[1] = pageNum;
IanBenzMaxim 7:9cd16581b578 488 request[2] = (destinationSecret << 2) | masterSecret;
IanBenzMaxim 7:9cd16581b578 489 copy(partialSecret.begin(), partialSecret.end(), request + 3);
IanBenzMaxim 7:9cd16581b578 490 return runCommand(request, writeMemoryTimeMs + computeTimeMs);
IanBenzMaxim 7:9cd16581b578 491 }
IanBenzMaxim 7:9cd16581b578 492
IanBenzMaxim 8:5ea891c7d1a1 493 Result<void> DS28C40::generateEcc256KeyPair(KeySecret key) {
IanBenzMaxim 7:9cd16581b578 494 if (key == KeySecretS) {
IanBenzMaxim 8:5ea891c7d1a1 495 return InvalidParameterError;
IanBenzMaxim 7:9cd16581b578 496 }
IanBenzMaxim 7:9cd16581b578 497
IanBenzMaxim 7:9cd16581b578 498 const uint_least8_t request[] = {0xCB, key == KeySecretB};
IanBenzMaxim 7:9cd16581b578 499 return runCommand(request, generateEccKeyPairTimeMs);
IanBenzMaxim 7:9cd16581b578 500 }
IanBenzMaxim 7:9cd16581b578 501
IanBenzMaxim 8:5ea891c7d1a1 502 Result<void> DS28C40::readRng(span<uint_least8_t> data) const {
IanBenzMaxim 7:9cd16581b578 503 const span<uint_least8_t>::index_type maxDataSize = 64;
IanBenzMaxim 7:9cd16581b578 504 if ((data.size() < 1) || (data.size() > maxDataSize)) {
IanBenzMaxim 8:5ea891c7d1a1 505 return InvalidParameterError;
IanBenzMaxim 7:9cd16581b578 506 }
IanBenzMaxim 7:9cd16581b578 507
IanBenzMaxim 7:9cd16581b578 508 uint_least8_t buffer[1 + maxDataSize];
IanBenzMaxim 7:9cd16581b578 509 buffer[0] = readRngCmd;
IanBenzMaxim 7:9cd16581b578 510 buffer[1] = static_cast<uint_least8_t>(data.size() - 1);
IanBenzMaxim 8:5ea891c7d1a1 511 const Result<span<uint_least8_t> > response =
IanBenzMaxim 8:5ea891c7d1a1 512 runCommand(make_span(buffer, 2), trngGenerationTimeMs,
IanBenzMaxim 8:5ea891c7d1a1 513 make_span(buffer, 1 + data.size()));
IanBenzMaxim 8:5ea891c7d1a1 514 if (!response) {
IanBenzMaxim 8:5ea891c7d1a1 515 return response.error();
IanBenzMaxim 7:9cd16581b578 516 }
IanBenzMaxim 8:5ea891c7d1a1 517 copy(response.value().begin(), response.value().end(), data.begin());
IanBenzMaxim 8:5ea891c7d1a1 518 return none;
IanBenzMaxim 7:9cd16581b578 519 }
IanBenzMaxim 7:9cd16581b578 520
IanBenzMaxim 8:5ea891c7d1a1 521 Result<void> DS28C40::entropyHealthTest() const {
IanBenzMaxim 7:9cd16581b578 522 const uint_least8_t request[] = {readRngCmd, 0x80};
IanBenzMaxim 7:9cd16581b578 523 return runCommand(request, trngOnDemandCheckTimeMs);
IanBenzMaxim 7:9cd16581b578 524 }
IanBenzMaxim 7:9cd16581b578 525
IanBenzMaxim 8:5ea891c7d1a1 526 Result<span<uint_least8_t> >
IanBenzMaxim 8:5ea891c7d1a1 527 DS28C40::runCommand(span<const uint_least8_t> request, int delayTime,
IanBenzMaxim 8:5ea891c7d1a1 528 span<uint_least8_t> response) const {
IanBenzMaxim 8:5ea891c7d1a1 529 const Result<span<uint_least8_t> > responseOutput =
IanBenzMaxim 8:5ea891c7d1a1 530 doRunCommand(request, delayTime, response);
IanBenzMaxim 8:5ea891c7d1a1 531 if (!responseOutput) {
IanBenzMaxim 8:5ea891c7d1a1 532 return responseOutput;
IanBenzMaxim 7:9cd16581b578 533 }
IanBenzMaxim 8:5ea891c7d1a1 534 if (responseOutput.value().empty()) {
IanBenzMaxim 8:5ea891c7d1a1 535 return InvalidResponseError;
IanBenzMaxim 7:9cd16581b578 536 }
IanBenzMaxim 7:9cd16581b578 537 // Parse command result byte.
IanBenzMaxim 8:5ea891c7d1a1 538 switch (responseOutput.value().front()) {
IanBenzMaxim 7:9cd16581b578 539 case 0xAA:
IanBenzMaxim 7:9cd16581b578 540 // Success response.
IanBenzMaxim 7:9cd16581b578 541 break;
IanBenzMaxim 7:9cd16581b578 542
IanBenzMaxim 7:9cd16581b578 543 case 0x00:
IanBenzMaxim 8:5ea891c7d1a1 544 return AuthenticationError;
IanBenzMaxim 7:9cd16581b578 545
IanBenzMaxim 7:9cd16581b578 546 default:
IanBenzMaxim 8:5ea891c7d1a1 547 return error_code(responseOutput.value().front(), errorCategory());
IanBenzMaxim 7:9cd16581b578 548 }
IanBenzMaxim 8:5ea891c7d1a1 549 if (responseOutput.value().size() != response.size()) {
IanBenzMaxim 8:5ea891c7d1a1 550 return InvalidResponseError;
IanBenzMaxim 8:5ea891c7d1a1 551 }
IanBenzMaxim 8:5ea891c7d1a1 552 return responseOutput.value().subspan(1);
IanBenzMaxim 7:9cd16581b578 553 }
IanBenzMaxim 7:9cd16581b578 554
IanBenzMaxim 8:5ea891c7d1a1 555 Result<void> DS28C40::runCommand(span<const uint_least8_t> request,
IanBenzMaxim 8:5ea891c7d1a1 556 int delayTime) const {
IanBenzMaxim 7:9cd16581b578 557 uint_least8_t buffer;
IanBenzMaxim 8:5ea891c7d1a1 558 MaximInterfaceCore_TRY(runCommand(request, delayTime, make_span(&buffer, 1)));
IanBenzMaxim 8:5ea891c7d1a1 559 return none;
IanBenzMaxim 7:9cd16581b578 560 }
IanBenzMaxim 7:9cd16581b578 561
IanBenzMaxim 7:9cd16581b578 562 const error_category & DS28C40::errorCategory() {
IanBenzMaxim 7:9cd16581b578 563 static class : public error_category {
IanBenzMaxim 7:9cd16581b578 564 public:
IanBenzMaxim 11:3f3bf6bf5e6c 565 virtual const char * name() const {
IanBenzMaxim 11:3f3bf6bf5e6c 566 return "MaximInterfaceDevices.DS28C40";
IanBenzMaxim 11:3f3bf6bf5e6c 567 }
IanBenzMaxim 7:9cd16581b578 568
IanBenzMaxim 7:9cd16581b578 569 virtual std::string message(int condition) const {
IanBenzMaxim 7:9cd16581b578 570 switch (condition) {
IanBenzMaxim 7:9cd16581b578 571 case InvalidOperationError:
IanBenzMaxim 7:9cd16581b578 572 return "Invalid Operation Error";
IanBenzMaxim 7:9cd16581b578 573
IanBenzMaxim 7:9cd16581b578 574 case InvalidParameterError:
IanBenzMaxim 7:9cd16581b578 575 return "Invalid Parameter Error";
IanBenzMaxim 7:9cd16581b578 576
IanBenzMaxim 7:9cd16581b578 577 case InvalidSequenceError:
IanBenzMaxim 7:9cd16581b578 578 return "Invalid Sequence Error";
IanBenzMaxim 7:9cd16581b578 579
IanBenzMaxim 7:9cd16581b578 580 case AuthenticationError:
IanBenzMaxim 7:9cd16581b578 581 return "Authentication Error";
IanBenzMaxim 7:9cd16581b578 582
IanBenzMaxim 7:9cd16581b578 583 case InternalError:
IanBenzMaxim 7:9cd16581b578 584 return "Internal Error";
IanBenzMaxim 7:9cd16581b578 585
IanBenzMaxim 7:9cd16581b578 586 case DeviceDisabledError:
IanBenzMaxim 7:9cd16581b578 587 return "Device Disabled Error";
IanBenzMaxim 7:9cd16581b578 588
IanBenzMaxim 7:9cd16581b578 589 case InvalidResponseError:
IanBenzMaxim 7:9cd16581b578 590 return "Invalid Response Error";
IanBenzMaxim 12:7eb41621ba22 591
IanBenzMaxim 12:7eb41621ba22 592 case EntropyHealthTestError:
IanBenzMaxim 12:7eb41621ba22 593 return "Entropy Health Test Error";
IanBenzMaxim 7:9cd16581b578 594 }
IanBenzMaxim 7:9cd16581b578 595 return defaultErrorMessage(condition);
IanBenzMaxim 7:9cd16581b578 596 }
IanBenzMaxim 7:9cd16581b578 597 } instance;
IanBenzMaxim 7:9cd16581b578 598 return instance;
IanBenzMaxim 7:9cd16581b578 599 }
IanBenzMaxim 7:9cd16581b578 600
IanBenzMaxim 8:5ea891c7d1a1 601 Result<void> computeMultiblockHash(DS28C40 & device,
IanBenzMaxim 8:5ea891c7d1a1 602 span<const uint_least8_t> data) {
IanBenzMaxim 7:9cd16581b578 603 span<const uint_least8_t>::index_type dataIdx = 0;
IanBenzMaxim 8:5ea891c7d1a1 604 while (dataIdx < data.size()) {
IanBenzMaxim 7:9cd16581b578 605 const span<const uint_least8_t>::index_type remainingSize =
IanBenzMaxim 7:9cd16581b578 606 data.size() - dataIdx;
IanBenzMaxim 7:9cd16581b578 607 const span<const uint_least8_t>::index_type chunkSize =
IanBenzMaxim 7:9cd16581b578 608 std::min<span<const uint_least8_t>::index_type>(remainingSize, 64);
IanBenzMaxim 8:5ea891c7d1a1 609 MaximInterfaceCore_TRY(
IanBenzMaxim 7:9cd16581b578 610 device.computeMultiblockHash(dataIdx == 0, remainingSize == chunkSize,
IanBenzMaxim 8:5ea891c7d1a1 611 data.subspan(dataIdx, chunkSize)));
IanBenzMaxim 7:9cd16581b578 612 dataIdx += chunkSize;
IanBenzMaxim 7:9cd16581b578 613 }
IanBenzMaxim 8:5ea891c7d1a1 614 return none;
IanBenzMaxim 7:9cd16581b578 615 }
IanBenzMaxim 7:9cd16581b578 616
IanBenzMaxim 7:9cd16581b578 617 static void setAnonymous(RomId::span romId) {
IanBenzMaxim 7:9cd16581b578 618 std::fill(romId.begin(), romId.end(), 0xFF);
IanBenzMaxim 7:9cd16581b578 619 }
IanBenzMaxim 7:9cd16581b578 620
IanBenzMaxim 7:9cd16581b578 621 DS28C40::PageAuthenticationData &
IanBenzMaxim 7:9cd16581b578 622 DS28C40::PageAuthenticationData::setAnonymousRomId() {
IanBenzMaxim 7:9cd16581b578 623 setAnonymous(romId());
IanBenzMaxim 7:9cd16581b578 624 return *this;
IanBenzMaxim 7:9cd16581b578 625 }
IanBenzMaxim 7:9cd16581b578 626
IanBenzMaxim 7:9cd16581b578 627 DS28C40::ComputeSecretData::ComputeSecretData() : data() {
IanBenzMaxim 7:9cd16581b578 628 setPageNum(0);
IanBenzMaxim 7:9cd16581b578 629 setManId(ManId::array());
IanBenzMaxim 7:9cd16581b578 630 }
IanBenzMaxim 7:9cd16581b578 631
IanBenzMaxim 7:9cd16581b578 632 DS28C40::ComputeSecretData &
IanBenzMaxim 7:9cd16581b578 633 DS28C40::ComputeSecretData::setManId(ManId::const_span manId) {
IanBenzMaxim 7:9cd16581b578 634 ManId::array validatedManId;
IanBenzMaxim 7:9cd16581b578 635 copy(manId, make_span(validatedManId));
IanBenzMaxim 7:9cd16581b578 636 validatedManId[1] |= 0x80;
IanBenzMaxim 7:9cd16581b578 637 data.setManId(validatedManId);
IanBenzMaxim 7:9cd16581b578 638 return *this;
IanBenzMaxim 7:9cd16581b578 639 }
IanBenzMaxim 7:9cd16581b578 640
IanBenzMaxim 7:9cd16581b578 641 DS28C40::DecryptionHmacData & DS28C40::DecryptionHmacData::setAnonymousRomId() {
IanBenzMaxim 7:9cd16581b578 642 setAnonymous(romId());
IanBenzMaxim 7:9cd16581b578 643 return *this;
IanBenzMaxim 7:9cd16581b578 644 }
IanBenzMaxim 7:9cd16581b578 645
IanBenzMaxim 7:9cd16581b578 646 } // namespace MaximInterfaceDevices