Device interface library for multiple platforms including Mbed.
Dependents: DeepCover Embedded Security in IoT MaximInterface MAXREFDES155#
DS28E39.cpp
00001 /******************************************************************************* 00002 * Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. 00003 * 00004 * Permission is hereby granted, free of charge, to any person obtaining a 00005 * copy of this software and associated documentation files (the "Software"), 00006 * to deal in the Software without restriction, including without limitation 00007 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 00008 * and/or sell copies of the Software, and to permit persons to whom the 00009 * Software is furnished to do so, subject to the following conditions: 00010 * 00011 * The above copyright notice and this permission notice shall be included 00012 * in all copies or substantial portions of the Software. 00013 * 00014 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 00015 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 00016 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 00017 * IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES 00018 * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 00019 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 00020 * OTHER DEALINGS IN THE SOFTWARE. 00021 * 00022 * Except as contained in this notice, the name of Maxim Integrated 00023 * Products, Inc. shall not be used except as stated in the Maxim Integrated 00024 * Products, Inc. Branding Policy. 00025 * 00026 * The mere transfer of this software does not imply any licenses 00027 * of trade secrets, proprietary technology, copyrights, patents, 00028 * trademarks, maskwork rights, or any other form of intellectual 00029 * property whatsoever. Maxim Integrated Products, Inc. retains all 00030 * ownership rights. 00031 *******************************************************************************/ 00032 00033 #include <stddef.h> 00034 #include <algorithm> 00035 #include <MaximInterfaceCore/Error.hpp> 00036 #include "DS28E39.hpp" 00037 00038 namespace MaximInterfaceDevices { 00039 00040 using namespace Core; 00041 using std::copy; 00042 00043 static const int readMemoryTimeMs = 30; 00044 static const int writeMemoryTimeMs = 65; 00045 static const int writeStateTimeMs = 15; 00046 static const int generateEccKeyPairTimeMs = 200; 00047 static const int generateEcdsaSignatureTimeMs = 130; 00048 static const int trngOnDemandCheckTimeMs = 20; 00049 static const int trngGenerationTimeMs = 10; 00050 static const int verifyEcdsaSignatureTimeMs = 180; 00051 00052 const int DS28E39::decrementCounterPage; 00053 const int DS28E39::authorityPublicKeyXPage; 00054 const int DS28E39::authorityPublicKeyYPage; 00055 const int DS28E39::writePublicKeyXPage; 00056 const int DS28E39::writePublicKeyYPage; 00057 const int DS28E39::memoryPages; 00058 00059 Result<void> DS28E39::writeMemory(int pageNum, Page::const_span page) { 00060 if (pageNum < 0 || pageNum >= memoryPages) { 00061 return InvalidParameterError; 00062 } 00063 00064 uint_least8_t request[2 + Page::size]; 00065 request[0] = 0x96; 00066 request[1] = pageNum; 00067 copy(page.begin(), page.end(), request + 2); 00068 return runCommand(request, writeMemoryTimeMs); 00069 } 00070 00071 Result<DS28E39::Page::array> DS28E39::readMemory(int pageNum) const { 00072 if (pageNum < 0 || pageNum >= memoryPages) { 00073 return InvalidParameterError; 00074 } 00075 00076 uint_least8_t buffer[1 + Page::size]; 00077 buffer[0] = 0x44; 00078 buffer[1] = pageNum; 00079 const Result<span<uint_least8_t> > response = 00080 runCommand(make_span(buffer, 2), readMemoryTimeMs, buffer); 00081 if (!response) { 00082 return response.error(); 00083 } 00084 Page::array page; 00085 copy(response.value().begin(), response.value().end(), page.begin()); 00086 return page; 00087 } 00088 00089 Result<DS28E39::Status> DS28E39::readStatus(bool entropyHealthTest) const { 00090 int delay = readMemoryTimeMs; 00091 if (entropyHealthTest) { 00092 delay += trngOnDemandCheckTimeMs; 00093 } 00094 uint_least8_t buffer[Status::PageProtectionList::size + ManId::size + 00095 Status::RomVersion::size + 2]; 00096 buffer[0] = 0xAA; 00097 buffer[1] = entropyHealthTest ? 0x01 : 0x00; 00098 const Result<span<uint_least8_t> > response = 00099 runCommand(make_span(buffer, 2), delay, buffer); 00100 if (!response) { 00101 return response.error(); 00102 } 00103 Status status; 00104 span<uint_least8_t>::const_iterator responseIt = response.value().begin(); 00105 for (Status::PageProtectionList::array::iterator it = 00106 status.pageProtection.begin(); 00107 it != status.pageProtection.end(); ++it) { 00108 *it = *responseIt; 00109 ++responseIt; 00110 } 00111 span<uint_least8_t>::const_iterator responseItEnd = 00112 responseIt + status.manId.size(); 00113 copy(responseIt, responseItEnd, status.manId.begin()); 00114 responseIt = responseItEnd; 00115 responseItEnd = responseIt + status.romVersion.size(); 00116 copy(responseIt, responseItEnd, status.romVersion.begin()); 00117 responseIt = responseItEnd; 00118 switch (*responseIt) { 00119 case Status::TestNotPerformed: 00120 case Status::EntropyHealthy: 00121 case Status::EntropyNotHealthy: 00122 status.entropyHealthTestStatus = 00123 static_cast<Status::EntropyHealthTestStatus>(*responseIt); 00124 break; 00125 00126 default: 00127 return InvalidResponseError; 00128 } 00129 return status; 00130 } 00131 00132 Result<void> DS28E39::setPageProtection(int pageNum, 00133 const PageProtection & protection) { 00134 if (pageNum < 0 || pageNum >= memoryPages) { 00135 return InvalidParameterError; 00136 } 00137 00138 int delay = writeStateTimeMs; 00139 if (pageNum == decrementCounterPage) { 00140 delay += writeMemoryTimeMs; 00141 } 00142 const uint_least8_t request[] = { 00143 0xC3, static_cast<uint_least8_t>(pageNum), 00144 static_cast<uint_least8_t>(protection.to_ulong())}; 00145 return runCommand(request, delay); 00146 } 00147 00148 Result<Ecc256::Signature::array> 00149 DS28E39::computeAndReadPageAuthentication(int pageNum, bool anonymous, 00150 Page::const_span challenge) const { 00151 if (pageNum < 0 || pageNum >= memoryPages) { 00152 return InvalidParameterError; 00153 } 00154 00155 const size_t requestSize = 2 + Page::size; 00156 const size_t responseSize = 1 + 2 * Ecc256::Scalar::size; 00157 uint_least8_t buffer[MaximInterfaceCore_MAX(requestSize, responseSize)]; 00158 buffer[0] = 0xA5; 00159 buffer[1] = pageNum | (anonymous ? 0xE0 : 0x00); 00160 copy(challenge.begin(), challenge.end(), buffer + 2); 00161 const Result<span<uint_least8_t> > response = 00162 runCommand(make_span(buffer, requestSize), generateEcdsaSignatureTimeMs, 00163 make_span(buffer, responseSize)); 00164 if (!response) { 00165 return response.error(); 00166 } 00167 Ecc256::Signature::array signature; 00168 span<uint_least8_t>::const_iterator begin = response.value().begin(); 00169 span<uint_least8_t>::const_iterator end = begin + signature.s.size(); 00170 copy(begin, end, signature.s.begin()); 00171 begin = end; 00172 end = begin + signature.r.size(); 00173 copy(begin, end, signature.r.begin()); 00174 return signature; 00175 } 00176 00177 Result<void> DS28E39::decrementCounter() { 00178 const uint_least8_t request = 0xC9; 00179 return runCommand(make_span(&request, 1), writeMemoryTimeMs); 00180 } 00181 00182 Result<void> DS28E39::disableDevice() { 00183 const uint_least8_t request[] = {0x33, 0x9E, 0xA7, 0x49, 0xFB, 00184 0x10, 0x62, 0x0A, 0x26}; 00185 return runCommand(request, writeStateTimeMs); 00186 } 00187 00188 Result<Ecc256::PublicKey::array> DS28E39::readDevicePublicKey() const { 00189 uint_least8_t buffer[1 + 2 * Ecc256::Scalar::size]; 00190 buffer[0] = 0xCB; 00191 const Result<span<uint_least8_t> > response = 00192 runCommand(make_span(buffer, 1), generateEccKeyPairTimeMs, buffer); 00193 if (!response) { 00194 return response.error(); 00195 } 00196 Ecc256::PublicKey::array devicePublicKey; 00197 span<uint_least8_t>::const_iterator begin = response.value().begin(); 00198 span<uint_least8_t>::const_iterator end = begin + devicePublicKey.x.size(); 00199 copy(begin, end, devicePublicKey.x.begin()); 00200 begin = end; 00201 end = begin + devicePublicKey.y.size(); 00202 copy(begin, end, devicePublicKey.y.begin()); 00203 return devicePublicKey; 00204 } 00205 00206 Result<void> DS28E39::readRng(span<uint_least8_t> data) const { 00207 const span<uint_least8_t>::index_type maxDataSize = 64; 00208 if ((data.size() < 1) || (data.size() > maxDataSize)) { 00209 return InvalidParameterError; 00210 } 00211 00212 uint_least8_t buffer[1 + maxDataSize]; 00213 buffer[0] = 0xD2; 00214 buffer[1] = static_cast<uint_least8_t>(data.size() - 1); 00215 const Result<span<uint_least8_t> > response = 00216 runCommand(make_span(buffer, 2), trngGenerationTimeMs, 00217 make_span(buffer, 1 + data.size())); 00218 if (!response) { 00219 return response.error(); 00220 } 00221 copy(response.value().begin(), response.value().end(), data.begin()); 00222 return none; 00223 } 00224 00225 Result<void> 00226 DS28E39::authenticatePublicKey(Ecc256::Signature::const_span certificate, 00227 span<const uint_least8_t> customization) { 00228 static const span<const uint_least8_t>::index_type maxCustomizationSize = 32; 00229 static const span<const uint_least8_t>::index_type signatureSize = 00230 2 * Ecc256::Scalar::size; 00231 00232 if (customization.size() < 1 || customization.size() > maxCustomizationSize) { 00233 return InvalidParameterError; 00234 } 00235 00236 uint_least8_t request[1 + signatureSize + maxCustomizationSize]; 00237 uint_least8_t * requestIt = request; 00238 *requestIt++ = 0x59; 00239 requestIt = copy(certificate.r.begin(), certificate.r.end(), requestIt); 00240 requestIt = copy(certificate.s.begin(), certificate.s.end(), requestIt); 00241 requestIt = copy(customization.begin(), customization.end(), requestIt); 00242 return runCommand(make_span(request, requestIt), verifyEcdsaSignatureTimeMs); 00243 } 00244 00245 Result<void> 00246 DS28E39::authenticatedWriteMemory(int pageNum, Page::const_span page, 00247 Ecc256::Signature::const_span signature) { 00248 if (pageNum < 0 || pageNum >= memoryPages) { 00249 return InvalidParameterError; 00250 } 00251 00252 uint_least8_t request[2 + Page::size + 2 * Ecc256::Scalar::size]; 00253 uint_least8_t * requestIt = request; 00254 *requestIt++ = 0x89; 00255 *requestIt++ = pageNum; 00256 requestIt = copy(page.begin(), page.end(), requestIt); 00257 requestIt = copy(signature.r.begin(), signature.r.end(), requestIt); 00258 copy(signature.s.begin(), signature.s.end(), requestIt); 00259 return runCommand(request, verifyEcdsaSignatureTimeMs + writeMemoryTimeMs); 00260 } 00261 00262 Result<span<uint_least8_t> > 00263 DS28E39::runCommand(span<const uint_least8_t> request, int delayTime, 00264 span<uint_least8_t> response) const { 00265 const Result<span<uint_least8_t> > responseOutput = 00266 doRunCommand(request, delayTime, response); 00267 if (!responseOutput) { 00268 return responseOutput; 00269 } 00270 if (responseOutput.value().empty()) { 00271 return InvalidResponseError; 00272 } 00273 // Parse command result byte. 00274 switch (responseOutput.value().front()) { 00275 case 0xAA: 00276 // Success response. 00277 break; 00278 00279 case 0x00: 00280 return AuthenticationError; 00281 00282 default: 00283 return error_code(responseOutput.value().front(), errorCategory()); 00284 } 00285 if (responseOutput.value().size() != response.size()) { 00286 return InvalidResponseError; 00287 } 00288 return responseOutput.value().subspan(1); 00289 } 00290 00291 Result<void> DS28E39::runCommand(span<const uint_least8_t> request, 00292 int delayTime) { 00293 uint_least8_t buffer; 00294 MaximInterfaceCore_TRY(runCommand(request, delayTime, make_span(&buffer, 1))); 00295 return none; 00296 } 00297 00298 const error_category & DS28E39::errorCategory() { 00299 static class : public error_category { 00300 public: 00301 virtual const char * name() const { 00302 return "MaximInterfaceDevices.DS28E39"; 00303 } 00304 00305 virtual std::string message(int condition) const { 00306 switch (condition) { 00307 case InvalidOperationError: 00308 return "Invalid Operation Error"; 00309 00310 case InvalidParameterError: 00311 return "Invalid Parameter Error"; 00312 00313 case InvalidSequenceError: 00314 return "Invalid Sequence Error"; 00315 00316 case InternalError: 00317 return "Internal Error"; 00318 00319 case DeviceDisabledError: 00320 return "Device Disabled Error"; 00321 00322 case AuthenticationError: 00323 return "Authentication Error"; 00324 00325 case InvalidResponseError: 00326 return "Invalid Response Error"; 00327 } 00328 return defaultErrorMessage(condition); 00329 } 00330 } instance; 00331 return instance; 00332 } 00333 00334 DS28E39::PageAuthenticationData & 00335 DS28E39::PageAuthenticationData::setAnonymousRomId() { 00336 std::fill(romId().begin(), romId().end(), 0xFF); 00337 return *this; 00338 } 00339 00340 } // namespace MaximInterfaceDevices
Generated on Fri May 29 2020 21:20:48 by
