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

DS28C16.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 "DS28C16.hpp"
00037 
00038 namespace MaximInterfaceDevices {
00039 
00040 using namespace Core;
00041 using std::copy;
00042 using std::fill;
00043 
00044 static const int readMemoryTimeMs = 5;
00045 static const int writeMemoryTimeMs = 60;
00046 static const int shortWriteMemoryTimeMs = 15;
00047 static const int computationTimeMs = 15;
00048 
00049 const int DS28C16::decrementCounterPage;
00050 const int DS28C16::masterSecretPage;
00051 const int DS28C16::memoryPages;
00052 
00053 Result<void> DS28C16::writeMemory(int pageNum, Page::const_span page) {
00054   if (pageNum < 0 || pageNum >= memoryPages) {
00055     return InvalidParameterError;
00056   }
00057 
00058   uint_least8_t request[2 + Page::size];
00059   request[0] = 0x96;
00060   request[1] = pageNum;
00061   copy(page.begin(), page.end(), request + 2);
00062   return runCommand(request, writeMemoryTimeMs);
00063 }
00064 
00065 Result<DS28C16::Page::array> DS28C16::readMemory(int pageNum) const {
00066   if (pageNum < 0 || pageNum >= memoryPages) {
00067     return InvalidParameterError;
00068   }
00069 
00070   uint_least8_t buffer[1 + Page::size * 2];
00071   buffer[0] = 0x44;
00072   buffer[1] = pageNum;
00073   Result<span<uint_least8_t> > response =
00074       runCommand(make_span(buffer, 2), readMemoryTimeMs, buffer);
00075   if (!response) {
00076     return response.error();
00077   }
00078   Page::array page;
00079   response.value() = response.value().first(Page::size);
00080   copy(response.value().begin(), response.value().end(), page.begin());
00081   return page;
00082 }
00083 
00084 Result<DS28C16::Status> DS28C16::readStatus() const {
00085   uint_least8_t buffer[1 + Status::PageProtectionList::size + RomId::size + 2];
00086   buffer[0] = 0xAA;
00087   const Result<span<uint_least8_t> > response =
00088       runCommand(make_span(buffer, 1), readMemoryTimeMs, buffer);
00089   if (!response) {
00090     return response.error();
00091   }
00092   Status status;
00093   span<uint_least8_t>::const_iterator responseIt = response.value().begin();
00094   for (Status::PageProtectionList::array::iterator it =
00095            status.pageProtection.begin();
00096        it != status.pageProtection.end(); ++it) {
00097     *it = *responseIt;
00098     ++responseIt;
00099   }
00100   const span<uint_least8_t>::const_iterator responseItEnd =
00101       responseIt + status.romId.size();
00102   copy(responseIt, responseItEnd, status.romId.begin());
00103   responseIt = responseItEnd;
00104   status.manId = *responseIt;
00105   ++responseIt;
00106   status.deviceVersion = *responseIt;
00107   return status;
00108 }
00109 
00110 Result<void> DS28C16::setPageProtection(int pageNum,
00111                                         const PageProtection & protection) {
00112   if (pageNum < 0 || pageNum >= memoryPages) {
00113     return InvalidParameterError;
00114   }
00115 
00116   const uint_least8_t request[] = {
00117       0xC3, static_cast<uint_least8_t>(pageNum),
00118       static_cast<uint_least8_t>(protection.to_ulong())};
00119   return runCommand(request, shortWriteMemoryTimeMs);
00120 }
00121 
00122 Result<DS28C16::DoublePage::array> DS28C16::computeAndReadPageAuthentication(
00123     int pageNum, bool anonymous, DoublePage::const_span challenge) const {
00124   if (pageNum < 0 || pageNum >= memoryPages) {
00125     return InvalidParameterError;
00126   }
00127 
00128   const size_t requestSize = 3 + DoublePage::size;
00129   const size_t responseSize = 1 + DoublePage::size;
00130   uint_least8_t buffer[MaximInterfaceCore_MAX(requestSize, responseSize)];
00131   buffer[0] = 0xA5;
00132   buffer[1] = pageNum;
00133   if (anonymous) {
00134     buffer[1] |= 0xE0;
00135   }
00136   buffer[2] = 0x02;
00137   copy(challenge.begin(), challenge.end(), buffer + 3);
00138   const Result<span<uint_least8_t> > response =
00139       runCommand(make_span(buffer, requestSize), computationTimeMs,
00140                  make_span(buffer, responseSize));
00141   if (!response) {
00142     return response.error();
00143   }
00144   DoublePage::array hmac;
00145   copy(response.value().begin(), response.value().end(), hmac.begin());
00146   return hmac;
00147 }
00148 
00149 Result<void> DS28C16::computeSecret(int bindingDataPageNum,
00150                                     bool constantBindingData, bool anonymous,
00151                                     DoublePage::const_span partialSecret) {
00152   if (bindingDataPageNum < 0 || bindingDataPageNum >= memoryPages) {
00153     return InvalidParameterError;
00154   }
00155 
00156   uint_least8_t request[3 + DoublePage::size];
00157   request[0] = 0x3C;
00158   request[1] = bindingDataPageNum;
00159   if (constantBindingData) {
00160     request[1] |= 0x04;
00161   }
00162   if (anonymous) {
00163     request[1] |= 0xE0;
00164   }
00165   request[2] = 0x08;
00166   copy(partialSecret.begin(), partialSecret.end(), request + 3);
00167   return runCommand(request, computationTimeMs);
00168 }
00169 
00170 Result<void> DS28C16::decrementCounter() {
00171   const uint_least8_t request = 0xC9;
00172   return runCommand(make_span(&request, 1), writeMemoryTimeMs);
00173 }
00174 
00175 Result<void> DS28C16::lockOutDisableDevice() {
00176   const DisableDevicePassword::array password = {0};
00177   return disableDevice(LockOutDisableDevice, password);
00178 }
00179 
00180 Result<void>
00181 DS28C16::setDisableDevicePassword(DisableDevicePassword::const_span password) {
00182   return disableDevice(SetDisableDevicePassword, password);
00183 }
00184 
00185 Result<void>
00186 DS28C16::disableDevice(DisableDevicePassword::const_span password) {
00187   return disableDevice(DisableDevice, password);
00188 }
00189 
00190 Result<void>
00191 DS28C16::disableDevice(DisableDeviceOperation operation,
00192                        DisableDevicePassword::const_span password) {
00193   const uint_least8_t request[] = {
00194       0x33,        static_cast<uint_least8_t>(operation),
00195       password[0], password[1],
00196       0x71,        0x35,
00197       0x0E,        0xAC,
00198       0x95,        0xF8};
00199   return runCommand(request, shortWriteMemoryTimeMs);
00200 }
00201 
00202 Result<span<uint_least8_t> >
00203 DS28C16::runCommand(span<const uint_least8_t> request, int delayTime,
00204                     span<uint_least8_t> response) const {
00205   const Result<span<uint_least8_t> > responseOutput =
00206       doRunCommand(request, delayTime, response);
00207   if (!responseOutput) {
00208     return responseOutput;
00209   }
00210   if (responseOutput.value().empty()) {
00211     return InvalidResponseError;
00212   }
00213   // Parse command result byte.
00214   switch (responseOutput.value().front()) {
00215   case 0xAA:
00216     // Success response.
00217     break;
00218 
00219   case 0x00:
00220     return AuthenticationError;
00221 
00222   default:
00223     return error_code(responseOutput.value().front(), errorCategory());
00224   }
00225   if (responseOutput.value().size() != response.size()) {
00226     return InvalidResponseError;
00227   }
00228   return responseOutput.value().subspan(1);
00229 }
00230 
00231 Result<void> DS28C16::runCommand(span<const uint_least8_t> request,
00232                                  int delayTime) {
00233   uint_least8_t buffer;
00234   MaximInterfaceCore_TRY(runCommand(request, delayTime, make_span(&buffer, 1)));
00235   return none;
00236 }
00237 
00238 const error_category & DS28C16::errorCategory() {
00239   static class : public error_category {
00240   public:
00241     virtual const char * name() const {
00242       return "MaximInterfaceDevices.DS28C16";
00243     }
00244 
00245     virtual std::string message(int condition) const {
00246       switch (condition) {
00247       case InvalidOperationError:
00248         return "Invalid Operation Error";
00249 
00250       case InvalidParameterError:
00251         return "Invalid Parameter Error";
00252 
00253       case InvalidSequenceError:
00254         return "Invalid Sequence Error";
00255 
00256       case InternalError:
00257         return "Internal Error";
00258 
00259       case DeviceDisabledError:
00260         return "Device Disabled Error";
00261 
00262       case AuthenticationError:
00263         return "Authentication Error";
00264 
00265       case InvalidResponseError:
00266         return "Invalid Response Error";
00267       }
00268       return defaultErrorMessage(condition);
00269     }
00270   } instance;
00271   return instance;
00272 }
00273 
00274 DS28C16::PageAuthenticationData &
00275 DS28C16::PageAuthenticationData::setAnonymousRomId() {
00276   fill(romId().begin(), romId().end(), 0xFF);
00277   return *this;
00278 }
00279 
00280 DS28C16::ComputeSecretData &
00281 DS28C16::ComputeSecretData::setConstantBindingData(bool constantBindingData) {
00282   if (constantBindingData) {
00283     data.setPageNum(data.pageNum() | constantBindingDataMask);
00284     fill(bindingData().begin(), bindingData().end(), 0);
00285   } else {
00286     data.setPageNum(data.pageNum() & ~constantBindingDataMask);
00287   }
00288   return *this;
00289 }
00290 
00291 } // namespace MaximInterfaceDevices