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

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