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

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