Device interface library for multiple platforms including Mbed.

Dependents:   DeepCover Embedded Security in IoT MaximInterface MAXREFDES155#

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers DS28E38.cpp Source File

DS28E38.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 "DS28E38.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 
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 Result<void> DS28E38::writeMemory(int pageNum, Page::const_span page) {
00058   if (pageNum < 0 || pageNum >= memoryPages) {
00059     return InvalidParameterError;
00060   }
00061 
00062   uint_least8_t request[2 + Page::size];
00063   request[0] = 0x96;
00064   request[1] = pageNum;
00065   copy(page.begin(), page.end(), request + 2);
00066   return runCommand(request, writeMemoryTimeMs);
00067 }
00068 
00069 Result<DS28E38::Page::array> DS28E38::readMemory(int pageNum) const {
00070   if (pageNum < 0 || pageNum >= memoryPages) {
00071     return InvalidParameterError;
00072   }
00073 
00074   uint_least8_t buffer[1 + Page::size];
00075   buffer[0] = 0x44;
00076   buffer[1] = pageNum;
00077   const Result<span<uint_least8_t> > response =
00078       runCommand(make_span(buffer, 2), readMemoryTimeMs, buffer);
00079   if (!response) {
00080     return response.error();
00081   }
00082   Page::array page;
00083   copy(response.value().begin(), response.value().end(), page.begin());
00084   return page;
00085 }
00086 
00087 Result<DS28E38::Status> DS28E38::readStatus(bool entropyHealthTest) const {
00088   int delay = readMemoryTimeMs;
00089   if (entropyHealthTest) {
00090     delay += trngOnDemandCheckTimeMs;
00091   }
00092   uint_least8_t buffer[Status::PageProtectionList::size + ManId::size +
00093                        Status::RomVersion::size + 2];
00094   buffer[0] = 0xAA;
00095   buffer[1] = entropyHealthTest ? 0x01 : 0x00;
00096   const Result<span<uint_least8_t> > response =
00097       runCommand(make_span(buffer, 2), delay, buffer);
00098   if (!response) {
00099     return response.error();
00100   }
00101   Status status;
00102   span<uint_least8_t>::const_iterator responseIt = response.value().begin();
00103   for (Status::PageProtectionList::array::iterator it =
00104            status.pageProtection.begin();
00105        it != status.pageProtection.end(); ++it) {
00106     *it = *responseIt;
00107     ++responseIt;
00108   }
00109   span<uint_least8_t>::const_iterator responseItEnd =
00110       responseIt + status.manId.size();
00111   copy(responseIt, responseItEnd, status.manId.begin());
00112   responseIt = responseItEnd;
00113   responseItEnd = responseIt + status.romVersion.size();
00114   copy(responseIt, responseItEnd, status.romVersion.begin());
00115   responseIt = responseItEnd;
00116   switch (*responseIt) {
00117   case Status::TestNotPerformed:
00118   case Status::EntropyHealthy:
00119   case Status::EntropyNotHealthy:
00120     status.entropyHealthTestStatus =
00121         static_cast<Status::EntropyHealthTestStatus>(*responseIt);
00122     break;
00123 
00124   default:
00125     return InvalidResponseError;
00126   }
00127   return status;
00128 }
00129 
00130 Result<void> DS28E38::setPageProtection(int pageNum,
00131                                         const PageProtection & protection) {
00132   if (pageNum < 0 || pageNum >= memoryPages) {
00133     return InvalidParameterError;
00134   }
00135 
00136   int delay = writeStateTimeMs;
00137   if (pageNum == decrementCounterPage) {
00138     delay += writeMemoryTimeMs;
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, delay);
00144 }
00145 
00146 Result<Ecc256::Signature::array>
00147 DS28E38::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> DS28E38::decrementCounter() {
00176   const uint_least8_t request = 0xC9;
00177   return runCommand(make_span(&request, 1), writeMemoryTimeMs);
00178 }
00179 
00180 Result<void> DS28E38::disableDevice() {
00181   const uint_least8_t request[] = {0x33, 0x9E, 0xA7, 0x49, 0xFB,
00182                                    0x10, 0x62, 0x0A, 0x26};
00183   return runCommand(request, writeStateTimeMs);
00184 }
00185 
00186 Result<void> DS28E38::generateEcc256KeyPair(bool privateKeyPuf,
00187                                             bool writeProtectEnable) {
00188   int delay = generateEccKeyPairTimeMs;
00189   if (writeProtectEnable) {
00190     delay += writeStateTimeMs;
00191   }
00192   uint_least8_t request[] = {0xCB, 0x00};
00193   if (privateKeyPuf) {
00194     request[1] |= 0x01;
00195   }
00196   if (writeProtectEnable) {
00197     request[1] |= 0x80;
00198   }
00199   return runCommand(request, delay);
00200 }
00201 
00202 Result<void> DS28E38::readRng(span<uint_least8_t> data) const {
00203   const span<uint_least8_t>::index_type maxDataSize = 64;
00204   if ((data.size() < 1) || (data.size() > maxDataSize)) {
00205     return InvalidParameterError;
00206   }
00207 
00208   uint_least8_t buffer[1 + maxDataSize];
00209   buffer[0] = 0xD2;
00210   buffer[1] = static_cast<uint_least8_t>(data.size() - 1);
00211   const Result<span<uint_least8_t> > response =
00212       runCommand(make_span(buffer, 2), trngGenerationTimeMs,
00213                  make_span(buffer, 1 + data.size()));
00214   if (!response) {
00215     return response.error();
00216   }
00217   copy(response.value().begin(), response.value().end(), data.begin());
00218   return none;
00219 }
00220 
00221 Result<span<uint_least8_t> >
00222 DS28E38::runCommand(span<const uint_least8_t> request, int delayTime,
00223                     span<uint_least8_t> response) const {
00224   const Result<span<uint_least8_t> > responseOutput =
00225       doRunCommand(request, delayTime, response);
00226   if (!responseOutput) {
00227     return responseOutput;
00228   }
00229   if (responseOutput.value().empty()) {
00230     return InvalidResponseError;
00231   }
00232   // Parse command result byte.
00233   switch (responseOutput.value().front()) {
00234   case 0xAA:
00235     // Success response.
00236     break;
00237 
00238   case 0x00:
00239     return InvalidResponseError;
00240 
00241   default:
00242     return error_code(responseOutput.value().front(), errorCategory());
00243   }
00244   if (responseOutput.value().size() != response.size()) {
00245     return InvalidResponseError;
00246   }
00247   return responseOutput.value().subspan(1);
00248 }
00249 
00250 Result<void> DS28E38::runCommand(span<const uint_least8_t> request,
00251                                  int delayTime) {
00252   uint_least8_t buffer;
00253   MaximInterfaceCore_TRY(runCommand(request, delayTime, make_span(&buffer, 1)));
00254   return none;
00255 }
00256 
00257 const error_category & DS28E38::errorCategory() {
00258   static class : public error_category {
00259   public:
00260     virtual const char * name() const {
00261       return "MaximInterfaceDevices.DS28E38";
00262     }
00263 
00264     virtual std::string message(int condition) const {
00265       switch (condition) {
00266       case InvalidOperationError:
00267         return "Invalid Operation Error";
00268 
00269       case InvalidParameterError:
00270         return "Invalid Parameter Error";
00271 
00272       case InvalidSequenceError:
00273         return "Invalid Sequence Error";
00274 
00275       case InternalError:
00276         return "Internal Error";
00277 
00278       case DeviceDisabledError:
00279         return "Device Disabled Error";
00280 
00281       case InvalidResponseError:
00282         return "Invalid Response Error";
00283       }
00284       return defaultErrorMessage(condition);
00285     }
00286   } instance;
00287   return instance;
00288 }
00289 
00290 DS28E38::PageAuthenticationData &
00291 DS28E38::PageAuthenticationData::setAnonymousRomId() {
00292   std::fill(romId().begin(), romId().end(), 0xFF);
00293   return *this;
00294 }
00295 
00296 } // namespace MaximInterfaceDevices