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.hpp Source File

DS28C16.hpp

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 #ifndef MaximInterfaceDevices_DS28C16_hpp
00034 #define MaximInterfaceDevices_DS28C16_hpp
00035 
00036 #include <stdint.h>
00037 #include <MaximInterfaceCore/Algorithm.hpp>
00038 #include <MaximInterfaceCore/array_span.hpp>
00039 #include <MaximInterfaceCore/FlagSet.hpp>
00040 #include <MaximInterfaceCore/RomId.hpp>
00041 #include <MaximInterfaceCore/RunCommand.hpp>
00042 #include <MaximInterfaceCore/system_error.hpp>
00043 #include "Config.hpp"
00044 
00045 namespace MaximInterfaceDevices {
00046 
00047 class DS28C16 {
00048 public:
00049   /// Device command results.
00050   enum ErrorValue {
00051     InvalidOperationError = 0x55,
00052     InvalidParameterError = 0x77,
00053     InvalidSequenceError = 0x33,
00054     InternalError = 0x22,
00055     DeviceDisabledError = 0x88,
00056     AuthenticationError = 0x100,
00057     InvalidResponseError ///< Command response does not match expected format.
00058   };
00059 
00060   /// @name Device memory pages
00061   /// @{
00062 
00063   static const int decrementCounterPage = 2;
00064   static const int masterSecretPage = 3;
00065 
00066   /// @}
00067 
00068   static const int memoryPages = 4;
00069 
00070   /// Holds a device memory page.
00071   typedef Core::array_span<uint_least8_t, 16> Page;
00072 
00073   /// Holds a Challenge, Partial Secret, or HMAC.
00074   typedef Core::array_span<uint_least8_t, 32> DoublePage;
00075 
00076   /// Holds a password used to disable the device.
00077   typedef Core::array_span<uint_least8_t, 2> DisableDevicePassword;
00078 
00079   // Format page authentication input data.
00080   class PageAuthenticationData;
00081 
00082   // Format compute secret input data.
00083   class ComputeSecretData;
00084 
00085   /// Page protection types.
00086   enum PageProtectionType {
00087     RP = 0x01, ///< Read protection.
00088     WP = 0x02, ///< Write protection.
00089     DC = 0x08  ///< Decrement counter.
00090   };
00091   typedef Core::FlagSet<PageProtectionType, 4> PageProtection;
00092 
00093   struct Status {
00094     typedef Core::array_span<PageProtection, memoryPages> PageProtectionList;
00095 
00096     PageProtectionList::array pageProtection;
00097     Core::RomId::array romId;
00098     uint_least8_t manId;
00099     uint_least8_t deviceVersion;
00100   };
00101 
00102   explicit DS28C16(const Core::RunCommand & runCommand)
00103       : doRunCommand(runCommand) {}
00104 
00105   void setRunCommand(const Core::RunCommand & runCommand) {
00106     doRunCommand = runCommand;
00107   }
00108 
00109   /// @brief Write memory with no protection.
00110   /// @param pageNum Number of page to write.
00111   /// @param page Data to write.
00112   MaximInterfaceDevices_EXPORT Core::Result<void>
00113   writeMemory(int pageNum, Page::const_span page);
00114 
00115   /// @brief Read memory with no protection.
00116   /// @param pageNum Number of page to read.
00117   /// @returns Data that was read.
00118   MaximInterfaceDevices_EXPORT Core::Result<Page::array>
00119   readMemory(int pageNum) const;
00120 
00121   /// @brief Reads the current status of the device.
00122   /// @returns Status that was read.
00123   MaximInterfaceDevices_EXPORT Core::Result<Status> readStatus() const;
00124 
00125   /// @brief Set the protection settings of a page.
00126   /// @param pageNum Number of page to write.
00127   /// @param protection Protection to write.
00128   MaximInterfaceDevices_EXPORT Core::Result<void>
00129   setPageProtection(int pageNum, const PageProtection & protection);
00130 
00131   /// @brief Compute and read page authentication with HMAC.
00132   /// @param pageNum Number of page to authenticate.
00133   /// @param anonymous True to disable use of ROM ID in computation.
00134   /// @param challenge Random challenge used to prevent replay attacks.
00135   /// @returns Computed page HMAC.
00136   MaximInterfaceDevices_EXPORT Core::Result<DoublePage::array>
00137   computeAndReadPageAuthentication(int pageNum, bool anonymous,
00138                                    DoublePage::const_span challenge) const;
00139 
00140   /// Decrement the decrement-only counter.
00141   MaximInterfaceDevices_EXPORT Core::Result<void> decrementCounter();
00142 
00143   /// Set password that will be subsequently used to disable the device.
00144   MaximInterfaceDevices_EXPORT Core::Result<void>
00145   setDisableDevicePassword(DisableDevicePassword::const_span password);
00146 
00147   /// @brief Lock-out all disable functionality for the device.
00148   /// @note Only allowed prior to setting password.
00149   MaximInterfaceDevices_EXPORT Core::Result<void> lockOutDisableDevice();
00150 
00151   /// Permanently disable the device.
00152   MaximInterfaceDevices_EXPORT Core::Result<void>
00153   disableDevice(DisableDevicePassword::const_span password);
00154 
00155   /// @brief
00156   /// Compute a derivative secret for authentication from the Master Secret.
00157   /// @param bindingDataPageNum Page number for Binding Data.
00158   /// @param constantBindingData
00159   /// Use constant Binding Data instead of Binding Data from the selected page.
00160   /// @param anonymous True to disable use of ROM ID in computation.
00161   /// @param partialSecret Partial secret to use in computation.
00162   /// @note
00163   /// This command should be executed prior to the
00164   /// Compute and Read Page Authentication command.
00165   MaximInterfaceDevices_EXPORT Core::Result<void>
00166   computeSecret(int bindingDataPageNum, bool constantBindingData,
00167                 bool anonymous, DoublePage::const_span partialSecret);
00168 
00169   MaximInterfaceDevices_EXPORT static const Core::error_category &
00170   errorCategory();
00171 
00172 protected:
00173   MaximInterfaceDevices_EXPORT Core::Result<Core::span<uint_least8_t> >
00174   runCommand(Core::span<const uint_least8_t> request, int delayTime,
00175              Core::span<uint_least8_t> response) const;
00176 
00177   MaximInterfaceDevices_EXPORT Core::Result<void>
00178   runCommand(Core::span<const uint_least8_t> request, int delayTime);
00179 
00180 private:
00181   enum DisableDeviceOperation {
00182     SetDisableDevicePassword = 0x0F,
00183     LockOutDisableDevice = 0x05,
00184     DisableDevice = 0x00
00185   };
00186 
00187   Core::Result<void> disableDevice(DisableDeviceOperation operation,
00188                                    DisableDevicePassword::const_span password);
00189 
00190   Core::RunCommand doRunCommand;
00191 };
00192 
00193 } // namespace MaximInterfaceDevices
00194 namespace MaximInterfaceCore {
00195 
00196 template <>
00197 struct is_error_code_enum<MaximInterfaceDevices::DS28C16::ErrorValue>
00198     : true_type {};
00199 
00200 } // namespace MaximInterfaceCore
00201 namespace MaximInterfaceDevices {
00202 
00203 inline Core::error_code make_error_code(DS28C16::ErrorValue e) {
00204   return Core::error_code(e, DS28C16::errorCategory());
00205 }
00206 
00207 /// Format page authentication input data.
00208 class DS28C16::PageAuthenticationData {
00209 public:
00210   typedef Core::array_span<uint_least8_t, Core::RomId::size + 2 * Page::size +
00211                                               DoublePage::size + 3>
00212       Result;
00213 
00214   PageAuthenticationData() : result_() {}
00215 
00216   /// Formatted data result.
00217   Result::const_span result() const { return result_; }
00218 
00219   /// @name ROM ID
00220   /// @brief 1-Wire ROM ID of the device.
00221   /// @{
00222 
00223   /// Get mutable ROM ID.
00224   Core::RomId::span romId() {
00225     return make_span(result_).subspan<romIdIdx, Core::RomId::size>();
00226   }
00227 
00228   /// Get immutable ROM ID.
00229   Core::RomId::const_span romId() const {
00230     return const_cast<PageAuthenticationData &>(*this).romId();
00231   }
00232 
00233   /// Set ROM ID.
00234   PageAuthenticationData & setRomId(Core::RomId::const_span romId) {
00235     copy(romId, this->romId());
00236     return *this;
00237   }
00238 
00239   /// Set ROM ID for use in anonymous mode.
00240   MaximInterfaceDevices_EXPORT PageAuthenticationData & setAnonymousRomId();
00241 
00242   /// @}
00243 
00244   /// @name Page
00245   /// @brief Data from a device memory page.
00246   /// @{
00247 
00248   /// Get mutable page.
00249   Page::span page() {
00250     return make_span(result_).subspan<pageIdx, Page::size>();
00251   }
00252 
00253   /// Get immutable page.
00254   Page::const_span page() const {
00255     return const_cast<PageAuthenticationData &>(*this).page();
00256   }
00257 
00258   /// Set page.
00259   PageAuthenticationData & setPage(Page::const_span page) {
00260     copy(page, this->page());
00261     return *this;
00262   }
00263 
00264   /// @}
00265 
00266   /// @name Challenge.
00267   /// @brief Random challenge used to prevent replay attacks.
00268   /// @{
00269 
00270   /// Get mutable Challenge.
00271   DoublePage::span challenge() {
00272     return make_span(result_).subspan<challengeIdx, DoublePage::size>();
00273   }
00274 
00275   /// Get immutable Challenge.
00276   DoublePage::const_span challenge() const {
00277     return const_cast<PageAuthenticationData &>(*this).challenge();
00278   }
00279 
00280   /// Set Challenge.
00281   PageAuthenticationData & setChallenge(DoublePage::const_span challenge) {
00282     copy(challenge, this->challenge());
00283     return *this;
00284   }
00285 
00286   /// @}
00287 
00288   /// @name Page number
00289   /// @brief Number of the page to use data from.
00290   /// @{
00291 
00292   /// Get page number.
00293   int pageNum() const { return result_[pageNumIdx]; }
00294 
00295   /// Set page number.
00296   PageAuthenticationData & setPageNum(int pageNum) {
00297     result_[pageNumIdx] = pageNum;
00298     return *this;
00299   }
00300 
00301   /// @}
00302 
00303   /// @name MAN ID
00304   /// @brief Manufacturer ID of the device.
00305   /// @{
00306 
00307   /// Get mutable MAN ID.
00308   uint_least8_t & manId() { return result_[manIdIdx]; }
00309 
00310   /// Get immutable MAN ID.
00311   uint_least8_t manId() const {
00312     return const_cast<PageAuthenticationData &>(*this).manId();
00313   }
00314 
00315   /// Set MAN ID.
00316   PageAuthenticationData & setManId(uint_least8_t manId) {
00317     this->manId() = manId;
00318     return *this;
00319   }
00320 
00321   /// @}
00322 
00323 private:
00324   static const size_t romIdIdx = 0;
00325   static const size_t pageIdx = romIdIdx + Core::RomId::size;
00326   static const size_t challengeIdx = pageIdx + 2 * Page::size;
00327   static const size_t pageNumIdx = challengeIdx + DoublePage::size;
00328   static const size_t manIdIdx = pageNumIdx + 1;
00329 
00330   Result::array result_;
00331 };
00332 
00333 /// Format compute secret input data.
00334 class DS28C16::ComputeSecretData {
00335 public:
00336   typedef PageAuthenticationData::Result Result;
00337 
00338   ComputeSecretData() : data() {
00339     data.setPageNum(0x80 | constantBindingDataMask);
00340   }
00341 
00342   /// Formatted data result.
00343   Result::const_span result() const { return data.result(); }
00344 
00345   /// @name ROM ID
00346   /// @brief 1-Wire ROM ID of the device.
00347   /// @{
00348 
00349   /// Get mutable ROM ID.
00350   Core::RomId::span romId() { return data.romId(); }
00351 
00352   /// Get immutable ROM ID.
00353   Core::RomId::const_span romId() const { return data.romId(); }
00354 
00355   /// Set ROM ID.
00356   ComputeSecretData & setRomId(Core::RomId::const_span romId) {
00357     data.setRomId(romId);
00358     return *this;
00359   }
00360 
00361   /// @}
00362 
00363   /// @name Binding Data
00364   /// @brief Binding Data contained in the selected page.
00365   /// @{
00366 
00367   /// Get mutable Binding Data.
00368   Page::span bindingData() { return data.page(); }
00369 
00370   /// Get immutable Binding Data.
00371   Page::const_span bindingData() const { return data.page(); }
00372 
00373   /// Set Binding Data.
00374   ComputeSecretData & setBindingData(Page::const_span bindingData) {
00375     data.setPage(bindingData);
00376     return *this;
00377   }
00378 
00379   /// @}
00380 
00381   /// @name Constant Binding Data
00382   /// @brief
00383   /// Use constant Binding Data instead of Binding Data from the selected page.
00384   /// @{
00385 
00386   /// Get Constant Binding Data.
00387   bool constantBindingData() const {
00388     return (data.pageNum() & constantBindingDataMask) ==
00389            constantBindingDataMask;
00390   }
00391 
00392   /// Set Constant Binding Data.
00393   MaximInterfaceDevices_EXPORT ComputeSecretData &
00394   setConstantBindingData(bool constantBindingData);
00395 
00396   /// @}
00397 
00398   /// @name Partial Secret
00399   /// @brief Partial Secret used for customization.
00400   /// @{
00401 
00402   /// Get mutable Partial Secret.
00403   DoublePage::span partialSecret() { return data.challenge(); }
00404 
00405   /// Get immutable Partial Secret.
00406   DoublePage::const_span partialSecret() const { return data.challenge(); }
00407 
00408   /// Set Partial Secret.
00409   ComputeSecretData & setPartialSecret(DoublePage::const_span partialSecret) {
00410     data.setChallenge(partialSecret);
00411     return *this;
00412   }
00413 
00414   /// @}
00415 
00416   /// @name Binding Data page number
00417   /// @{
00418 
00419   /// Get Binding Data page number.
00420   int bindingDataPageNum() const {
00421     return data.pageNum() & bindingDataPageNumMask;
00422   }
00423 
00424   /// Set Binding Data page number.
00425   ComputeSecretData & setBindingDataPageNum(int bindingDataPageNum) {
00426     data.setPageNum((bindingDataPageNum & bindingDataPageNumMask) |
00427                     (data.pageNum() & ~bindingDataPageNumMask));
00428     return *this;
00429   }
00430 
00431   /// @}
00432 
00433   /// @name MAN ID
00434   /// @brief Manufacturer ID of the device.
00435   /// @{
00436 
00437   /// Get mutable MAN ID.
00438   uint_least8_t & manId() { return data.manId(); }
00439 
00440   /// Get immutable MAN ID.
00441   uint_least8_t manId() const { return data.manId(); }
00442 
00443   /// Set MAN ID.
00444   ComputeSecretData & setManId(uint_least8_t manId) {
00445     data.setManId(manId);
00446     return *this;
00447   }
00448 
00449   /// @}
00450 
00451 private:
00452   static const unsigned int bindingDataPageNumMask = 0x03;
00453   static const unsigned int constantBindingDataMask = 0x04;
00454 
00455   PageAuthenticationData data;
00456 };
00457 
00458 } // namespace MaximInterfaceDevices
00459 
00460 #endif