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 DS28E39.cpp Source File

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