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

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