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

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