Aleksandrs Gumenuks / MaximInterface_Extended

Dependents:   mbed_DS28EC20_GPIO

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers DS28E38.cpp Source File

DS28E38.cpp

00001 /*******************************************************************************
00002 * Copyright (C) 2017 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 <MaximInterface/Utilities/Algorithm.hpp>
00036 #include <MaximInterface/Utilities/Error.hpp>
00037 #include "DS28E38.hpp"
00038 
00039 namespace MaximInterface {
00040 
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 
00051 const int DS28E38::decrementCounterPage;
00052 const int DS28E38::publicKeyXPage;
00053 const int DS28E38::publicKeyYPage;
00054 const int DS28E38::privateKeyPage;
00055 const int DS28E38::memoryPages;
00056 
00057 error_code DS28E38::writeMemory(int pageNum, Page::const_span page) {
00058   if (pageNum < 0 || pageNum >= memoryPages) {
00059     return make_error_code(InvalidParameterError);
00060   }
00061 
00062   uint_least8_t command[2 + Page::size];
00063   command[0] = 0x96;
00064   command[1] = pageNum;
00065   copy(page.begin(), page.end(), command + 2);
00066   return runCommand(command, writeMemoryTimeMs);
00067 }
00068 
00069 error_code DS28E38::readMemory(int pageNum, Page::span page) {
00070   if (pageNum < 0 || pageNum >= memoryPages) {
00071     return make_error_code(InvalidParameterError);
00072   }
00073 
00074   uint_least8_t buffer[1 + Page::size];
00075   buffer[0] = 0x44;
00076   buffer[1] = pageNum;
00077   span<uint_least8_t> response(buffer);
00078   const error_code result =
00079       runCommand(make_span(buffer, 2), readMemoryTimeMs, response);
00080   if (!result) {
00081     copy(response.begin(), response.end(), page.begin());
00082   }
00083   return result;
00084 }
00085 
00086 error_code DS28E38::readStatus(bool entropyHealthTest, Status & status) {
00087   int delay = readMemoryTimeMs;
00088   if (entropyHealthTest) {
00089     delay += trngOnDemandCheckTimeMs;
00090   }
00091   uint_least8_t buffer[Status::PageProtectionList::csize + ManId::size +
00092                        Status::RomVersion::csize + 2];
00093   buffer[0] = 0xAA;
00094   buffer[1] = entropyHealthTest ? 0x01 : 0x00;
00095   span<uint_least8_t> response(buffer);
00096   error_code result = runCommand(make_span(buffer, 2), delay, response);
00097   if (!result) {
00098     span<uint_least8_t>::const_iterator responseIt = response.begin();
00099     for (Status::PageProtectionList::iterator it =
00100              status.pageProtection.begin();
00101          it != status.pageProtection.end(); ++it) {
00102       *it = *responseIt;
00103       ++responseIt;
00104     }
00105     span<uint_least8_t>::const_iterator responseItEnd =
00106         responseIt + status.manId.size();
00107     copy(responseIt, responseItEnd, status.manId.begin());
00108     responseIt = responseItEnd;
00109     responseItEnd = responseIt + status.romVersion.size();
00110     copy(responseIt, responseItEnd, status.romVersion.begin());
00111     responseIt = responseItEnd;
00112     switch (*responseIt) {
00113     case Status::TestNotPerformed:
00114     case Status::EntropyHealthy:
00115     case Status::EntropyNotHealthy:
00116       status.entropyHealthTestStatus =
00117           static_cast<Status::EntropyHealthTestStatus>(*responseIt);
00118       break;
00119 
00120     default:
00121       result = make_error_code(InvalidResponseError);
00122       break;
00123     }
00124   }
00125   return result;
00126 }
00127 
00128 error_code DS28E38::setPageProtection(int pageNum,
00129                                       const PageProtection & protection) {
00130   if (pageNum < 0 || pageNum >= memoryPages) {
00131     return make_error_code(InvalidParameterError);
00132   }
00133 
00134   int delay = writeStateTimeMs;
00135   if (pageNum == decrementCounterPage) {
00136     delay += writeMemoryTimeMs;
00137   }
00138   const uint_least8_t command[] = {
00139       0xC3, static_cast<uint_least8_t>(pageNum),
00140       static_cast<uint_least8_t>(protection.to_ulong())};
00141   return runCommand(command, delay);
00142 }
00143 
00144 error_code
00145 DS28E38::computeAndReadPageAuthentication(int pageNum, bool anonymous,
00146                                           Page::const_span challenge,
00147                                           Ecc256::Signature::span signature) {
00148   if (pageNum < 0 || pageNum >= memoryPages) {
00149     return make_error_code(InvalidParameterError);
00150   }
00151 
00152   const size_t commandSize = 2 + Page::size;
00153   const size_t responseSize = 1 + 2 * Ecc256::Scalar::size;
00154   uint_least8_t buffer[MaximInterface_MAX(commandSize, responseSize)];
00155   buffer[0] = 0xA5;
00156   buffer[1] = pageNum | (anonymous ? 0xE0 : 0x00);
00157   copy(challenge.begin(), challenge.end(), buffer + 2);
00158   span<uint_least8_t> response(buffer, responseSize);
00159   const error_code result = runCommand(make_span(buffer, commandSize),
00160                                        generateEcdsaSignatureTimeMs, response);
00161   if (!result) {
00162     span<uint_least8_t>::const_iterator begin = response.begin();
00163     span<uint_least8_t>::const_iterator end = begin + signature.s.size();
00164     copy(begin, end, signature.s.begin());
00165     begin = end;
00166     end = begin + signature.r.size();
00167     copy(begin, end, signature.r.begin());
00168   }
00169   return result;
00170 }
00171 
00172 error_code DS28E38::decrementCounter() {
00173   const uint_least8_t command = 0xC9;
00174   return runCommand(make_span(&command, 1), writeMemoryTimeMs);
00175 }
00176 
00177 error_code DS28E38::disableDevice() {
00178   const uint_least8_t command[] = {0x33, 0x9E, 0xA7, 0x49, 0xFB,
00179                                    0x10, 0x62, 0x0A, 0x26};
00180   return runCommand(command, writeStateTimeMs);
00181 }
00182 
00183 error_code DS28E38::generateEcc256KeyPair(bool privateKeyPuf,
00184                                           bool writeProtectEnable) {
00185   int delay = generateEccKeyPairTimeMs;
00186   if (writeProtectEnable) {
00187     delay += writeStateTimeMs;
00188   }
00189   uint_least8_t command[] = {0xCB, 0x00};
00190   if (privateKeyPuf) {
00191     command[1] |= 0x01;
00192   }
00193   if (writeProtectEnable) {
00194     command[1] |= 0x80;
00195   }
00196   return runCommand(command, delay);
00197 }
00198 
00199 error_code DS28E38::readRng(span<uint_least8_t> data) {
00200   const span<uint_least8_t>::index_type maxDataSize = 64;
00201   if ((data.size() < 1) || (data.size() > maxDataSize)) {
00202     return make_error_code(InvalidParameterError);
00203   }
00204 
00205   uint_least8_t buffer[1 + maxDataSize];
00206   buffer[0] = 0xD2;
00207   buffer[1] = data.size() - 1;
00208   span<uint_least8_t> response(buffer, 1 + data.size());
00209   const error_code result =
00210       runCommand(make_span(buffer, 2), trngGenerationTimeMs, response);
00211   if (!result) {
00212     copy(response.begin(), response.end(), data.begin());
00213   }
00214   return result;
00215 }
00216 
00217 error_code DS28E38::runCommand(span<const uint_least8_t> command, int delayTime,
00218                                span<uint_least8_t> & response) {
00219   const span<const uint_least8_t>::index_type responseInputSize =
00220       response.size();
00221   error_code result = doRunCommand(command, delayTime, response);
00222   if (result) {
00223     return result;
00224   }
00225   if (response.empty()) {
00226     return make_error_code(InvalidResponseError);
00227   }
00228   // Parse command result byte.
00229   switch (response[0]) {
00230   case 0xAA:
00231     // Success response.
00232     if (response.size() != responseInputSize) {
00233       result = make_error_code(InvalidResponseError);
00234     }
00235     break;
00236 
00237   case 0x00:
00238     result = make_error_code(InvalidResponseError);
00239     break;
00240 
00241   default:
00242     result.assign(response[0], errorCategory());
00243     break;
00244   }
00245   response = response.subspan(1);
00246   return result;
00247 }
00248 
00249 error_code DS28E38::runCommand(span<const uint_least8_t> command,
00250                                int delayTime) {
00251   uint_least8_t buffer;
00252   span<uint_least8_t> response(&buffer, 1);
00253   return runCommand(command, delayTime, response);
00254 }
00255 
00256 const error_category & DS28E38::errorCategory() {
00257   static class : public error_category {
00258   public:
00259     virtual const char * name() const { return "DS28E38"; }
00260 
00261     virtual std::string message(int condition) const {
00262       switch (condition) {
00263       case InvalidOperationError:
00264         return "Invalid Operation Error";
00265 
00266       case InvalidParameterError:
00267         return "Invalid Parameter Error";
00268 
00269       case InvalidSequenceError:
00270         return "Invalid Sequence Error";
00271 
00272       case InternalError:
00273         return "Internal Error";
00274 
00275       case DeviceDisabledError:
00276         return "Device Disabled Error";
00277 
00278       case InvalidResponseError:
00279         return "Invalid Response Error";
00280       }
00281       return defaultErrorMessage(condition);
00282     }
00283   } instance;
00284   return instance;
00285 }
00286 
00287 error_code readManId(DS28E38 & ds28e38, ManId::span manId) {
00288   DS28E38::Status status;
00289   const error_code result = ds28e38.readStatus(false, status);
00290   if (!result) {
00291     copy(make_span(status.manId), manId);
00292   }
00293   return result;
00294 }
00295 
00296 DS28E38::PageAuthenticationData &
00297 DS28E38::PageAuthenticationData::setAnonymousRomId() {
00298   std::fill(romId().begin(), romId().end(), 0xFF);
00299   return *this;
00300 }
00301 
00302 } // namespace MaximInterface