Device interface library for multiple platforms including Mbed.
Dependents: DeepCover Embedded Security in IoT MaximInterface MAXREFDES155#
DS28C39.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 "DS28C39.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 DS28C39::authorityPublicKeyXPage; 00053 const int DS28C39::authorityPublicKeyYPage; 00054 const int DS28C39::writePublicKeyXPage; 00055 const int DS28C39::writePublicKeyYPage; 00056 const int DS28C39::memoryPages; 00057 00058 Result<void> DS28C39::writeMemory(int pageNum, Page::const_span page) { 00059 if (pageNum < 0 || pageNum >= memoryPages) { 00060 return InvalidParameterError; 00061 } 00062 00063 uint_least8_t request[2 + Page::size]; 00064 request[0] = 0x96; 00065 request[1] = pageNum; 00066 copy(page.begin(), page.end(), request + 2); 00067 return runCommand(request, writeMemoryTimeMs); 00068 } 00069 00070 Result<DS28C39::Page::array> DS28C39::readMemory(int pageNum) const { 00071 if (pageNum < 0 || pageNum >= memoryPages) { 00072 return InvalidParameterError; 00073 } 00074 00075 uint_least8_t buffer[1 + Page::size]; 00076 buffer[0] = 0x44; 00077 buffer[1] = pageNum; 00078 const Result<span<uint_least8_t> > response = 00079 runCommand(make_span(buffer, 2), readMemoryTimeMs, buffer); 00080 if (!response) { 00081 return response.error(); 00082 } 00083 Page::array page; 00084 copy(response.value().begin(), response.value().end(), page.begin()); 00085 return page; 00086 } 00087 00088 Result<DS28C39::Status> DS28C39::readStatus(bool entropyHealthTest) const { 00089 int delay = readMemoryTimeMs; 00090 if (entropyHealthTest) { 00091 delay += trngOnDemandCheckTimeMs; 00092 } 00093 uint_least8_t buffer[Status::PageProtectionList::size + RomId::size + 00094 ManId::size + Status::RomVersion::size + 2]; 00095 buffer[0] = 0xAA; 00096 buffer[1] = entropyHealthTest ? 0x01 : 0x00; 00097 const Result<span<uint_least8_t> > response = 00098 runCommand(make_span(buffer, 2), delay, buffer); 00099 if (!response) { 00100 return response.error(); 00101 } 00102 Status status; 00103 span<uint_least8_t>::const_iterator responseIt = response.value().begin(); 00104 for (Status::PageProtectionList::array::iterator it = 00105 status.pageProtection.begin(); 00106 it != status.pageProtection.end(); ++it) { 00107 *it = *responseIt; 00108 ++responseIt; 00109 } 00110 span<uint_least8_t>::const_iterator responseItEnd = 00111 responseIt + status.romId.size(); 00112 copy(responseIt, responseItEnd, status.romId.begin()); 00113 responseIt = responseItEnd; 00114 responseItEnd = responseIt + status.manId.size(); 00115 copy(responseIt, responseItEnd, status.manId.begin()); 00116 responseIt = responseItEnd; 00117 responseItEnd = responseIt + status.romVersion.size(); 00118 copy(responseIt, responseItEnd, status.romVersion.begin()); 00119 responseIt = responseItEnd; 00120 switch (*responseIt) { 00121 case Status::TestNotPerformed: 00122 case Status::EntropyHealthy: 00123 case Status::EntropyNotHealthy: 00124 status.entropyHealthTestStatus = 00125 static_cast<Status::EntropyHealthTestStatus>(*responseIt); 00126 break; 00127 00128 default: 00129 return InvalidResponseError; 00130 } 00131 return status; 00132 } 00133 00134 Result<void> DS28C39::setPageProtection(int pageNum, 00135 const PageProtection & protection) { 00136 if (pageNum < 0 || pageNum >= memoryPages) { 00137 return InvalidParameterError; 00138 } 00139 00140 const uint_least8_t request[] = { 00141 0xC3, static_cast<uint_least8_t>(pageNum), 00142 static_cast<uint_least8_t>(protection.to_ulong())}; 00143 return runCommand(request, writeStateTimeMs); 00144 } 00145 00146 Result<Ecc256::Signature::array> 00147 DS28C39::computeAndReadPageAuthentication(int pageNum, bool anonymous, 00148 Page::const_span challenge) const { 00149 if (pageNum < 0 || pageNum >= memoryPages) { 00150 return InvalidParameterError; 00151 } 00152 00153 const size_t requestSize = 2 + Page::size; 00154 const size_t responseSize = 1 + 2 * Ecc256::Scalar::size; 00155 uint_least8_t buffer[MaximInterfaceCore_MAX(requestSize, responseSize)]; 00156 buffer[0] = 0xA5; 00157 buffer[1] = pageNum | (anonymous ? 0xE0 : 0x00); 00158 copy(challenge.begin(), challenge.end(), buffer + 2); 00159 const Result<span<uint_least8_t> > response = 00160 runCommand(make_span(buffer, requestSize), generateEcdsaSignatureTimeMs, 00161 make_span(buffer, responseSize)); 00162 if (!response) { 00163 return response.error(); 00164 } 00165 Ecc256::Signature::array signature; 00166 span<uint_least8_t>::const_iterator begin = response.value().begin(); 00167 span<uint_least8_t>::const_iterator end = begin + signature.s.size(); 00168 copy(begin, end, signature.s.begin()); 00169 begin = end; 00170 end = begin + signature.r.size(); 00171 copy(begin, end, signature.r.begin()); 00172 return signature; 00173 } 00174 00175 Result<void> DS28C39::disableDevice() { 00176 const uint_least8_t request[] = {0x33, 0x9E, 0xA7, 0x49, 0xFB, 00177 0x10, 0x62, 0x0A, 0x26}; 00178 return runCommand(request, writeStateTimeMs); 00179 } 00180 00181 Result<Ecc256::PublicKey::array> DS28C39::readDevicePublicKey() const { 00182 uint_least8_t buffer[1 + 2 * Ecc256::Scalar::size]; 00183 buffer[0] = 0xCB; 00184 const Result<span<uint_least8_t> > response = 00185 runCommand(make_span(buffer, 1), generateEccKeyPairTimeMs, buffer); 00186 if (!response) { 00187 return response.error(); 00188 } 00189 Ecc256::PublicKey::array devicePublicKey; 00190 span<uint_least8_t>::const_iterator begin = response.value().begin(); 00191 span<uint_least8_t>::const_iterator end = begin + devicePublicKey.x.size(); 00192 copy(begin, end, devicePublicKey.x.begin()); 00193 begin = end; 00194 end = begin + devicePublicKey.y.size(); 00195 copy(begin, end, devicePublicKey.y.begin()); 00196 return devicePublicKey; 00197 } 00198 00199 Result<void> DS28C39::readRng(span<uint_least8_t> data) const { 00200 const span<uint_least8_t>::index_type maxDataSize = 64; 00201 if ((data.size() < 1) || (data.size() > maxDataSize)) { 00202 return InvalidParameterError; 00203 } 00204 00205 uint_least8_t buffer[1 + maxDataSize]; 00206 buffer[0] = 0xD2; 00207 buffer[1] = static_cast<uint_least8_t>(data.size() - 1); 00208 const Result<span<uint_least8_t> > response = 00209 runCommand(make_span(buffer, 2), trngGenerationTimeMs, 00210 make_span(buffer, 1 + data.size())); 00211 if (!response) { 00212 return response.error(); 00213 } 00214 copy(response.value().begin(), response.value().end(), data.begin()); 00215 return none; 00216 } 00217 00218 Result<void> 00219 DS28C39::authenticatePublicKey(Ecc256::Signature::const_span certificate, 00220 span<const uint_least8_t> customization) { 00221 static const span<const uint_least8_t>::index_type maxCustomizationSize = 32; 00222 static const span<const uint_least8_t>::index_type signatureSize = 00223 2 * Ecc256::Scalar::size; 00224 00225 if (customization.size() < 1 || customization.size() > maxCustomizationSize) { 00226 return InvalidParameterError; 00227 } 00228 00229 uint_least8_t request[1 + signatureSize + maxCustomizationSize]; 00230 uint_least8_t * requestIt = request; 00231 *requestIt++ = 0x59; 00232 requestIt = copy(certificate.r.begin(), certificate.r.end(), requestIt); 00233 requestIt = copy(certificate.s.begin(), certificate.s.end(), requestIt); 00234 requestIt = copy(customization.begin(), customization.end(), requestIt); 00235 return runCommand(make_span(request, requestIt), verifyEcdsaSignatureTimeMs); 00236 } 00237 00238 Result<void> 00239 DS28C39::authenticatedWriteMemory(int pageNum, Page::const_span page, 00240 Ecc256::Signature::const_span signature) { 00241 if (pageNum < 0 || pageNum >= memoryPages) { 00242 return InvalidParameterError; 00243 } 00244 00245 uint_least8_t request[2 + Page::size + 2 * Ecc256::Scalar::size]; 00246 uint_least8_t * requestIt = request; 00247 *requestIt++ = 0x89; 00248 *requestIt++ = pageNum; 00249 requestIt = copy(page.begin(), page.end(), requestIt); 00250 requestIt = copy(signature.r.begin(), signature.r.end(), requestIt); 00251 copy(signature.s.begin(), signature.s.end(), requestIt); 00252 return runCommand(request, verifyEcdsaSignatureTimeMs + writeMemoryTimeMs); 00253 } 00254 00255 Result<span<uint_least8_t> > 00256 DS28C39::runCommand(span<const uint_least8_t> request, int delayTime, 00257 span<uint_least8_t> response) const { 00258 const Result<span<uint_least8_t> > responseOutput = 00259 doRunCommand(request, delayTime, response); 00260 if (!responseOutput) { 00261 return responseOutput; 00262 } 00263 if (responseOutput.value().empty()) { 00264 return InvalidResponseError; 00265 } 00266 // Parse command result byte. 00267 switch (responseOutput.value().front()) { 00268 case 0xAA: 00269 // Success response. 00270 break; 00271 00272 case 0x00: 00273 return AuthenticationError; 00274 00275 default: 00276 return error_code(responseOutput.value().front(), errorCategory()); 00277 } 00278 if (responseOutput.value().size() != response.size()) { 00279 return InvalidResponseError; 00280 } 00281 return responseOutput.value().subspan(1); 00282 } 00283 00284 Result<void> DS28C39::runCommand(span<const uint_least8_t> request, 00285 int delayTime) { 00286 uint_least8_t buffer; 00287 MaximInterfaceCore_TRY(runCommand(request, delayTime, make_span(&buffer, 1))); 00288 return none; 00289 } 00290 00291 const error_category & DS28C39::errorCategory() { 00292 static class : public error_category { 00293 public: 00294 virtual const char * name() const { 00295 return "MaximInterfaceDevices.DS28C39"; 00296 } 00297 00298 virtual std::string message(int condition) const { 00299 switch (condition) { 00300 case InvalidOperationError: 00301 return "Invalid Operation Error"; 00302 00303 case InvalidParameterError: 00304 return "Invalid Parameter Error"; 00305 00306 case InvalidSequenceError: 00307 return "Invalid Sequence Error"; 00308 00309 case InternalError: 00310 return "Internal Error"; 00311 00312 case DeviceDisabledError: 00313 return "Device Disabled Error"; 00314 00315 case AuthenticationError: 00316 return "Authentication Error"; 00317 00318 case InvalidResponseError: 00319 return "Invalid Response Error"; 00320 } 00321 return defaultErrorMessage(condition); 00322 } 00323 } instance; 00324 return instance; 00325 } 00326 00327 DS28C39::PageAuthenticationData & 00328 DS28C39::PageAuthenticationData::setAnonymousRomId() { 00329 std::fill(romId().begin(), romId().end(), 0xFF); 00330 return *this; 00331 } 00332 00333 } // namespace MaximInterfaceDevices
Generated on Tue Jul 12 2022 11:13:08 by 1.7.2