Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: DeepCover Embedded Security in IoT MaximInterface MAXREFDES155#
Diff: Devices/DS28C36_DS2476.hpp
- Revision:
- 5:a8c83a2e6fa4
- Parent:
- 3:f818ea5172ed
- Child:
- 6:471901a04573
--- a/Devices/DS28C36_DS2476.hpp Fri Jan 19 10:25:02 2018 -0600
+++ b/Devices/DS28C36_DS2476.hpp Wed Jan 23 13:11:04 2019 -0600
@@ -1,411 +1,775 @@
-/*******************************************************************************
-* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved.
-*
-* Permission is hereby granted, free of charge, to any person obtaining a
-* copy of this software and associated documentation files (the "Software"),
-* to deal in the Software without restriction, including without limitation
-* the rights to use, copy, modify, merge, publish, distribute, sublicense,
-* and/or sell copies of the Software, and to permit persons to whom the
-* Software is furnished to do so, subject to the following conditions:
-*
-* The above copyright notice and this permission notice shall be included
-* in all copies or substantial portions of the Software.
-*
-* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-* IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES
-* OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
-* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-* OTHER DEALINGS IN THE SOFTWARE.
-*
-* Except as contained in this notice, the name of Maxim Integrated
-* Products, Inc. shall not be used except as stated in the Maxim Integrated
-* Products, Inc. Branding Policy.
-*
-* The mere transfer of this software does not imply any licenses
-* of trade secrets, proprietary technology, copyrights, patents,
-* trademarks, maskwork rights, or any other form of intellectual
-* property whatsoever. Maxim Integrated Products, Inc. retains all
-* ownership rights.
-*******************************************************************************/
-
-#ifndef MaximInterface_DS28C36_DS2476
-#define MaximInterface_DS28C36_DS2476
-
-#include <stddef.h>
-#include <stdint.h>
-#include <vector>
-#include <MaximInterface/Links/I2CMaster.hpp>
-#include <MaximInterface/Links/Sleep.hpp>
-#include <MaximInterface/Utilities/array.hpp>
-#include <MaximInterface/Utilities/Ecc256.hpp>
-#include <MaximInterface/Utilities/Export.h>
-#include <MaximInterface/Utilities/RomId.hpp>
-#include <MaximInterface/Utilities/ManId.hpp>
-#include <MaximInterface/Utilities/Sha256.hpp>
-#include <MaximInterface/Utilities/system_error.hpp>
-#include <MaximInterface/Utilities/FlagSet.hpp>
-
-namespace MaximInterface {
-
-/// Interface to the DS28C36 authenticator.
-class DS28C36 {
-public:
- /// Device command results.
- enum ErrorValue {
- ProtectionError = 0x55,
- InvalidParameterError = 0x77,
- InvalidSequenceError = 0x33,
- InvalidEcdsaInputOrResultError = 0x22,
- AuthenticationError = 0x100,
- InvalidResponseError = 0x101 ///< Response does not match expected format.
- };
-
- /// Device memory pages.
- enum PageNum {
- UserData0 = 0,
- UserData1,
- UserData2,
- UserData3,
- UserData4,
- UserData5,
- UserData6,
- UserData7,
- UserData8,
- UserData9,
- UserData10,
- UserData11,
- UserData12,
- UserData13,
- UserData14,
- UserData15,
- PublicKeyAX,
- PublicKeyAY,
- PublicKeyBX,
- PublicKeyBY,
- PublicKeyCX,
- PublicKeyCY,
- PrivateKeyA,
- PrivateKeyB,
- PrivateKeyC,
- SecretA,
- SecretB,
- DecrementCounter,
- RomOptions,
- GpioControl,
- PublicKeySX,
- PublicKeySY
- };
-
- /// Available keys for ECDSA operations.
- enum KeyNum { KeyNumA = 0, KeyNumB = 1, KeyNumC = 2, KeyNumS = 3 };
-
- /// Available secrets for HMAC operations.
- enum SecretNum { SecretNumA = 0, SecretNumB = 1, SecretNumS = 2 };
-
- /// Data hash type when verifying an ECDSA signature.
- enum HashType {
- HashInBuffer = 0, ///< Hash is loaded in the buffer.
- DataInBuffer = 1, ///< Compute hash from data loaded in the buffer.
- THASH = 2 ///< Use THASH from Compute Multiblock Hash command.
- };
-
- /// Available PIO states when verifying an ECDSA signature.
- enum PioState { Unchanged, Conducting, HighImpedance };
-
- /// Holds a device memory page.
- typedef array<uint_least8_t, 32> Page;
-
- /// Holds page authentication input data.
- typedef array<uint_least8_t, 75> PageAuthenticationData;
-
- /// Page protection types.
- enum PageProtectionType {
- RP = 0x01, ///< Read protection.
- WP = 0x02, ///< Write protection.
- EM = 0x04, ///< EPROM emulation mode.
- APH = 0x08, ///< Authentication write protection HMAC.
- EPH = 0x10, ///< Encryption and authenticated write protection HMAC.
- AUTH = 0x20, ///< Public Key C is set to authority public key.
- ECH = 0x40, ///< Encrypted read and write using shared key from ECDH.
- ECW = 0x80 ///< Authentication write protection ECDSA.
- };
- typedef FlagSet<PageProtectionType, 8> PageProtection;
-
- /// Holds an encrypted device memory page.
- struct EncryptedPage {
- typedef array<uint_least8_t, 8> Challenge;
-
- /// Total size of all elements in bytes.
- static const size_t size = Challenge::csize + Page::csize;
-
- Challenge challenge;
- Page data;
- };
-
- /// Number of memory pages on the device.
- static const int memoryPages = 32;
-
- DS28C36(const Sleep & sleep, I2CMaster & master, uint_least8_t address = 0x36)
- : sleep_(&sleep), master(&master), address_(address & 0xFE) {}
-
- void setSleep(const Sleep & sleep) { this->sleep_ = &sleep; }
- void setMaster(I2CMaster & master) { this->master = &master; }
- uint_least8_t address() const { return address_; }
- void setAddress(uint_least8_t address) { this->address_ = (address & 0xFE); }
-
- /// Write memory with no protection.
- /// @param pageNum Number of page to write.
- /// @param page Data to write.
- MaximInterface_EXPORT error_code writeMemory(int pageNum, const Page & page);
-
- /// Read memory with no protection.
- /// @param pageNum Number of page to read.
- /// @param[out] page Data that was read.
- MaximInterface_EXPORT error_code readMemory(int pageNum, Page & page);
-
- /// Write the temporary buffer.
- /// @param data Data to write.
- /// @param dataSize Size of data to write.
- MaximInterface_EXPORT error_code writeBuffer(const uint_least8_t * data,
- size_t dataSize);
-
- /// Read the temporary buffer.
- /// @param[out] data Data that was read.
- MaximInterface_EXPORT error_code
- readBuffer(std::vector<uint_least8_t> & data);
-
- /// Read the protection settings of a page.
- /// @param pageNum Number of page to read.
- /// @param[out] protection Protection that was read.
- MaximInterface_EXPORT error_code
- readPageProtection(int pageNum, PageProtection & protection);
-
- /// Set the protection settings of a page.
- /// @param pageNum Number of page to write.
- /// @param protection Protection to write.
- MaximInterface_EXPORT error_code
- setPageProtection(int pageNum, const PageProtection & protection);
-
- /// Decrement the decrement-only counter.
- MaximInterface_EXPORT error_code decrementCounter();
-
- /// Read a block of random data from the RNG.
- /// @param[out] data Buffer to hold random data from RNG.
- /// @param dataSize Number of bytes to read from 1 to 64 and length of data.
- MaximInterface_EXPORT error_code readRng(uint_least8_t * data,
- size_t dataSize);
-
- /// Read memory with encryption.
- /// @param pageNum Number of page to read from.
- /// @param secretNum Secret to use for encryption.
- /// @param[out] page Data that was read.
- MaximInterface_EXPORT error_code encryptedReadMemory(int pageNum,
- SecretNum secretNum,
- EncryptedPage & page);
-
- /// Compute and read page authentication with ECDSA.
- /// @param pageNum Number of page to authenticate.
- /// @param keyNum Private key to use for authentication.
- /// Key S cannot be used with this command.
- /// @param[out] signature Computed page signature.
- MaximInterface_EXPORT error_code computeAndReadEcdsaPageAuthentication(
- int pageNum, KeyNum keyNum, Ecc256::Signature & signature);
-
- /// Compute and read page authentication with HMAC.
- /// @param pageNum Number of page to authenticate.
- /// @param secretNum Secret to use for authentication.
- /// @param[out] hmac Computed page HMAC.
- MaximInterface_EXPORT error_code computeAndReadHmacPageAuthentication(
- int pageNum, SecretNum secretNum, Sha256::Hash & hmac);
-
- /// Write with SHA2 authentication.
- /// @param pageNum Number of page to write.
- /// @param secretNum Secret to use for authentication.
- /// @param page Data to write.
- MaximInterface_EXPORT error_code authenticatedSha2WriteMemory(
- int pageNum, SecretNum secretNum, const Page & page);
-
- /// Compute SHA2 secret and optionally lock.
- /// @param pageNum Number of page to use in computation.
- /// @param msecretNum Master secret to use in computation.
- /// @param dsecretNum Destination secret to receive the computation result.
- /// @param writeProtectEnable
- /// True to lock the destination secret against further writes.
- MaximInterface_EXPORT error_code
- computeAndLockSha2Secret(int pageNum, SecretNum msecretNum,
- SecretNum dsecretNum, bool writeProtectEnable);
-
- /// Generate a new ECDSA key pair.
- /// @param keyNum Key to generate. Key S cannot be used with this command.
- /// @param writeProtectEnable True to lock the key against further writes.
- MaximInterface_EXPORT error_code
- generateEcc256KeyPair(KeyNum keyNum, bool writeProtectEnable);
-
- /// Compute a hash over multiple blocks.
- /// @param firstBlock True if this is the first block being hashed.
- /// @param lastBlock True if this is the last block being hashed.
- /// @param data Data block to hash.
- /// @param dataSize Size of data to hash.
- /// Should be 64 bytes unless this is the last block.
- MaximInterface_EXPORT error_code
- computeMultiblockHash(bool firstBlock, bool lastBlock,
- const uint_least8_t * data, size_t dataSize);
-
- /// Verify ECDSA signature.
- /// @param keyNum Public key to use for verification.
- /// @param hashType Source of the data hash input.
- /// @param signature Signature to verify.
- /// @param pioa New state of PIOA if verification successful.
- /// @param piob New state of PIOB if verification successful.
- MaximInterface_EXPORT error_code verifyEcdsaSignature(
- KeyNum keyNum, HashType hashType, const Ecc256::Signature & signature,
- PioState pioa = Unchanged, PioState piob = Unchanged);
-
- /// Authenticate a public key for authenticated writes or encrypted reads with ECDH.
- /// @param authWrites True to select authentication for writes.
- /// @param ecdh True to select ECDH key exchange.
- /// @param keyNum Private key to use for ECDH key exchange.
- /// Key A or B can be selected.
- /// @param csOffset Certificate customization field ending offset in buffer.
- /// @param signature Signature to use for authentication of public key S.
- MaximInterface_EXPORT error_code
- authenticateEcdsaPublicKey(bool authWrites, bool ecdh, KeyNum keyNum,
- int csOffset, const Ecc256::Signature & signature);
-
- /// Write with ECDSA authentication.
- /// @param pageNum Number of page to write.
- /// @param page Data to write.
- MaximInterface_EXPORT error_code
- authenticatedEcdsaWriteMemory(int pageNum, const Page & page);
-
- /// Create data used by the Compute and Read Page Authentication command to
- /// generate a signature.
- MaximInterface_EXPORT static PageAuthenticationData
- createPageAuthenticationData(const RomId & romId, const Page & page,
- const Page & challenge, int pageNum,
- const ManId & manId);
-
- MaximInterface_EXPORT static const error_category & errorCategory();
-
-protected:
- // Timing constants.
- static const int generateEcdsaSignatureTimeMs = 50;
- static const int generateEccKeyPairTimeMs = 100;
- static const int verifyEsdsaSignatureOrComputeEcdhTimeMs = 150;
- static const int sha256ComputationTimeMs = 3;
- static const int readMemoryTimeMs = /*1*/ 2;
- static const int writeMemoryTimeMs = 15;
-
- error_code writeCommand(uint_least8_t command,
- const uint_least8_t * parameters,
- size_t parametersSize);
-
- error_code writeCommand(uint_least8_t command) {
- return writeCommand(command, NULL, 0);
- }
-
- error_code readVariableLengthResponse(uint_least8_t * response,
- size_t & responseSize);
-
- error_code readFixedLengthResponse(uint_least8_t * response,
- size_t responseSize);
-
- void sleep(int ms) const { (*sleep_)(ms); }
-
-private:
- enum AuthType {
- HmacWithSecretA = 0,
- HmacWithSecretB = 1,
- HmacWithSecretS = 2,
- EcdsaWithKeyA = 3,
- EcdsaWithKeyB = 4,
- EcdsaWithKeyC = 5
- };
-
- const Sleep * sleep_;
- I2CMaster * master;
- uint_least8_t address_;
-
- error_code computeAndReadPageAuthentication(int pageNum, AuthType authType);
-};
-
-/// Read the device ROM ID and MAN ID using the Read Memory command on the
-/// ROM Options page.
-/// @param[out] romId
-/// Read ROM ID valid when operation is successful. May be set to NULL.
-/// @param[out] manId
-/// Read MAN ID valid when operation is successful. May be set to NULL.
-MaximInterface_EXPORT error_code readRomIdAndManId(DS28C36 & ds28c36,
- RomId * romId,
- ManId * manId);
-
-/// Hash arbitrary length data with successive Compute Multiblock Hash commands.
-/// @param data Data to hash.
-/// @param dataSize Size of data to hash.
-MaximInterface_EXPORT error_code computeMultiblockHash(
- DS28C36 & ds28c36, const uint_least8_t * data, const size_t dataSize);
-
-/// Verify ECDSA signature.
-/// @param publicKey Public key to use for verification.
-/// @param data Data to verify.
-/// @param dataSize Size of data to verify.
-/// @param signature Signature to verify.
-/// @param pioa New state of PIOA if verification successful.
-/// @param piob New state of PIOB if verification successful.
-MaximInterface_EXPORT error_code verifyEcdsaSignature(
- DS28C36 & ds28c36, DS28C36::KeyNum publicKey, const uint_least8_t * data,
- size_t dataSize, const Ecc256::Signature & signature,
- DS28C36::PioState pioa = DS28C36::Unchanged,
- DS28C36::PioState piob = DS28C36::Unchanged);
-
-/// Verify ECDSA signature.
-/// @param publicKey
-/// Public key to use for verification which is loaded into Public Key S.
-/// @param data Data to verify.
-/// @param dataSize Size of data to verify.
-/// @param signature Signature to verify.
-/// @param pioa New state of PIOA if verification successful.
-/// @param piob New state of PIOB if verification successful.
-MaximInterface_EXPORT error_code
-verifyEcdsaSignature(DS28C36 & ds28c36, const Ecc256::PublicKey & publicKey,
- const uint_least8_t * data, size_t dataSize,
- const Ecc256::Signature & signature,
- DS28C36::PioState pioa = DS28C36::Unchanged,
- DS28C36::PioState piob = DS28C36::Unchanged);
-
-inline error_code make_error_code(DS28C36::ErrorValue e) {
- return error_code(e, DS28C36::errorCategory());
-}
-
-/// Interface to the DS2476 coprocessor.
-class DS2476 : public DS28C36 {
-public:
- DS2476(const Sleep & sleep, I2CMaster & master, uint_least8_t address = 0x76)
- : DS28C36(sleep, master, address) {}
-
- /// Generate ECDSA signature.
- /// @param keyNum Private key to use to create signature.
- /// Key S cannot be used with this command.
- /// @param[out] signature Computed signature.
- MaximInterface_EXPORT error_code
- generateEcdsaSignature(KeyNum keyNum, Ecc256::Signature & signature);
-
- /// Compute unique SHA2 secret.
- /// @param msecretNum Master secret to use in computation.
- MaximInterface_EXPORT error_code
- computeSha2UniqueSecret(SecretNum msecretNum);
-
- /// Compute SHA2 HMAC.
- /// @param[out] hmac Computed HMAC.
- MaximInterface_EXPORT error_code computeSha2Hmac(Sha256::Hash & hmac);
-};
-
-/// Enable coprocessor functionality on the DS2476 by writing to the
-/// ROM Options page.
-MaximInterface_EXPORT error_code enableCoprocessor(DS2476 & ds2476);
-
-} // namespace MaximInterface
-
-#endif
+/*******************************************************************************
+* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved.
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included
+* in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+* IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES
+* OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+* OTHER DEALINGS IN THE SOFTWARE.
+*
+* Except as contained in this notice, the name of Maxim Integrated
+* Products, Inc. shall not be used except as stated in the Maxim Integrated
+* Products, Inc. Branding Policy.
+*
+* The mere transfer of this software does not imply any licenses
+* of trade secrets, proprietary technology, copyrights, patents,
+* trademarks, maskwork rights, or any other form of intellectual
+* property whatsoever. Maxim Integrated Products, Inc. retains all
+* ownership rights.
+*******************************************************************************/
+
+#ifndef MaximInterface_DS28C36_DS2476
+#define MaximInterface_DS28C36_DS2476
+
+#include <stdint.h>
+#include <vector>
+#include <MaximInterface/Links/I2CMaster.hpp>
+#include <MaximInterface/Links/Sleep.hpp>
+#include <MaximInterface/Utilities/array_span.hpp>
+#include <MaximInterface/Utilities/Ecc256.hpp>
+#include <MaximInterface/Utilities/Export.h>
+#include <MaximInterface/Utilities/RomId.hpp>
+#include <MaximInterface/Utilities/ManId.hpp>
+#include <MaximInterface/Utilities/Sha256.hpp>
+#include <MaximInterface/Utilities/system_error.hpp>
+#include <MaximInterface/Utilities/FlagSet.hpp>
+
+namespace MaximInterface {
+
+/// Interface to the DS28C36 authenticator.
+class DS28C36 {
+public:
+ /// Device command results.
+ enum ErrorValue {
+ ProtectionError = 0x55,
+ InvalidParameterError = 0x77,
+ InvalidSequenceError = 0x33,
+ InvalidEcdsaInputOrResultError = 0x22,
+ AuthenticationError = 0x100,
+ InvalidResponseError = 0x101 ///< Response does not match expected format.
+ };
+
+ // Device memory pages.
+ static const int publicKeyAxPage = 16;
+ static const int publicKeyAyPage = 17;
+ static const int publicKeyBxPage = 18;
+ static const int publicKeyByPage = 19;
+ static const int publicKeyCxPage = 20;
+ static const int publicKeyCyPage = 21;
+ static const int privateKeyAPage = 22;
+ static const int privateKeyBPage = 23;
+ static const int privateKeyCPage = 24;
+ static const int secretAPage = 25;
+ static const int secretBPage = 26;
+ static const int decrementCounterPage = 27;
+ static const int romOptionsPage = 28;
+ static const int gpioControlPage = 29;
+ static const int publicKeySxPage = 30;
+ static const int publicKeySyPage = 31;
+
+ /// Number of memory pages on the device.
+ static const int memoryPages = 32;
+
+ /// Available keys for ECDSA operations.
+ enum KeyNum { KeyNumA = 0, KeyNumB = 1, KeyNumC = 2, KeyNumS = 3 };
+
+ /// Available secrets for HMAC operations.
+ enum SecretNum { SecretNumA = 0, SecretNumB = 1, SecretNumS = 2 };
+
+ /// Data hash type when verifying an ECDSA signature.
+ enum HashType {
+ HashInBuffer = 0, ///< Hash is loaded in the buffer.
+ DataInBuffer = 1, ///< Compute hash from data loaded in the buffer.
+ THASH = 2 ///< Use THASH from Compute Multiblock Hash command.
+ };
+
+ /// Available PIO states when verifying an ECDSA signature.
+ enum PioState { Unchanged, Conducting, HighImpedance };
+
+ /// Holds a device memory page.
+ typedef array_span<uint_least8_t, 32> Page;
+
+ /// Format page authentication input data.
+ class PageAuthenticationData;
+
+ /// Format authenticated write input data.
+ class WriteAuthenticationData;
+
+ /// Format compute secret input data.
+ class ComputeSecretData;
+
+ /// Format encryption or decryption HMAC input data.
+ class EncryptionHmacData;
+
+ /// Access fields in the ROM Options page. Can be used with writeMemory and
+ /// readMemory functions.
+ class RomOptions;
+
+ /// Access fields in the GPIO Control page. Can be used with writeMemory and
+ /// readMemory functions.
+ class GpioControl;
+
+ /// Page protection types.
+ enum PageProtectionType {
+ RP = 0x01, ///< Read protection.
+ WP = 0x02, ///< Write protection.
+ EM = 0x04, ///< EPROM emulation mode.
+ APH = 0x08, ///< Authentication write protection HMAC.
+ EPH = 0x10, ///< Encryption and authenticated write protection HMAC.
+ AUTH = 0x20, ///< Public Key C is set to authority public key.
+ ECH = 0x40, ///< Encrypted read and write using shared key from ECDH.
+ ECW = 0x80 ///< Authentication write protection ECDSA.
+ };
+ typedef FlagSet<PageProtectionType, 8> PageProtection;
+
+ /// Challenge for an encrypted device memory page.
+ typedef array_span<uint_least8_t, 8> EncryptionChallenge;
+
+ DS28C36(Sleep & sleep, I2CMaster & master, uint_least8_t address = 0x36)
+ : sleep_(&sleep), master(&master), address_(address & 0xFE) {}
+
+ void setSleep(Sleep & sleep) { sleep_ = &sleep; }
+
+ void setMaster(I2CMaster & master) { this->master = &master; }
+
+ uint_least8_t address() const { return address_; }
+
+ void setAddress(uint_least8_t address) { address_ = address & 0xFE; }
+
+ /// Write memory with no protection.
+ /// @param pageNum Number of page to write.
+ /// @param page Data to write.
+ MaximInterface_EXPORT error_code writeMemory(int pageNum,
+ Page::const_span page);
+
+ /// Read memory with no protection.
+ /// @param pageNum Number of page to read.
+ /// @param[out] page Data that was read.
+ MaximInterface_EXPORT error_code readMemory(int pageNum, Page::span page);
+
+ /// Write the temporary buffer.
+ /// @param data Data to write.
+ MaximInterface_EXPORT error_code writeBuffer(span<const uint_least8_t> data);
+
+ /// Read the temporary buffer.
+ /// @param[out] data Data that was read.
+ MaximInterface_EXPORT error_code
+ readBuffer(std::vector<uint_least8_t> & data);
+
+ /// Read the protection settings of a page.
+ /// @param pageNum Number of page to read.
+ /// @param[out] protection Protection that was read.
+ MaximInterface_EXPORT error_code
+ readPageProtection(int pageNum, PageProtection & protection);
+
+ /// Set the protection settings of a page.
+ /// @param pageNum Number of page to write.
+ /// @param protection Protection to write.
+ MaximInterface_EXPORT error_code
+ setPageProtection(int pageNum, const PageProtection & protection);
+
+ /// Decrement the decrement-only counter.
+ MaximInterface_EXPORT error_code decrementCounter();
+
+ /// Read a block of random data from the RNG.
+ /// @param[out] data Random data from RNG with length from 1 to 64.
+ MaximInterface_EXPORT error_code readRng(span<uint_least8_t> data);
+
+ /// Read memory with encryption.
+ /// @param pageNum Number of page to read from.
+ /// @param secretNum Secret to use for encryption.
+ /// @param[out] challenge Encryption challenge that was read.
+ /// @param[out] data Encrypted page data that was read.
+ MaximInterface_EXPORT error_code
+ encryptedReadMemory(int pageNum, SecretNum secretNum,
+ EncryptionChallenge::span challenge, Page::span data);
+
+ /// Compute and read page authentication with ECDSA.
+ /// @param pageNum Number of page to authenticate.
+ /// @param keyNum Private key to use for authentication.
+ /// Key S cannot be used with this command.
+ /// @param[out] signature Computed page signature.
+ MaximInterface_EXPORT error_code computeAndReadPageAuthentication(
+ int pageNum, KeyNum keyNum, Ecc256::Signature::span signature);
+
+ /// Compute and read page authentication with HMAC.
+ /// @param pageNum Number of page to authenticate.
+ /// @param secretNum Secret to use for authentication.
+ /// @param[out] hmac Computed page HMAC.
+ MaximInterface_EXPORT error_code computeAndReadPageAuthentication(
+ int pageNum, SecretNum secretNum, Sha256::Hash::span hmac);
+
+ /// Write with SHA2 authentication.
+ /// @param pageNum Number of page to write.
+ /// @param secretNum Secret to use for authentication.
+ /// @param page Data to write.
+ MaximInterface_EXPORT error_code authenticatedSha2WriteMemory(
+ int pageNum, SecretNum secretNum, Page::const_span page);
+
+ /// Compute SHA2 secret and optionally lock.
+ /// @param pageNum Number of page to use in computation.
+ /// @param msecretNum Master secret to use in computation.
+ /// @param dsecretNum Destination secret to receive the computation result.
+ /// @param writeProtectEnable
+ /// True to lock the destination secret against further writes.
+ MaximInterface_EXPORT error_code
+ computeAndLockSha2Secret(int pageNum, SecretNum msecretNum,
+ SecretNum dsecretNum, bool writeProtectEnable);
+
+ /// Generate a new ECDSA key pair.
+ /// @param keyNum Key to generate. Key S cannot be used with this command.
+ /// @param writeProtectEnable True to lock the key against further writes.
+ MaximInterface_EXPORT error_code
+ generateEcc256KeyPair(KeyNum keyNum, bool writeProtectEnable);
+
+ /// Compute a hash over multiple blocks.
+ /// @param firstBlock True if this is the first block being hashed.
+ /// @param lastBlock True if this is the last block being hashed.
+ /// @param data
+ /// Data block to hash. Should be 64 bytes unless this is the last block.
+ MaximInterface_EXPORT error_code computeMultiblockHash(
+ bool firstBlock, bool lastBlock, span<const uint_least8_t> data);
+
+ /// Verify ECDSA signature.
+ /// @param keyNum Public key to use for verification.
+ /// @param hashType Source of the data hash input.
+ /// @param signature Signature to verify.
+ /// @param pioa New state of PIOA if verification successful.
+ /// @param piob New state of PIOB if verification successful.
+ MaximInterface_EXPORT error_code verifyEcdsaSignature(
+ KeyNum keyNum, HashType hashType, Ecc256::Signature::const_span signature,
+ PioState pioa = Unchanged, PioState piob = Unchanged);
+
+ /// Authenticate a public key for authenticated writes or encrypted reads with ECDH.
+ /// @param authWrites True to select authentication for writes.
+ /// @param ecdh True to select ECDH key exchange.
+ /// @param keyNum Private key to use for ECDH key exchange.
+ /// Key A or B can be selected.
+ /// @param csOffset Certificate customization field ending offset in buffer.
+ /// @param signature Signature to use for authentication of public key S.
+ MaximInterface_EXPORT error_code authenticateEcdsaPublicKey(
+ bool authWrites, bool ecdh, KeyNum keyNum, int csOffset,
+ Ecc256::Signature::const_span signature);
+
+ /// Write with ECDSA authentication.
+ /// @param pageNum Number of page to write.
+ /// @param page Data to write.
+ MaximInterface_EXPORT error_code
+ authenticatedEcdsaWriteMemory(int pageNum, Page::const_span page);
+
+ MaximInterface_EXPORT static const error_category & errorCategory();
+
+protected:
+ // Timing constants.
+ static const int generateEcdsaSignatureTimeMs = 50;
+ static const int generateEccKeyPairTimeMs = 100;
+ static const int verifyEsdsaSignatureOrComputeEcdhTimeMs = 150;
+ static const int sha256ComputationTimeMs = 3;
+ static const int readMemoryTimeMs = /*1*/ 2;
+ static const int writeMemoryTimeMs = 15;
+
+ error_code writeCommand(uint_least8_t command,
+ span<const uint_least8_t> parameters);
+
+ error_code writeCommand(uint_least8_t command) {
+ return writeCommand(command, span<const uint_least8_t>());
+ }
+
+ error_code readVariableLengthResponse(span<uint_least8_t> & response);
+
+ error_code readFixedLengthResponse(span<uint_least8_t> response);
+
+ void sleep(int ms) const { sleep_->invoke(ms); }
+
+private:
+ enum AuthType {
+ HmacWithSecretA = 0,
+ HmacWithSecretB = 1,
+ HmacWithSecretS = 2,
+ EcdsaWithKeyA = 3,
+ EcdsaWithKeyB = 4,
+ EcdsaWithKeyC = 5
+ };
+
+ const Sleep * sleep_;
+ I2CMaster * master;
+ uint_least8_t address_;
+
+ error_code computeAndReadPageAuthentication(int pageNum, AuthType authType);
+};
+
+/// Interface to the DS2476 coprocessor.
+class DS2476 : public DS28C36 {
+public:
+ DS2476(Sleep & sleep, I2CMaster & master, uint_least8_t address = 0x76)
+ : DS28C36(sleep, master, address) {}
+
+ /// Generate ECDSA signature.
+ /// @param keyNum Private key to use to create signature.
+ /// Key S cannot be used with this command.
+ /// @param[out] signature Computed signature.
+ MaximInterface_EXPORT error_code
+ generateEcdsaSignature(KeyNum keyNum, Ecc256::Signature::span signature);
+
+ /// Compute unique SHA2 secret.
+ /// @param msecretNum Master secret to use in computation.
+ MaximInterface_EXPORT error_code
+ computeSha2UniqueSecret(SecretNum msecretNum);
+
+ /// Compute SHA2 HMAC.
+ /// @param[out] hmac Computed HMAC.
+ MaximInterface_EXPORT error_code computeSha2Hmac(Sha256::Hash::span hmac);
+};
+
+inline error_code make_error_code(DS28C36::ErrorValue e) {
+ return error_code(e, DS28C36::errorCategory());
+}
+
+/// Hash arbitrary length data with successive Compute Multiblock Hash commands.
+/// @param data Data to hash.
+MaximInterface_EXPORT error_code
+computeMultiblockHash(DS28C36 & ds28c36, span<const uint_least8_t> data);
+
+/// Verify ECDSA signature.
+/// @param publicKey Public key to use for verification.
+/// @param data Data to verify.
+/// @param signature Signature to verify.
+/// @param pioa New state of PIOA if verification successful.
+/// @param piob New state of PIOB if verification successful.
+MaximInterface_EXPORT error_code verifyEcdsaSignature(
+ DS28C36 & ds28c36, DS28C36::KeyNum publicKey,
+ span<const uint_least8_t> data, Ecc256::Signature::const_span signature,
+ DS28C36::PioState pioa = DS28C36::Unchanged,
+ DS28C36::PioState piob = DS28C36::Unchanged);
+
+/// Verify ECDSA signature.
+/// @param publicKey
+/// Public key to use for verification which is loaded into Public Key S.
+/// @param data Data to verify.
+/// @param signature Signature to verify.
+/// @param pioa New state of PIOA if verification successful.
+/// @param piob New state of PIOB if verification successful.
+MaximInterface_EXPORT error_code verifyEcdsaSignature(
+ DS28C36 & ds28c36, Ecc256::PublicKey::const_span publicKey,
+ span<const uint_least8_t> data, Ecc256::Signature::const_span signature,
+ DS28C36::PioState pioa = DS28C36::Unchanged,
+ DS28C36::PioState piob = DS28C36::Unchanged);
+
+/// Read the device ROM ID and MAN ID using the Read Memory command on the
+/// ROM Options page.
+/// @param[out] romId Read ROM ID valid when operation is successful.
+/// @param[out] manId Read MAN ID valid when operation is successful.
+MaximInterface_EXPORT error_code readRomIdAndManId(DS28C36 & ds28c36,
+ RomId::span romId,
+ ManId::span manId);
+
+/// Enable coprocessor functionality on the DS2476 by writing to the
+/// ROM Options page.
+MaximInterface_EXPORT error_code enableCoprocessor(DS2476 & ds2476);
+
+class DS28C36::PageAuthenticationData {
+public:
+ typedef array_span<uint_least8_t,
+ RomId::size + 2 * Page::size + 1 + ManId::size>
+ Result;
+
+ PageAuthenticationData() : result_() {}
+
+ /// Formatted data result.
+ Result::const_span result() const { return result_; }
+
+ /// @{
+ /// 1-Wire ROM ID of the device.
+ RomId::span romId() {
+ return make_span(result_).subspan<romIdIdx, RomId::size>();
+ }
+
+ RomId::const_span romId() const {
+ return const_cast<PageAuthenticationData &>(*this).romId();
+ }
+
+ PageAuthenticationData & setRomId(RomId::const_span romId) {
+ copy(romId, this->romId());
+ return *this;
+ }
+
+ MaximInterface_EXPORT PageAuthenticationData & setAnonymousRomId();
+ /// @}
+
+ /// @{
+ /// Data from a device memory page.
+ Page::span page() {
+ return make_span(result_).subspan<pageIdx, Page::size>();
+ }
+
+ Page::const_span page() const {
+ return const_cast<PageAuthenticationData &>(*this).page();
+ }
+
+ PageAuthenticationData & setPage(Page::const_span page) {
+ copy(page, this->page());
+ return *this;
+ }
+ /// @}
+
+ /// @{
+ /// Random challenge used to prevent replay attacks.
+ Page::span challenge() {
+ return make_span(result_).subspan<challengeIdx, Page::size>();
+ }
+
+ Page::const_span challenge() const {
+ return const_cast<PageAuthenticationData &>(*this).challenge();
+ }
+
+ PageAuthenticationData & setChallenge(Page::const_span challenge) {
+ copy(challenge, this->challenge());
+ return *this;
+ }
+ /// @}
+
+ /// @{
+ /// Number of the page to use data from.
+ int pageNum() const { return result_[pageNumIdx]; }
+
+ PageAuthenticationData & setPageNum(int pageNum) {
+ result_[pageNumIdx] = pageNum;
+ return *this;
+ }
+ /// @}
+
+ /// @{
+ /// Manufacturer ID of the device.
+ ManId::span manId() {
+ return make_span(result_).subspan<manIdIdx, ManId::size>();
+ }
+
+ ManId::const_span manId() const {
+ return const_cast<PageAuthenticationData &>(*this).manId();
+ }
+
+ PageAuthenticationData & setManId(ManId::const_span manId) {
+ copy(manId, this->manId());
+ return *this;
+ }
+ /// @}
+
+private:
+ typedef Result::span::index_type index;
+
+ static const index romIdIdx = 0;
+ static const index pageIdx = romIdIdx + RomId::size;
+ static const index challengeIdx = pageIdx + Page::size;
+ static const index pageNumIdx = challengeIdx + Page::size;
+ static const index manIdIdx = pageNumIdx + 1;
+
+ Result::array result_;
+};
+
+class DS28C36::WriteAuthenticationData {
+public:
+ typedef PageAuthenticationData::Result Result;
+
+ WriteAuthenticationData() : data() {}
+
+ /// Formatted data result.
+ Result::const_span result() const { return data.result(); }
+
+ /// @{
+ /// 1-Wire ROM ID of the device.
+ RomId::span romId() { return data.romId(); }
+
+ RomId::const_span romId() const { return data.romId(); }
+
+ WriteAuthenticationData & setRomId(RomId::const_span romId) {
+ data.setRomId(romId);
+ return *this;
+ }
+
+ WriteAuthenticationData & setAnonymousRomId() {
+ data.setAnonymousRomId();
+ return *this;
+ }
+ /// @}
+
+ /// @{
+ /// Existing data contained in the page.
+ Page::span oldPage() { return data.page(); }
+
+ Page::const_span oldPage() const { return data.page(); }
+
+ WriteAuthenticationData & setOldPage(Page::const_span oldPage) {
+ data.setPage(oldPage);
+ return *this;
+ }
+ /// @}
+
+ /// @{
+ /// New data to write to the page.
+ Page::span newPage() { return data.challenge(); }
+
+ Page::const_span newPage() const { return data.challenge(); }
+
+ WriteAuthenticationData & setNewPage(Page::const_span newPage) {
+ data.setChallenge(newPage);
+ return *this;
+ }
+ /// @}
+
+ /// @{
+ /// Page number for write operation.
+ int pageNum() const { return data.pageNum(); }
+
+ WriteAuthenticationData & setPageNum(int pageNum) {
+ data.setPageNum(pageNum);
+ return *this;
+ }
+ /// @}
+
+ /// @{
+ /// Manufacturer ID of the device.
+ ManId::span manId() { return data.manId(); }
+
+ ManId::const_span manId() const { return data.manId(); }
+
+ WriteAuthenticationData & setManId(ManId::const_span manId) {
+ data.setManId(manId);
+ return *this;
+ }
+ /// @}
+
+private:
+ PageAuthenticationData data;
+};
+
+class DS28C36::ComputeSecretData {
+public:
+ typedef PageAuthenticationData::Result Result;
+
+ ComputeSecretData() : data() {}
+
+ /// Formatted data result.
+ Result::const_span result() const { return data.result(); }
+
+ /// @{
+ /// 1-Wire ROM ID of the device.
+ RomId::span romId() { return data.romId(); }
+
+ RomId::const_span romId() const { return data.romId(); }
+
+ ComputeSecretData & setRomId(RomId::const_span romId) {
+ data.setRomId(romId);
+ return *this;
+ }
+ /// @}
+
+ /// @{
+ /// Binding Data contained in the selected page.
+ Page::span bindingData() { return data.page(); }
+
+ Page::const_span bindingData() const { return data.page(); }
+
+ ComputeSecretData & setBindingData(Page::const_span bindingData) {
+ data.setPage(bindingData);
+ return *this;
+ }
+ /// @}
+
+ /// @{
+ /// Partial Secret used for customization.
+ Page::span partialSecret() { return data.challenge(); }
+
+ Page::const_span partialSecret() const { return data.challenge(); }
+
+ ComputeSecretData & setPartialSecret(Page::const_span partialSecret) {
+ data.setChallenge(partialSecret);
+ return *this;
+ }
+ /// @}
+
+ /// @{
+ /// Page number for Binding Data.
+ int pageNum() const { return data.pageNum(); }
+
+ ComputeSecretData & setPageNum(int pageNum) {
+ data.setPageNum(pageNum);
+ return *this;
+ }
+ /// @}
+
+ /// @{
+ /// Manufacturer ID of the device.
+ ManId::span manId() { return data.manId(); }
+
+ ManId::const_span manId() const { return data.manId(); }
+
+ ComputeSecretData & setManId(ManId::const_span manId) {
+ data.setManId(manId);
+ return *this;
+ }
+ /// @}
+
+private:
+ PageAuthenticationData data;
+};
+
+class DS28C36::EncryptionHmacData {
+public:
+ typedef array_span<uint_least8_t,
+ EncryptionChallenge::size + RomId::size + 1 + ManId::size>
+ Result;
+
+ EncryptionHmacData() : result_() {}
+
+ /// Formatted data result.
+ Result::const_span result() const { return result_; }
+
+ /// @{
+ /// Random challenge used to prevent replay attacks.
+ EncryptionChallenge::span encryptionChallenge() {
+ return make_span(result_)
+ .subspan<encryptionChallengeIdx, EncryptionChallenge::size>();
+ }
+
+ EncryptionChallenge::const_span encryptionChallenge() const {
+ return const_cast<EncryptionHmacData &>(*this).encryptionChallenge();
+ }
+
+ EncryptionHmacData &
+ setEncryptionChallenge(EncryptionChallenge::const_span encryptionChallenge) {
+ copy(encryptionChallenge, this->encryptionChallenge());
+ return *this;
+ }
+ /// @}
+
+ /// @{
+ /// 1-Wire ROM ID of the device.
+ RomId::span romId() {
+ return make_span(result_).subspan<romIdIdx, RomId::size>();
+ }
+
+ RomId::const_span romId() const {
+ return const_cast<EncryptionHmacData &>(*this).romId();
+ }
+
+ EncryptionHmacData & setRomId(RomId::const_span romId) {
+ copy(romId, this->romId());
+ return *this;
+ }
+
+ MaximInterface_EXPORT EncryptionHmacData & setAnonymousRomId();
+ /// @}
+
+ /// @{
+ /// Number of the page to use data from.
+ int pageNum() const { return result_[pageNumIdx]; }
+
+ EncryptionHmacData & setPageNum(int pageNum) {
+ result_[pageNumIdx] = pageNum;
+ return *this;
+ }
+ /// @}
+
+ /// @{
+ /// Manufacturer ID of the device.
+ ManId::span manId() {
+ return make_span(result_).subspan<manIdIdx, ManId::size>();
+ }
+
+ ManId::const_span manId() const {
+ return const_cast<EncryptionHmacData &>(*this).manId();
+ }
+
+ EncryptionHmacData & setManId(ManId::const_span manId) {
+ copy(manId, this->manId());
+ return *this;
+ }
+ /// @}
+
+private:
+ typedef Result::span::index_type index;
+
+ static const index encryptionChallengeIdx = 0;
+ static const index romIdIdx =
+ encryptionChallengeIdx + EncryptionChallenge::size;
+ static const index pageNumIdx = romIdIdx + RomId::size;
+ static const index manIdIdx = pageNumIdx + 1;
+
+ Result::array result_;
+};
+
+class DS28C36::RomOptions {
+public:
+ operator Page::const_span() const { return page; }
+ operator Page::span() { return page; }
+
+ bool anonymous() const { return page[anonymousIdx] == anonymousValue; }
+
+ void setAnonymous(bool anonymous) {
+ page[anonymousIdx] = (anonymous ? anonymousValue : 0);
+ }
+
+ ManId::const_span manId() const {
+ return make_span(page).subspan<22, ManId::size>();
+ }
+
+ RomId::const_span romId() const {
+ return make_span(page).subspan<24, RomId::size>();
+ }
+
+private:
+ static const Page::array::size_type anonymousIdx = 1;
+ static const Page::array::value_type anonymousValue = 0xAA;
+
+ Page::array page;
+};
+
+class DS28C36::GpioControl {
+public:
+ operator Page::const_span() const { return page; }
+ operator Page::span() { return page; }
+
+ bool pioaConducting() const {
+ return page[pioaConductingIdx] == pioConductingValue;
+ }
+
+ void setPioaConducting(bool pioaConducting) {
+ page[pioaConductingIdx] = (pioaConducting ? pioConductingValue : 0x55);
+ }
+
+ bool piobConducting() const {
+ return page[piobConductingIdx] == pioConductingValue;
+ }
+
+ void setPiobConducting(bool piobConducting) {
+ page[piobConductingIdx] = (piobConducting ? pioConductingValue : 0x55);
+ }
+
+ bool pioaLevel() const { return page[2] == pioLevelValue; }
+
+ bool piobLevel() const { return page[3] == pioLevelValue; }
+
+private:
+ static const Page::array::size_type pioaConductingIdx = 0;
+ static const Page::array::size_type piobConductingIdx = 1;
+ static const Page::array::value_type pioConductingValue = 0xAA;
+ static const Page::array::value_type pioLevelValue = 0x55;
+
+ Page::array page;
+};
+
+} // namespace MaximInterface
+
+#endif