Maxim Integrated / Mbed OS MAXREFDES155#

Dependencies:   MaximInterface

DS28C36.hpp

Committer:
IanBenzMaxim
Date:
2017-04-06
Revision:
9:40dd19da90c3
Parent:
0:33d4e66780c0

File content as of revision 9:40dd19da90c3:

/*******************************************************************************
* 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 DS28C36_HPP
#define DS28C36_HPP

#include <vector>
#include "array.h"

namespace mbed { class I2C; }
namespace OneWire { class RomId; }

/// Interface to the DS28C36 authenticator.
class DS28C36
{
public:
    /// Device command results.
    enum CmdResult
    {
        Success = 0xAA,
        ProtectionError = 0x55,
        InvalidParameterError = 0x77,
        InvalidSequenceError = 0x33,
        InvalidEcdsaInputOrResultError = 0x22,
        AuthenticationError = 0x00,
        CommunicationError = 0xFF ///< Special code for I2C communication error.
    };
    
    /// 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
    };
    
    typedef OneWire::array<uint8_t, 32> Page; ///< Holds a device memory page.
    typedef OneWire::array<uint8_t, 32> HMAC; ///< Holds a computed HMAC.
    typedef std::vector<uint8_t> Buffer; ///< Holds a variable length device buffer.
    
    /// Holds a computed ECDSA signature.
    struct Signature
    {
        Page r;
        Page s;
    };
    
    /// Holds an encrypted device memory page.
    struct EncryptedPage
    {
        OneWire::array<uint8_t, 8> challenge;
        Page data;
    };
    
    /// Holds the protection status of a memory page.
    class PageProtection
    {       
    public:
        /// Page protection types.
        enum Protection
        {
            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.
         };
    
        explicit PageProtection(uint8_t status = 0x00) : m_status(status) { }
        
        /// @{
        /// Byte representation used by the device.
        uint8_t statusByte() const { return m_status; }
        void setStatusByte(uint8_t status) { m_status = status; }
        /// @}
        
        /// @{
        /// Get/set whether a protection type is enabled.
        bool protectionEnabled(Protection protection) const
        {
            return ((m_status & protection) == protection);
        }
        void setProtectionEnabled(Protection protection, bool enabled)
        {
            if (enabled) { m_status |= protection; }
            else { m_status &= ~protection; }
        }
        /// @}
        
        bool operator==(const PageProtection & rhs) const { return this->m_status == rhs.m_status; }
        bool operator!=(const PageProtection & rhs) const { return !operator==(rhs); }
        
    private:                             
        uint8_t m_status;
    };
    
    explicit DS28C36(mbed::I2C & i2c, uint8_t i2cAddress = 0x36) :
        m_i2c(i2c), m_i2cAddress(i2cAddress) { }

    /// Write memory with no protection.
    /// @param pageNum Number of page to write.
    /// @param page Data to write.
    CmdResult 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.
    CmdResult readMemory(int pageNum, Page & page);
    
    /// Write the temporary buffer.
    /// @param data Data to write.
    CmdResult writeBuffer(const Buffer & data);
    
    /// Read the temporary buffer.
    /// @param[out] data Data that was read.
    CmdResult readBuffer(Buffer & data);
    
    /// Read the protection settings of a page.
    /// @param pageNum Number of page to read.
    /// @param[out] protection Protection that was read.
    CmdResult readPageProtection(int pageNum, PageProtection & protection);
    
    /// Set the protection settings of a page.
    /// @param pageNum Number of page to write.
    /// @param protection Protection to write.
    CmdResult setPageProtection(int pageNum, const PageProtection & protection);
    
    /// Decrement the decrement-only counter.
    CmdResult decrementCounter();
    
    /// Read a block of random data from the RNG.
    /// @param numBytes Number of bytes to read from 1 to 64.
    /// @param[out] data Random data from RNG.
    CmdResult readRng(int numBytes, Buffer & data);
    
    /// 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.
    CmdResult 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.
    CmdResult computeAndReadEcdsaPageAuthentication(int pageNum, KeyNum keyNum, 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.
    CmdResult computeAndReadHmacPageAuthentication(int pageNum, SecretNum secretNum, HMAC & hmac);
    
    /// Write with SHA2 authentication.
    /// @param pageNum Number of page to write.
    /// @param secretNum Secret to use for authentication.
    /// @param page Data to write.
    CmdResult 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.
    CmdResult 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.
    CmdResult 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 thisis the last block being hashed.
    /// @param data Data block to hash. Length should be 64 bytes unless this is the last block.
    CmdResult computeMultiblockHash(bool firstBlock, bool lastBlock, const Buffer & 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.
    CmdResult verifyEcdsaSignature(KeyNum keyNum, HashType hashType, const 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.
    CmdResult authenticateEcdsaPublicKey(bool authWrites, bool ecdh, KeyNum keyNum, int csOffset, const Signature & signature);
    
    /// Write with ECDSA authentication.
    /// @param pageNum Number of page to write.
    /// @param page Data to write.
    CmdResult authenticatedEcdsaWriteMemory(int pageNum, const Page & page);
    
    /// Read the device ROM ID using the Read Memory command.
    /// @param ds28c36 Device to read.
    /// @param[out] romId Read ROM ID valid when operation is successful.
    static CmdResult readRomId(DS28C36 & ds28c36, OneWire::RomId & romId);

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;
    
    static CmdResult convertResultByte(uint8_t resultByte);

    CmdResult writeCommand(uint8_t command, const Buffer & parameters);
    CmdResult readResponse(Buffer & response);
    
private:
    enum AuthType
    {
        HmacWithSecretA = 0,
        HmacWithSecretB = 1,
        HmacWithSecretS = 2,
        EcdsaWithKeyA = 3,
        EcdsaWithKeyB = 4,
        EcdsaWithKeyC = 5
    };

    static const int numPages = 32;

    mbed::I2C & m_i2c;
    uint8_t m_i2cAddress;
    
    /// Compute any type of authentication on page.
    /// @param pageNum Number of page to authenticate.
    /// @param authType Method to use to compute authentication.
    /// @param[out] data Raw computed page authentication.
    CmdResult computeAndReadPageAuthentication(int pageNum, AuthType authType, Buffer & data);
};

#endif