Device interface library for multiple platforms including Mbed.
Dependents: DeepCover Embedded Security in IoT MaximInterface MAXREFDES155#
Maxim Interface is a library framework focused on providing flexible and expressive hardware interfaces. Both communication interfaces such as I2C and 1-Wire and device interfaces such as DS18B20 are supported. Modern C++ concepts are used extensively while keeping compatibility with C++98/C++03 and requiring no external dependencies. The embedded-friendly design does not depend on exceptions or RTTI.
The full version of the project is hosted on GitLab: https://gitlab.com/iabenz/MaximInterface
Diff: MaximInterfaceDevices/DS28C40.cpp
- Revision:
- 8:5ea891c7d1a1
- Parent:
- 7:9cd16581b578
- Child:
- 11:3f3bf6bf5e6c
--- a/MaximInterfaceDevices/DS28C40.cpp Mon Jul 22 11:44:07 2019 -0500 +++ b/MaximInterfaceDevices/DS28C40.cpp Mon Sep 16 11:13:37 2019 -0500 @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (C) 2019 Maxim Integrated Products, Inc., All Rights Reserved. +* Copyright (C) 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"), @@ -39,6 +39,7 @@ using namespace Core; using std::copy; +using std::pair; static const int readMemoryTimeMs = 2; static const int writeMemoryTimeMs = 150; @@ -73,9 +74,9 @@ const int DS28C40::memoryPages; const int DS28C40::protectionBlocks; -error_code DS28C40::writeMemory(int pageNum, Page::const_span page) { +Result<void> DS28C40::writeMemory(int pageNum, Page::const_span page) { if (pageNum < 0 || pageNum >= memoryPages) { - return make_error_code(InvalidParameterError); + return InvalidParameterError; } uint_least8_t request[2 + Page::size]; @@ -85,29 +86,28 @@ return runCommand(request, writeMemoryTimeMs); } -error_code DS28C40::readMemory(int pageNum, Page::span page) { +Result<DS28C40::Page::array> DS28C40::readMemory(int pageNum) const { if (pageNum < 0 || pageNum >= memoryPages) { - return make_error_code(InvalidParameterError); + return InvalidParameterError; } uint_least8_t buffer[1 + Page::size]; buffer[0] = 0x44; buffer[1] = pageNum; - span<uint_least8_t> response(buffer); - const error_code result = - runCommand(make_span(buffer, 2), readMemoryTimeMs, response); - if (!result) { - copy(response.begin(), response.end(), page.begin()); + const Result<span<uint_least8_t> > response = + runCommand(make_span(buffer, 2), readMemoryTimeMs, buffer); + if (!response) { + return response.error(); } - return result; + Page::array page; + copy(response.value().begin(), response.value().end(), page.begin()); + return page; } -error_code -DS28C40::encryptedReadMemory(int pageNum, KeySecret secret, - EncryptionChallenge::span encryptionChallenge, - Page::span encryptedPage) { +Result<pair<DS28C40::EncryptionChallenge::array, DS28C40::Page::array> > +DS28C40::encryptedReadMemory(int pageNum, KeySecret secret) const { if (pageNum < 0 || pageNum >= memoryPages) { - return make_error_code(InvalidParameterError); + return InvalidParameterError; } const size_t requestSize = 3; @@ -116,27 +116,26 @@ buffer[0] = 0x4B; buffer[1] = pageNum; buffer[2] = secret; - span<uint_least8_t> response(buffer, responseSize); - const error_code result = - runCommand(make_span(buffer, requestSize), - readMemoryTimeMs + computeTimeMs, response); - if (!result) { - span<uint_least8_t>::const_iterator begin = response.begin(); - span<uint_least8_t>::const_iterator end = - begin + encryptionChallenge.size(); - copy(begin, end, encryptionChallenge.begin()); - begin = end; - end = begin + encryptedPage.size(); - copy(begin, end, encryptedPage.begin()); + const Result<span<uint_least8_t> > response = runCommand( + make_span(buffer, requestSize), readMemoryTimeMs + computeTimeMs, + make_span(buffer, responseSize)); + if (!response) { + return response.error(); } - return result; + pair<EncryptionChallenge::array, Page::array> data; + span<uint_least8_t>::const_iterator begin = response.value().begin(); + span<uint_least8_t>::const_iterator end = begin + data.first.size(); + copy(begin, end, data.first.begin()); + begin = end; + end = begin + data.second.size(); + copy(begin, end, data.second.begin()); + return data; } -error_code DS28C40::readBlockProtection(int blockNumber, - Optional<KeySecret> & keySecret, - BlockProtection & protection) { +Result<pair<Optional<DS28C40::KeySecret>, DS28C40::BlockProtection> > +DS28C40::readBlockProtection(int blockNumber) const { if (blockNumber < 0 || blockNumber >= protectionBlocks) { - return make_error_code(InvalidParameterError); + return InvalidParameterError; } const size_t requestSize = 2; @@ -144,39 +143,40 @@ uint_least8_t buffer[MaximInterfaceCore_MAX(requestSize, responseSize)]; buffer[0] = 0xAA; buffer[1] = blockNumber; - span<uint_least8_t> response(buffer, responseSize); - const error_code result = - runCommand(make_span(buffer, requestSize), readMemoryTimeMs, response); - if (result) { - return result; + const Result<span<uint_least8_t> > response = + runCommand(make_span(buffer, requestSize), readMemoryTimeMs, + make_span(buffer, responseSize)); + if (!response) { + return response.error(); } - if ((response[0] & 0x3F) != blockNumber) { - return make_error_code(InvalidResponseError); + if ((response.value()[0] & 0x3F) != blockNumber) { + return InvalidResponseError; } - switch (response[0] >> 6) { + pair<Optional<KeySecret>, BlockProtection> data; + switch (response.value()[0] >> 6) { case 0: - keySecret = none; + data.first = none; break; case 1: - keySecret = KeySecretA; + data.first = KeySecretA; break; case 2: - keySecret = KeySecretB; + data.first = KeySecretB; break; default: - return make_error_code(InvalidResponseError); + return InvalidResponseError; } - if ((response[1] & 0x20) != 0) { - return make_error_code(InvalidResponseError); + if ((response.value()[1] & 0x20) != 0) { + return InvalidResponseError; } - protection = response[1]; - return error_code(); + data.second = response.value()[1]; + return data; } -error_code DS28C40::setBlockProtection(int blockNum, KeySecret keySecret, - const BlockProtection & protection) { +Result<void> DS28C40::setBlockProtection(int blockNum, KeySecret keySecret, + const BlockProtection & protection) { if (blockNum < 0 || blockNum >= protectionBlocks || keySecret == KeySecretS) { - return make_error_code(InvalidParameterError); + return InvalidParameterError; } const uint_least8_t request[] = { @@ -187,12 +187,10 @@ return runCommand(request, writeStateTimeMs); } -error_code -DS28C40::computeAndReadPageAuthentication(int pageNum, KeySecret key, - Page::const_span challenge, - Ecc256::Signature::span signature) { +Result<Ecc256::Signature::array> DS28C40::computeAndReadEcdsaPageAuthentication( + int pageNum, KeySecret key, Page::const_span challenge) const { if (pageNum < 0 || pageNum >= memoryPages || key == KeySecretS) { - return make_error_code(InvalidParameterError); + return InvalidParameterError; } const size_t requestSize = 3 + Page::size; @@ -202,26 +200,26 @@ buffer[1] = pageNum; buffer[2] = key + 3; copy(challenge.begin(), challenge.end(), buffer + 3); - span<uint_least8_t> response(buffer, responseSize); - const error_code result = runCommand(make_span(buffer, requestSize), - generateEcdsaSignatureTimeMs, response); - if (!result) { - span<uint_least8_t>::const_iterator begin = response.begin(); - span<uint_least8_t>::const_iterator end = begin + signature.s.size(); - copy(begin, end, signature.s.begin()); - begin = end; - end = begin + signature.r.size(); - copy(begin, end, signature.r.begin()); + const Result<span<uint_least8_t> > response = + runCommand(make_span(buffer, requestSize), generateEcdsaSignatureTimeMs, + make_span(buffer, responseSize)); + if (!response) { + return response.error(); } - return result; + Ecc256::Signature::array signature; + span<uint_least8_t>::const_iterator begin = response.value().begin(); + span<uint_least8_t>::const_iterator end = begin + signature.s.size(); + copy(begin, end, signature.s.begin()); + begin = end; + end = begin + signature.r.size(); + copy(begin, end, signature.r.begin()); + return signature; } -error_code DS28C40::computeAndReadPageAuthentication(int pageNum, - KeySecret secret, - Page::const_span challenge, - Page::span hmac) { +Result<DS28C40::Page::array> DS28C40::computeAndReadSha256PageAuthentication( + int pageNum, KeySecret secret, Page::const_span challenge) const { if (pageNum < 0 || pageNum >= memoryPages) { - return make_error_code(InvalidParameterError); + return InvalidParameterError; } const size_t requestSize = 3 + Page::size; @@ -231,21 +229,23 @@ buffer[1] = pageNum; buffer[2] = secret; copy(challenge.begin(), challenge.end(), buffer + 3); - span<uint_least8_t> response(buffer, responseSize); - const error_code result = - runCommand(make_span(buffer, requestSize), computeTimeMs, response); - if (!result) { - copy(response.begin(), response.end(), hmac.begin()); + const Result<span<uint_least8_t> > response = + runCommand(make_span(buffer, requestSize), computeTimeMs, + make_span(buffer, responseSize)); + if (!response) { + return response.error(); } - return result; + Page::array hmac; + copy(response.value().begin(), response.value().end(), hmac.begin()); + return hmac; } -error_code DS28C40::computeMultiblockHash(bool firstBlock, bool lastBlock, - span<const uint_least8_t> data) { +Result<void> DS28C40::computeMultiblockHash(bool firstBlock, bool lastBlock, + span<const uint_least8_t> data) { const span<const uint_least8_t>::index_type maxDataSize = 64; if (data.size() < 1 || data.size() > maxDataSize) { - return make_error_code(InvalidParameterError); + return InvalidParameterError; } uint_least8_t buffer[2 + maxDataSize]; @@ -261,21 +261,21 @@ return runCommand(make_span(buffer, 2 + data.size()), computeTimeMs); } -error_code DS28C40::verifyEcdsaSignature( +Result<void> DS28C40::verifyEcdsaSignature( KeySecret key, bool authorityKey, GpioState gpioState, Ecc256::Signature::const_span signature, span<const uint_least8_t> data) { return verifyEcdsaSignature(key, authorityKey, DataInput, gpioState, signature, data); } -error_code DS28C40::verifyEcdsaSignature( +Result<void> DS28C40::verifyEcdsaSignature( KeySecret key, bool authorityKey, GpioState gpioState, Ecc256::Signature::const_span signature, Page::const_span hash) { return verifyEcdsaSignature(key, authorityKey, HashInput, gpioState, signature, hash); } -error_code +Result<void> DS28C40::verifyEcdsaSignature(KeySecret key, bool authorityKey, GpioState gpioState, Ecc256::Signature::const_span signature) { @@ -283,13 +283,13 @@ span<const uint_least8_t>()); } -error_code DS28C40::verifyEcdsaSignature( +Result<void> DS28C40::verifyEcdsaSignature( KeySecret key, bool authorityKey, HashType hashType, GpioState gpioState, Ecc256::Signature::const_span signature, span<const uint_least8_t> buffer) { const span<const uint_least8_t>::index_type maxBufferSize = 61; if (buffer.size() > maxBufferSize) { - return make_error_code(InvalidParameterError); + return InvalidParameterError; } uint_least8_t request[2 + 2 * Ecc256::Scalar::size + maxBufferSize]; @@ -317,7 +317,7 @@ } // else: Go to default case. default: - return make_error_code(InvalidParameterError); + return InvalidParameterError; } *requestIt |= hashType << 3; if (gpioState != Unchanged) { @@ -334,13 +334,13 @@ (hashType == DataInput ? computeTimeMs : 0)); } -error_code DS28C40::authenticateEcdsaPublicKey( +Result<void> DS28C40::authenticateEcdsaPublicKey( KeySecret key, Ecc256::Signature::const_span cert, span<const uint_least8_t> certCustomization) { return authenticateEcdsaPublicKey(key, true, cert, certCustomization, NULL); } -error_code DS28C40::authenticateEcdsaPublicKey( +Result<void> DS28C40::authenticateEcdsaPublicKey( KeySecret key, bool authWrites, Ecc256::Signature::const_span cert, span<const uint_least8_t> certCustomization, span<const uint_least8_t> ecdhCustomization) { @@ -348,7 +348,7 @@ &ecdhCustomization); } -error_code DS28C40::authenticateEcdsaPublicKey( +Result<void> DS28C40::authenticateEcdsaPublicKey( KeySecret key, bool authWrites, Ecc256::Signature::const_span cert, span<const uint_least8_t> certCustomization, const span<const uint_least8_t> * ecdhCustomization) { @@ -364,11 +364,11 @@ ecdhCustomization->size() <= maxEcdhCustomizationSize && certCustomization.size() + ecdhCustomization->size() <= maxTotalCustomizationSize)))) { - return make_error_code(InvalidParameterError); + return InvalidParameterError; } if (key == KeySecretS) { - return make_error_code(InvalidParameterError); + return InvalidParameterError; } uint_least8_t @@ -395,14 +395,14 @@ return runCommand(make_span(request, requestIt), delay); } -error_code DS28C40::authenticatedEcdsaWriteMemory( +Result<void> DS28C40::authenticatedEcdsaWriteMemory( int pageNum, bool useKeyS, Page::const_span newPageData, Ecc256::Signature::const_span signature) { return authenticatedEcdsaWriteMemory(pageNum, useKeyS, newPageData, signature, NULL); } -error_code DS28C40::authenticatedEcdsaWriteMemory( +Result<void> DS28C40::authenticatedEcdsaWriteMemory( int pageNum, bool useKeyS, Page::const_span newPageData, Ecc256::Signature::const_span signature, EncryptionChallenge::const_span challenge) { @@ -410,12 +410,12 @@ &challenge); } -error_code DS28C40::authenticatedEcdsaWriteMemory( +Result<void> DS28C40::authenticatedEcdsaWriteMemory( int pageNum, bool useKeyS, Page::const_span newPageData, Ecc256::Signature::const_span signature, const EncryptionChallenge::const_span * challenge) { if (pageNum < 0 || pageNum >= memoryPages) { - return make_error_code(InvalidParameterError); + return InvalidParameterError; } uint_least8_t request[2 + Page::size + 2 * Ecc256::Scalar::size + @@ -437,25 +437,26 @@ return runCommand(make_span(request, requestIt), delay); } -error_code DS28C40::authenticatedSha256WriteMemory(int pageNum, bool useSecretS, - Page::const_span newPageData, - Page::const_span hmac) { +Result<void> +DS28C40::authenticatedSha256WriteMemory(int pageNum, bool useSecretS, + Page::const_span newPageData, + Page::const_span hmac) { return authenticatedSha256WriteMemory(pageNum, useSecretS, newPageData, hmac, NULL); } -error_code DS28C40::authenticatedSha256WriteMemory( +Result<void> DS28C40::authenticatedSha256WriteMemory( int pageNum, bool useSecretS, Page::const_span newPageData, Page::const_span hmac, EncryptionChallenge::const_span challenge) { return authenticatedSha256WriteMemory(pageNum, useSecretS, newPageData, hmac, &challenge); } -error_code DS28C40::authenticatedSha256WriteMemory( +Result<void> DS28C40::authenticatedSha256WriteMemory( int pageNum, bool useSecretS, Page::const_span newPageData, Page::const_span hmac, const EncryptionChallenge::const_span * challenge) { if (pageNum < 0 || pageNum >= memoryPages) { - return make_error_code(InvalidParameterError); + return InvalidParameterError; } uint_least8_t request[3 + 2 * Page::size + EncryptionChallenge::size]; @@ -473,12 +474,12 @@ return runCommand(make_span(request, requestIt), delay); } -error_code +Result<void> DS28C40::computeAndWriteSha256Secret(int pageNum, KeySecret masterSecret, KeySecret destinationSecret, Page::const_span partialSecret) { if (pageNum < 0 || pageNum >= memoryPages) { - return make_error_code(InvalidParameterError); + return InvalidParameterError; } uint_least8_t request[3 + Page::size]; @@ -489,75 +490,73 @@ return runCommand(request, writeMemoryTimeMs + computeTimeMs); } -error_code DS28C40::generateEcc256KeyPair(KeySecret key) { +Result<void> DS28C40::generateEcc256KeyPair(KeySecret key) { if (key == KeySecretS) { - return make_error_code(InvalidParameterError); + return InvalidParameterError; } const uint_least8_t request[] = {0xCB, key == KeySecretB}; return runCommand(request, generateEccKeyPairTimeMs); } -error_code DS28C40::readRng(span<uint_least8_t> data) { +Result<void> DS28C40::readRng(span<uint_least8_t> data) const { const span<uint_least8_t>::index_type maxDataSize = 64; if ((data.size() < 1) || (data.size() > maxDataSize)) { - return make_error_code(InvalidParameterError); + return InvalidParameterError; } uint_least8_t buffer[1 + maxDataSize]; buffer[0] = readRngCmd; buffer[1] = static_cast<uint_least8_t>(data.size() - 1); - span<uint_least8_t> response(buffer, 1 + data.size()); - const error_code result = - runCommand(make_span(buffer, 2), trngGenerationTimeMs, response); - if (!result) { - copy(response.begin(), response.end(), data.begin()); + const Result<span<uint_least8_t> > response = + runCommand(make_span(buffer, 2), trngGenerationTimeMs, + make_span(buffer, 1 + data.size())); + if (!response) { + return response.error(); } - return result; + copy(response.value().begin(), response.value().end(), data.begin()); + return none; } -error_code DS28C40::entropyHealthTest() { +Result<void> DS28C40::entropyHealthTest() const { const uint_least8_t request[] = {readRngCmd, 0x80}; return runCommand(request, trngOnDemandCheckTimeMs); } -error_code DS28C40::runCommand(span<const uint_least8_t> request, int delayTime, - span<uint_least8_t> & response) { - const span<const uint_least8_t>::index_type responseInputSize = - response.size(); - error_code result = doRunCommand(request, delayTime, response); - if (result) { - return result; +Result<span<uint_least8_t> > +DS28C40::runCommand(span<const uint_least8_t> request, int delayTime, + span<uint_least8_t> response) const { + const Result<span<uint_least8_t> > responseOutput = + doRunCommand(request, delayTime, response); + if (!responseOutput) { + return responseOutput; } - if (response.empty()) { - return make_error_code(InvalidResponseError); + if (responseOutput.value().empty()) { + return InvalidResponseError; } // Parse command result byte. - switch (response[0]) { + switch (responseOutput.value().front()) { case 0xAA: // Success response. - if (response.size() != responseInputSize) { - result = make_error_code(InvalidResponseError); - } break; case 0x00: - result = make_error_code(AuthenticationError); - break; + return AuthenticationError; default: - result.assign(response[0], errorCategory()); - break; + return error_code(responseOutput.value().front(), errorCategory()); } - response = response.subspan(1); - return result; + if (responseOutput.value().size() != response.size()) { + return InvalidResponseError; + } + return responseOutput.value().subspan(1); } -error_code DS28C40::runCommand(span<const uint_least8_t> request, - int delayTime) { +Result<void> DS28C40::runCommand(span<const uint_least8_t> request, + int delayTime) const { uint_least8_t buffer; - span<uint_least8_t> response(&buffer, 1); - return runCommand(request, delayTime, response); + MaximInterfaceCore_TRY(runCommand(request, delayTime, make_span(&buffer, 1))); + return none; } const error_category & DS28C40::errorCategory() { @@ -594,33 +593,20 @@ return instance; } -error_code computeMultiblockHash(DS28C40 & device, - span<const uint_least8_t> data) { - error_code result; +Result<void> computeMultiblockHash(DS28C40 & device, + span<const uint_least8_t> data) { span<const uint_least8_t>::index_type dataIdx = 0; - while (dataIdx < data.size() && !result) { + while (dataIdx < data.size()) { const span<const uint_least8_t>::index_type remainingSize = data.size() - dataIdx; const span<const uint_least8_t>::index_type chunkSize = std::min<span<const uint_least8_t>::index_type>(remainingSize, 64); - result = + MaximInterfaceCore_TRY( device.computeMultiblockHash(dataIdx == 0, remainingSize == chunkSize, - data.subspan(dataIdx, chunkSize)); + data.subspan(dataIdx, chunkSize))); dataIdx += chunkSize; } - return result; -} - -error_code readRomIdAndManId(DS28C40 & device, RomId::span romId, - ManId::span manId) { - DS28C40::Page::array page; - error_code result = device.readMemory(DS28C40::romOptionsPage, page); - if (!result) { - const DS28C40::RomOptions romOptions(page); - copy(romOptions.romId(), romId); - copy(romOptions.manId(), manId); - } - return result; + return none; } static void setAnonymous(RomId::span romId) {