From 6da926833bc003fe4a1deb23bde4f472907c89c4 Mon Sep 17 00:00:00 2001 From: Andrea Gilardoni Date: Mon, 30 Mar 2026 17:51:16 +0200 Subject: [PATCH 1/8] Adding Library Base definition --- .codespellrc | 9 ++ .gitignore | 44 ++++++ LICENSE | 373 +++++++++++++++++++++++++++++++++++++++++++++ README.md | 14 ++ library.properties | 9 ++ 5 files changed, 449 insertions(+) create mode 100644 .codespellrc create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 README.md create mode 100644 library.properties diff --git a/.codespellrc b/.codespellrc new file mode 100644 index 0000000..025901d --- /dev/null +++ b/.codespellrc @@ -0,0 +1,9 @@ +# Source: https://github.com/arduino/tooling-project-assets/blob/main/workflow-templates/assets/spell-check/.codespellrc +# See: https://github.com/codespell-project/codespell#using-a-config-file +[codespell] +# In the event of a false positive, add the problematic word, in all lowercase, to a comma-separated list here: +ignore-words-list = , +skip = ./.git,./.licenses,__pycache__,node_modules,./go.mod,./go.sum,./package-lock.json,./poetry.lock,./yarn.lock,./src/cbor/tinycbor +builtin = clear,informal,en-GB_to_en-US +check-filenames = +check-hidden = diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..96633a9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,44 @@ +# Created by https://www.toptal.com/developers/gitignore/api/cmake,visualstudiocode +# Edit at https://www.toptal.com/developers/gitignore?templates=cmake,visualstudiocode + +### CMake ### +CMakeLists.txt.user +CMakeCache.txt +CMakeFiles +CMakeScripts +Testing +Makefile +cmake_install.cmake +install_manifest.txt +compile_commands.json +CTestTestfile.cmake +_deps + +### CMake Patch ### +# External projects +*-prefix/ + +### VisualStudioCode ### +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +!.vscode/*.code-snippets + +# Local History for Visual Studio Code +.history/ + +# Built Visual Studio Code Extensions +*.vsix + +### VisualStudioCode Patch ### +# Ignore all local history of files +.history +.ionide + +# End of https://www.toptal.com/developers/gitignore/api/cmake,visualstudiocode + +extras/test/bin/ +extras/test/DartConfiguration.tcl +extras/test/Makefile diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..dbdb0fa --- /dev/null +++ b/LICENSE @@ -0,0 +1,373 @@ +Mozilla Public License Version 2.0 +================================== + +1. Definitions +-------------- + +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +1.8. "License" + means this document. + +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; + or + +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at https://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..296ea8c --- /dev/null +++ b/README.md @@ -0,0 +1,14 @@ +# 🛠️ Arduino Cloud Utils + +[![Arduino Lint](https://github.com/arduino-libraries/Arduino_CloudUtils/actions/workflows/check-arduino.yml/badge.svg)](https://github.com/arduino-libraries/Arduino_CloudUtils/actions/workflows/check-arduino.yml) [![Compile Examples](https://github.com/arduino-libraries/Arduino_CloudUtils/actions/workflows/compile-examples.yml/badge.svg)](https://github.com/arduino-libraries/Arduino_CloudUtils/actions/workflows/compile-examples.yml) [![Spell Check](https://github.com/arduino-libraries/Arduino_CloudUtils/actions/workflows/spell-check.yml/badge.svg)](https://github.com/arduino-libraries/Arduino_CloudUtils/actions/workflows/spell-check.yml) [![Sync Labels](https://github.com/arduino-libraries/Arduino_CloudUtils/actions/workflows/sync-labels.yml/badge.svg)](https://github.com/arduino-libraries/Arduino_CloudUtils/actions/workflows/sync-labels.yml) + +This library contains a set of functionalities that may be shared among cloud related projects, in particular functionalities for ArduinoIoTCloud + +# 🔧 Utilities +* ✉️ [CRC16](examples/crc16) +* 📧 [CRC32](examples/crc32) +* 🔒 [CBOR decoder](examples/customCborDecoder) +* 🔓 [CBOR encoder](examples/customCborEncoder) +* ⬆️ [LZSS decoder](examples/lzssDecoder) +* 💨 [SHA256](examples/sha256) +* ⏲️ [Timed action](examples/timedBlink) diff --git a/library.properties b/library.properties new file mode 100644 index 0000000..214cc43 --- /dev/null +++ b/library.properties @@ -0,0 +1,9 @@ +name=SE05X +version=0.0.1 +author=Arduino +maintainer=Arduino +sentence=Arduino Library for the NXP SE05X crypto chips +paragraph= +category=Communication +url= +architectures=renesas,renesas_portenta,zephyr_main From ad2aa40351f1154c32db58c659be0f7c4b6bec63 Mon Sep 17 00:00:00 2001 From: Andrea Gilardoni Date: Mon, 30 Mar 2026 17:58:09 +0200 Subject: [PATCH 2/8] Importing NXP plugandtrust nano-package library --- src/lib/apdu/se05x_APDU_apis.h | 1494 +++++++++++++++++++++ src/lib/apdu/se05x_APDU_impl.c | 1208 +++++++++++++++++ src/lib/apdu/se05x_tlv.c | 674 ++++++++++ src/lib/apdu/se05x_tlv.h | 108 ++ src/lib/apdu/se05x_types.h | 529 ++++++++ src/lib/apdu/smCom.c | 130 ++ src/lib/apdu/smCom.h | 34 + src/lib/t1oi2c/phEseStatus.h | 411 ++++++ src/lib/t1oi2c/phEseTypes.h | 44 + src/lib/t1oi2c/phNxpEsePal_i2c.c | 251 ++++ src/lib/t1oi2c/phNxpEsePal_i2c.h | 104 ++ src/lib/t1oi2c/phNxpEseProto7816_3.c | 1782 ++++++++++++++++++++++++++ src/lib/t1oi2c/phNxpEseProto7816_3.h | 437 +++++++ src/lib/t1oi2c/phNxpEse_Api.c | 828 ++++++++++++ src/lib/t1oi2c/phNxpEse_Api.h | 72 ++ src/lib/t1oi2c/phNxpEse_Internal.h | 56 + 16 files changed, 8162 insertions(+) create mode 100644 src/lib/apdu/se05x_APDU_apis.h create mode 100644 src/lib/apdu/se05x_APDU_impl.c create mode 100644 src/lib/apdu/se05x_tlv.c create mode 100644 src/lib/apdu/se05x_tlv.h create mode 100644 src/lib/apdu/se05x_types.h create mode 100644 src/lib/apdu/smCom.c create mode 100644 src/lib/apdu/smCom.h create mode 100644 src/lib/t1oi2c/phEseStatus.h create mode 100644 src/lib/t1oi2c/phEseTypes.h create mode 100644 src/lib/t1oi2c/phNxpEsePal_i2c.c create mode 100644 src/lib/t1oi2c/phNxpEsePal_i2c.h create mode 100644 src/lib/t1oi2c/phNxpEseProto7816_3.c create mode 100644 src/lib/t1oi2c/phNxpEseProto7816_3.h create mode 100644 src/lib/t1oi2c/phNxpEse_Api.c create mode 100644 src/lib/t1oi2c/phNxpEse_Api.h create mode 100644 src/lib/t1oi2c/phNxpEse_Internal.h diff --git a/src/lib/apdu/se05x_APDU_apis.h b/src/lib/apdu/se05x_APDU_apis.h new file mode 100644 index 0000000..edc4a9b --- /dev/null +++ b/src/lib/apdu/se05x_APDU_apis.h @@ -0,0 +1,1494 @@ +/** @file se05x_APDU_apis.h + * @brief Se05x apdu functions. + * + * Copyright 2021,2022,2024,2026 NXP + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef SE05X_APDU_APIS_H_INC +#define SE05X_APDU_APIS_H_INC + +/* ********************** Include files ********************** */ +#include "lib/apdu/se05x_types.h" +#include "lib/apdu/se05x_tlv.h" + +/** Se05x_API_SessionOpen + * + * Open session to SE05x. + * Multiple sessions are not supported. + * + * @param[in] session_ctx The session context + * + * @return The sm status. + */ +smStatus_t Se05x_API_SessionOpen(pSe05xSession_t session_ctx); + +/** Se05x_API_SessionClose + * + * Close session to SE05x. + * + * @param[in] session_ctx The session context + * + * @return The sm status. + */ +smStatus_t Se05x_API_SessionClose(pSe05xSession_t session_ctx); + +/** Se05x_API_WriteECKey + * + * Write or update an EC key object. + * + * P1KeyPart indicates the key type to be created (if the object does not yet + * exist). + * + * If P1KeyPart = P1_KEY_PAIR, Private Key Value (TLV[TAG_3]) and Public Key + * Value (TLV[TAG_4) must both be present, or both be absent. If absent, the key + * pair is generated in the SE05X . + * + * If the object already exists, P1KeyPart is ignored. + * + * @rst + * +---------+------------------------+------------------------------------------------+ + * | Field | Value | Description | + * +=========+========================+================================================+ + * | P1 | :cpp:type:`SE05x_P1_t` | See :cpp:type:`SE05x_P1_t` , P1KeyType | + * | | | P1_EC | should only be set for new objects. | + * +---------+------------------------+------------------------------------------------+ + * | P2 | P2_DEFAULT | See P2 | + * +---------+------------------------+------------------------------------------------+ + * | Payload | TLV[TAG_POLICY] | Byte array containing the object policy. | + * | | | [Optional: default policy applies] | + * | | | [Conditional - only when the object | + * | | | identifier is not in use yet] | + * +---------+------------------------+------------------------------------------------+ + * | | TLV[TAG_MAX_ATTEMPTS] | 2-byte maximum number of attempts. If 0 is | + * | | | given, this means unlimited. [Optional: | + * | | | default unlimited] [Conditional: only when | + * | | | the object identifier is not in use yet and | + * | | | INS includes INS_AUTH_OBJECT; see | + * | | | AuthenticationObjectPolicies ] | + * +---------+------------------------+------------------------------------------------+ + * | | TLV[TAG_1] | 4-byte object identifier | + * +---------+------------------------+------------------------------------------------+ + * | | TLV[TAG_2] | 1-byte curve identifier, see ECCurve | + * | | | [Conditional: only when the object identifier | + * | | | is not in use yet; ] | + * +---------+------------------------+------------------------------------------------+ + * | | TLV[TAG_3] | Private key value (see :cpp:type:`ECKeyRef` | + * | | | ) [Conditional: only when the private key is | + * | | | externally generated and P1KeyType is either | + * | | | P1_KEY_PAIR or P1_PRIVATE] | + * +---------+------------------------+------------------------------------------------+ + * | | TLV[TAG_4] | Public key value (see :cpp:type:`ECKeyRef` ) | + * | | | [Conditional: only when the public key is | + * | | | externally generated and P1KeyType is either | + * | | | P1_KEY_PAIR or P1_PUBLIC] | + * +---------+------------------------+------------------------------------------------+ + * | | TLV[TAG_11] | 4-byte version [Optional] | + * +---------+------------------------+------------------------------------------------+ + * @endrst + * + * @param[in] session_ctx The session context + * @param[in] policy The policy + * @param[in] maxAttempt The maximum attempt + * @param[in] objectID The object id + * @param[in] curveID The curve id + * @param[in] privKey The priv key + * @param[in] privKeyLen The priv key length + * @param[in] pubKey The pub key + * @param[in] pubKeyLen The pub key length + * @param[in] ins_type The insert type + * @param[in] key_part The key part + * + * @return The sm status. + */ +smStatus_t Se05x_API_WriteECKey(pSe05xSession_t session_ctx, + pSe05xPolicy_t policy, + SE05x_MaxAttemps_t maxAttempt, + uint32_t objectID, + SE05x_ECCurve_t curveID, + const uint8_t *privKey, + size_t privKeyLen, + const uint8_t *pubKey, + size_t pubKeyLen, + const SE05x_INS_t ins_type, + const SE05x_KeyPart_t key_part); + +/** Se05x_API_ReadObject + * + * Reads the content of a Secure Object. + * + * * If the object is a key pair, the command will return the key + * pair's public key. + * + * * If the object is a public key, the command will return the public + * key. + * + * * If the object is a private key or a symmetric key or a userID, + * the command will return SW_CONDITIONS_NOT_SATISFIED. + * + * * If the object is a binary file, the file content is read, giving + * the offset in TLV[TAG_2] and the length to read in + * TLV[TAG_3]. Both TLV[TAG_2] and TLV[TAG_3] are bound together; + * i.e.. either both tags are present, or both are absent. If both + * are absent, the whole file content is returned. + * + * Command to Applet + * + * @rst + * +-------+------------+----------------------------------------------+ + * | Field | Value | Description | + * +=======+============+==============================================+ + * | CLA | 0x80 | | + * +-------+------------+----------------------------------------------+ + * | INS | INS_READ | See :cpp:type:`SE05x_INS_t`, in addition to | + * | | | INS_READ, users can set the INS_ATTEST flag. | + * | | | In that case, attestation applies. | + * +-------+------------+----------------------------------------------+ + * | P1 | P1_DEFAULT | See :cpp:type:`SE05x_P1_t` | + * +-------+------------+----------------------------------------------+ + * | P2 | P2_DEFAULT | See :cpp:type:`SE05x_P2_t` | + * +-------+------------+----------------------------------------------+ + * | Lc | #(Payload) | Payload Length. | + * +-------+------------+----------------------------------------------+ + * | | TLV[TAG_1] | 4-byte object identifier | + * +-------+------------+----------------------------------------------+ + * | | TLV[TAG_2] | 2-byte offset [Optional: default 0] | + * | | | [Conditional: only when the object is a | + * | | | BinaryFile object] | + * +-------+------------+----------------------------------------------+ + * | | TLV[TAG_3] | 2-byte length [Optional: default 0] | + * | | | [Conditional: only when the object is a | + * | | | BinaryFile object] | + * +-------+------------+----------------------------------------------+ + * | | TLV[TAG_4] | 1-byte :cpp:type:`SE05x_RSAKeyComponent_t`: | + * | | | either RSA_COMP_MOD or RSA_COMP_PUB_EXP. | + * | | | [Optional] [Conditional: only for RSA key | + * | | | components] | + * +-------+------------+----------------------------------------------+ + * | Le | 0x00 | | + * +-------+------------+----------------------------------------------+ + * @endrst + * + * R-APDU Body + * + * @rst + * +------------+--------------------------------------------+ + * | Value | Description | + * +============+============================================+ + * | TLV[TAG_1] | Data read from the secure object. | + * +------------+--------------------------------------------+ + * @endrst + * + * R-APDU Trailer + * + * @rst + * +-------------+--------------------------------+ + * | SW | Description | + * +=============+================================+ + * | SW_NO_ERROR | The read is done successfully. | + * +-------------+--------------------------------+ + * @endrst + * + * @param[in] session_ctx Session Context [0:kSE05x_pSession] + * @param[in] objectID object id [1:kSE05x_TAG_1] + * @param[in] offset offset [2:kSE05x_TAG_2] + * @param[in] length length [3:kSE05x_TAG_3] + * @param[out] data [0:kSE05x_TAG_1] + * @param[in,out] pdataLen Length for data + */ +smStatus_t Se05x_API_ReadObject( + pSe05xSession_t session_ctx, uint32_t objectID, uint16_t offset, uint16_t length, uint8_t *data, size_t *pdataLen); + +/** Se05x_API_GetVersion + * + * Gets the applet version information. + * + * This will return 7-byte VersionInfo (including major, minor and patch version + * of the applet, supported applet features and secure box version). + * + * Command to Applet + * + * @rst + * +-------+------------------------------+----------------------------------------------+ + * | Field | Value | Description | + * +=======+==============================+==============================================+ + * | CLA | 0x80 | | + * +-------+------------------------------+----------------------------------------------+ + * | INS | INS_MGMT | See :cpp:type:`SE05x_INS_t` | + * +-------+------------------------------+----------------------------------------------+ + * | P1 | P1_DEFAULT | See :cpp:type:`SE05x_P1_t` | + * +-------+------------------------------+----------------------------------------------+ + * | P2 | P2_VERSION or P2_VERSION_EXT | See :cpp:type:`SE05x_P2_t` | + * +-------+------------------------------+----------------------------------------------+ + * | Lc | #(Payload) | | + * +-------+------------------------------+----------------------------------------------+ + * | Le | 0x00 | Expecting TLV with 7-byte data (when P2 = | + * | | | P2_VERSION) or a TLV with 37 byte data (when | + * | | | P2= P2_VERSION_EXT). | + * +-------+------------------------------+----------------------------------------------+ + * @endrst + * + * + * R-APDU Body + * + * @rst + * +------------+------------------------------------------------+ + * | Value | Description | + * +============+================================================+ + * | TLV[TAG_1] | 7-byte :cpp:type:`VersionInfoRef` (if P2 = | + * | | P2_VERSION) or 7-byte VersionInfo followed by | + * | | 30 bytes extendedFeatureBits (if P2 = | + * | | P2_VERSION_EXT) | + * +------------+------------------------------------------------+ + * @endrst + * + * R-APDU Trailer + * + * @rst + * +-------------+--------------------------------+ + * | SW | Description | + * +=============+================================+ + * | SW_NO_ERROR | Data is returned successfully. | + * +-------------+--------------------------------+ + * @endrst + * + * @param[in] session_ctx The session context + * @param pappletVersion The papplet version + * @param appletVersionLen The applet version length + * + * @return The sm status. + */ +smStatus_t Se05x_API_GetVersion(pSe05xSession_t session_ctx, uint8_t *pappletVersion, size_t *appletVersionLen); + +/** Se05x_API_ECDSASign + * + * The ECDSASign command signs external data using the indicated key pair or + * private key. + * + * The ECSignatureAlgo indicates the ECDSA algorithm that is used, but the + * hashing of data always must be done on the host. E.g., if ECSignatureAlgo = + * SIG_ ECDSA_SHA256, the user must have applied SHA256 on the input data + * already. Supported SHA algorithms - SHA1, SHA224, SHA256, SHA384. + * + * The user must take care of providing the correct input length; i.e., the data + * input length (TLV[TAG_3]) must match the digest indicated in the signature + * algorithm (TLV[TAG_2]). + * + * In any case, the APDU payload must be smaller than MAX_APDU_PAYLOAD_LENGTH. + * + * This is performed according to the ECDSA algorithm as specified in [ANSI + * X9.62]. The signature (a sequence of two integers 'r' and 's') as + * returned in the response adheres to the ASN.1 DER encoded formatting rules for + * integers. + * + * Command to Applet + * + * @rst + * +-------+--------------+---------------------------------------------+ + * | Field | Value | Description | + * +=======+==============+=============================================+ + * | CLA | 0x80 | | + * +-------+--------------+---------------------------------------------+ + * | INS | INS_CRYPTO | :cpp:type:`SE05x_INS_t` | + * +-------+--------------+---------------------------------------------+ + * | P1 | P1_SIGNATURE | See :cpp:type:`SE05x_P1_t` | + * +-------+--------------+---------------------------------------------+ + * | P2 | P2_SIGN | See :cpp:type:`SE05x_P2_t` | + * +-------+--------------+---------------------------------------------+ + * | Lc | #(Payload) | | + * +-------+--------------+---------------------------------------------+ + * | | TLV[TAG_1] | 4-byte identifier of EC key pair or private | + * | | | key. | + * +-------+--------------+---------------------------------------------+ + * | | TLV[TAG_2] | 1-byte ECSignatureAlgo. | + * +-------+--------------+---------------------------------------------+ + * | | TLV[TAG_3] | Byte array containing input data. | + * +-------+--------------+---------------------------------------------+ + * | Le | 0x00 | Expecting ASN.1 signature | + * +-------+--------------+---------------------------------------------+ + * @endrst + * + * R-APDU Body + * + * @rst + * +------------+----------------------------------+ + * | Value | Description | + * +============+==================================+ + * | TLV[TAG_1] | ECDSA Signature in ASN.1 format. | + * +------------+----------------------------------+ + * @endrst + * + * R-APDU Trailer + * + * @rst + * +-------------+--------------------------------------+ + * | SW | Description | + * +=============+======================================+ + * | SW_NO_ERROR | The command is handled successfully. | + * +-------------+--------------------------------------+ + * @endrst + * + * + * + * @param[in] session_ctx Session Context [0:kSE05x_pSession] + * @param[in] objectID objectID [1:kSE05x_TAG_1] + * @param[in] ecSignAlgo ecSignAlgo [2:kSE05x_TAG_2] + * @param[in] inputData inputData [3:kSE05x_TAG_3] + * @param[in] inputDataLen Length of inputData + * @param[out] signature [0:kSE05x_TAG_1] + * @param[in,out] psignatureLen Length for signature + */ +smStatus_t Se05x_API_ECDSASign(pSe05xSession_t session_ctx, + uint32_t objectID, + SE05x_ECSignatureAlgo_t ecSignAlgo, + const uint8_t *inputData, + size_t inputDataLen, + uint8_t *signature, + size_t *psignatureLen); + +/** Se05x_API_ECDSAVerify + * + * The ECDSAVerify command verifies whether the signature is correct for a given + * (hashed) data input using an EC public key or EC key pair's public key. + * + * The ECSignatureAlgo indicates the ECDSA algorithm that is used, but the + * hashing of data must always be done on the host. E.g., if ECSignatureAlgo = + * SIG_ ECDSA_SHA256, the user must have applied SHA256 on the input data + * already. Supported SHA algorithms - SHA1, SHA224, SHA256, SHA384. + * + * The key cannot be passed externally to the command directly. In case users + * want to use the command to verify signatures using different public keys or + * the public key value regularly changes, the user should create a transient key + * object to which the key value is written and then the identifier of that + * transient secure object can be used by this ECDSAVerify command. + * + * Command to Applet + * + * @rst + * +-------+--------------+-----------------------------------------------+ + * | Field | Value | Description | + * +=======+==============+===============================================+ + * | CLA | 0x80 | | + * +-------+--------------+-----------------------------------------------+ + * | INS | INS_CRYPTO | :cpp:type:`SE05x_INS_t` | + * +-------+--------------+-----------------------------------------------+ + * | P1 | P1_SIGNATURE | See :cpp:type:`SE05x_P1_t` | + * +-------+--------------+-----------------------------------------------+ + * | P2 | P2_VERIFY | See :cpp:type:`SE05x_P2_t` | + * +-------+--------------+-----------------------------------------------+ + * | Lc | #(Payload) | | + * +-------+--------------+-----------------------------------------------+ + * | | TLV[TAG_1] | 4-byte identifier of the key pair or public | + * | | | key. | + * +-------+--------------+-----------------------------------------------+ + * | | TLV[TAG_2] | 1-byte ECSignatureAlgo. | + * +-------+--------------+-----------------------------------------------+ + * | | TLV[TAG_3] | Byte array containing ASN.1 signature | + * +-------+--------------+-----------------------------------------------+ + * | | TLV[TAG_5] | Byte array containing hashed data to compare. | + * +-------+--------------+-----------------------------------------------+ + * | Le | 0x03 | Expecting TLV with :cpp:type:`SE05x_Result_t` | + * +-------+--------------+-----------------------------------------------+ + * @endrst + * + * R-APDU Body + * + * @rst + * +------------+--------------------------------------+ + * | Value | Description | + * +============+======================================+ + * | TLV[TAG_1] | Result of the signature verification | + * | | (:cpp:type:`SE05x_Result_t`). | + * +------------+--------------------------------------+ + * @endrst + * + * R-APDU Trailer + * + * @rst + * +-----------------------------+--------------------------------------+ + * | SW | Description | + * +=============================+======================================+ + * | SW_NO_ERROR | The command is handled successfully. | + * +-----------------------------+--------------------------------------+ + * | SW_CONDITIONS_NOT_SATISFIED | Incorrect data | + * +-----------------------------+--------------------------------------+ + * @endrst + * + * + * + * @param[in] session_ctx Session Context [0:kSE05x_pSession] + * @param[in] objectID objectID [1:kSE05x_TAG_1] + * @param[in] ecSignAlgo ecSignAlgo [2:kSE05x_TAG_2] + * @param[in] inputData inputData [3:kSE05x_TAG_3] + * @param[in] inputDataLen Length of inputData + * @param[in] signature signature [4:kSE05x_TAG_5] + * @param[in] signatureLen Length of signature + * @param[out] presult [0:kSE05x_TAG_1] + */ +smStatus_t Se05x_API_ECDSAVerify(pSe05xSession_t session_ctx, + uint32_t objectID, + SE05x_ECSignatureAlgo_t ecSignAlgo, + const uint8_t *inputData, + size_t inputDataLen, + const uint8_t *signature, + size_t signatureLen, + SE05x_Result_t *presult); + +/** Se05x_API_CheckObjectExists + * + * + * Check if a Secure Object with a certain identifier exists or not. + * + * Command to Applet + * + * @rst + * +-------+------------+-------------------------------------------+ + * | Field | Value | Description | + * +=======+============+===========================================+ + * | CLA | 0x80 | | + * +-------+------------+-------------------------------------------+ + * | INS | INS_MGMT | See :cpp:type:`SE05x_INS_t` | + * +-------+------------+-------------------------------------------+ + * | P1 | P1_DEFAULT | See :cpp:type:`SE05x_P1_t` | + * +-------+------------+-------------------------------------------+ + * | P2 | P2_EXIST | See :cpp:type:`SE05x_P2_t` | + * +-------+------------+-------------------------------------------+ + * | Lc | #(Payload) | | + * +-------+------------+-------------------------------------------+ + * | | TLV[TAG_1] | 4-byte existing Secure Object identifier. | + * +-------+------------+-------------------------------------------+ + * | Le | 0x00 | | + * +-------+------------+-------------------------------------------+ + * @endrst + * + * R-APDU Body + * + * @rst + * +------------+-----------------------------------+ + * | Value | Description | + * +============+===================================+ + * | TLV[TAG_1] | 1-byte :cpp:type:`SE05x_Result_t` | + * +------------+-----------------------------------+ + * @endrst + * + * R-APDU Trailer + * + * @rst + * +-------------+--------------------------------+ + * | SW | Description | + * +=============+================================+ + * | SW_NO_ERROR | Data is returned successfully. | + * +-------------+--------------------------------+ + * @endrst + * + * + * + * @param[in] session_ctx Session Context [0:kSE05x_pSession] + * @param[in] objectID object id [1:kSE05x_TAG_1] + * @param[out] presult [0:kSE05x_TAG_1] + */ +smStatus_t Se05x_API_CheckObjectExists(pSe05xSession_t session_ctx, uint32_t objectID, SE05x_Result_t *presult); + +/** Se05x_API_WriteBinary + * + * Creates or writes to a binary file object. Data are written to either the + * start of the file or (if specified) to the offset passed to the function. + * + * Command to Applet + * + * @rst + * +---------+-----------------+-----------------------------------------------+ + * | Field | Value | Description | + * +=========+=================+===============================================+ + * | P1 | P1_BINARY | See :cpp:type:`SE05x_P1_t` | + * +---------+-----------------+-----------------------------------------------+ + * | P2 | P2_DEFAULT | See :cpp:type:`SE05x_P2_t` | + * +---------+-----------------+-----------------------------------------------+ + * | Payload | TLV[TAG_POLICY] | Byte array containing the object policy. | + * | | | [Optional: default policy applies] | + * | | | [Conditional: only when the object identifier | + * | | | is not in use yet] | + * +---------+-----------------+-----------------------------------------------+ + * | | TLV[TAG_1] | 4-byte object identifier | + * +---------+-----------------+-----------------------------------------------+ + * | | TLV[TAG_2] | 2-byte file offset [Optional: default = 0] | + * +---------+-----------------+-----------------------------------------------+ + * | | TLV[TAG_3] | 2-byte file length (up to 0x7FFF). | + * | | | [Conditional: only when the object identifier | + * | | | is not in use yet] | + * +---------+-----------------+-----------------------------------------------+ + * | | TLV[TAG_4] | Data to be written [Optional: if not given, | + * | | | TAG_3 must be filled] | + * +---------+-----------------+-----------------------------------------------+ + * | | TLV[TAG_11] | 4-byte version [Optional] | + * +---------+-----------------+-----------------------------------------------+ + * @endrst + * + * + * @param[in] session_ctx Session Context [0:kSE05x_pSession] + * @param[in] policy policy [1:kSE05x_TAG_POLICY] + * @param[in] objectID object id [2:kSE05x_TAG_1] + * @param[in] offset offset [3:kSE05x_TAG_2] + * @param[in] length length [4:kSE05x_TAG_3] + * @param[in] inputData input data. (Max - 128 Bytes) [5:kSE05x_TAG_4] + * @param[in] inputDataLen Length of inputData + */ +smStatus_t Se05x_API_WriteBinary(pSe05xSession_t session_ctx, + pSe05xPolicy_t policy, + uint32_t objectID, + uint16_t offset, + uint16_t length, + const uint8_t *inputData, + size_t inputDataLen); + +/** Se05x_API_ECDHGenerateSharedSecret + * + * The ECDHGenerateSharedSecret command generates a shared secret ECC point on + * the curve using an EC private key on SE05X and an external public key provided + * by the caller. The output shared secret is returned to the caller. + * + * Command to Applet + * + * @rst + * +------------+------------------------------+----------------------------------------------+ + * | Field | Value | Description | + * +============+==============================+==============================================+ + * | CLA | 0x80 | | + * +------------+------------------------------+----------------------------------------------+ + * | INS | INS_CRYPTO | :cpp:type:`SE05x_INS_t` | + * +------------+------------------------------+----------------------------------------------+ + * | P1 | P1_EC | See :cpp:type:`SE05x_P1_t` | + * +------------+------------------------------+----------------------------------------------+ + * | P2 | P2_DH | See :cpp:type:`SE05x_P2_t` | + * +------------+------------------------------+----------------------------------------------+ + * | Lc | #(Payload) | | + * +------------+------------------------------+----------------------------------------------+ + * | Payload | TLV[TAG_1] | 4-byte identifier of the key pair or private | + * | | | key. | + * +------------+------------------------------+----------------------------------------------+ + * | TLV[TAG_2] | External public key (see | | + * | | :cpp:type:`ECKeyRef`). | | + * +------------+------------------------------+----------------------------------------------+ + * | TLV[TAG_7] | 4-byte HMACKey identifier to | | + * | | store output. [Optional] | | + * +------------+------------------------------+----------------------------------------------+ + * | Le | 0x00 | Expected shared secret length. | + * +------------+------------------------------+----------------------------------------------+ + * @endrst + * + * R-APDU Body + * + * @rst + * +------------+----------------------------------------------+ + * | Value | Description | + * +============+==============================================+ + * | TLV[TAG_1] | The returned shared secret. [Conditional: | + * | | only when the input does not contain | + * | | TLV[TAG_7].} | + * +------------+----------------------------------------------+ + * @endrst + * + * R-APDU Trailer + * + * @rst + * +-------------+--------------------------------------+ + * | SW | Description | + * +=============+======================================+ + * | SW_NO_ERROR | The command is handled successfully. | + * +-------------+--------------------------------------+ + * @endrst + * + * + * + * @param[in] session_ctx Session Context [0:kSE05x_pSession] + * @param[in] objectID objectID [1:kSE05x_TAG_1] + * @param[in] pubKey pubKey [2:kSE05x_TAG_2] + * @param[in] pubKeyLen Length of pubKey + * @param[out] sharedSecret [0:kSE05x_TAG_1] + * @param[in,out] psharedSecretLen Length for sharedSecret + */ +smStatus_t Se05x_API_ECDHGenerateSharedSecret(pSe05xSession_t session_ctx, + uint32_t objectID, + const uint8_t *pubKey, + size_t pubKeyLen, + uint8_t *sharedSecret, + size_t *psharedSecretLen); + +/** + * @brief Se05x_API_CipherOneShot + * + * Encrypt or decrypt data in one shot mode. + * + * The key object must be either an AES key or DES key. + * + * Command to Applet + * + * @rst + * +---------+-----------------------+------------------------------------------------+ + * | Field | Value | Description | + * +=========+=======================+================================================+ + * | CLA | 0x80 | | + * +---------+-----------------------+------------------------------------------------+ + * | INS | INS_CRYPTO | :cpp:type:`SE05x_INS_t` | + * +---------+-----------------------+------------------------------------------------+ + * | P1 | P1_CIPHER | See :cpp:type:`SE05x_P1_t` | + * +---------+-----------------------+------------------------------------------------+ + * | P2 | P2_ENCRYPT_ONESHOT or | See :cpp:type:`SE05x_P2_t` | + * | | P2_DECRYPT_ONESHOT | | + * +---------+-----------------------+------------------------------------------------+ + * | Lc | #(Payload) | | + * +---------+-----------------------+------------------------------------------------+ + * | Payload | TLV[TAG_1] | 4-byte identifier of the key object. | + * +---------+-----------------------+------------------------------------------------+ + * | | TLV[TAG_2] | 1-byte CipherMode | + * +---------+-----------------------+------------------------------------------------+ + * | | TLV[TAG_3] | Byte array containing input data. | + * +---------+-----------------------+------------------------------------------------+ + * | | TLV[TAG_4] | Byte array containing an initialization | + * | | | vector. [Optional] [Conditional: only when | + * | | | the Crypto Object type equals CC_CIPHER and | + * | | | subtype is not including ECB] | + * +---------+-----------------------+------------------------------------------------+ + * | Le | 0x00 | Expecting return data. | + * +---------+-----------------------+------------------------------------------------+ + * @endrst + * + * R-APDU Body + * + * @rst + * +------------+-------------+ + * | Value | Description | + * +============+=============+ + * | TLV[TAG_1] | Output data | + * +------------+-------------+ + * @endrst + * + * R-APDU Trailer + * + * @rst + * +-------------+--------------------------------------+ + * | SW | Description | + * +=============+======================================+ + * | SW_NO_ERROR | The command is handled successfully. | + * +-------------+--------------------------------------+ + * @endrst + * + * + * @param[in] session_ctx The session context + * @param[in] objectID The object id (AES key object with key length = 128 or 192 or 256 bits) + * @param[in] cipherMode The cipher mode + * @param[in] inputData The input data (16 Bytes aligned data. Max - 112 Bytes) + * @param[in] inputDataLen The input data length + * @param[in] IV Initial vector (16 Bytes) + * @param[in] IVLen The iv length + * @param[in,out] outputData The output data + * @param[in,out] poutputDataLen The poutput data length + * @param[in] operation The operation + * + * @return The sm status. + */ +smStatus_t Se05x_API_CipherOneShot(pSe05xSession_t session_ctx, + uint32_t objectID, + SE05x_CipherMode_t cipherMode, + const uint8_t *inputData, + size_t inputDataLen, + uint8_t *IV, + size_t IVLen, + uint8_t *outputData, + size_t *poutputDataLen, + const SE05x_Cipher_Oper_OneShot_t operation); + +/** Se05x_API_WriteSymmKey + * + * Creates or writes an AES key, DES key or HMAC key, indicated by P1: + * + * * P1_AES + * + * * P1_DES + * + * * P1_HMAC + * + * Users can pass RFC3394 wrapped keys by indicating the KEK in TLV[TAG_2]. Note + * that RFC3394 required 8-byte aligned input, so this can only be used when the + * key has an 8-byte aligned length. + * + * Command to Applet + * + * @rst + * +---------+-----------------------+-----------------------------------------------+ + * | Field | Value | Description | + * +=========+=======================+===============================================+ + * | P1 | See above | See :cpp:type:`SE05x_P1_t` | + * +---------+-----------------------+-----------------------------------------------+ + * | P2 | P2_DEFAULT | See :cpp:type:`SE05x_P2_t` | + * +---------+-----------------------+-----------------------------------------------+ + * | Payload | TLV[TAG_POLICY] | Byte array containing the object policy. | + * | | | [Optional: default policy applies] | + * | | | [Conditional: only when the object identifier | + * | | | is not in use yet] | + * +---------+-----------------------+-----------------------------------------------+ + * | | TLV[TAG_MAX_ATTEMPTS] | 2-byte maximum number of attempts. If 0 is | + * | | | given, this means unlimited. [Optional: | + * | | | default unlimited] [Conditional: only when | + * | | | the object identifier is not in use yet and | + * | | | INS includes INS_AUTH_OBJECT; see | + * | | | AuthenticationObjectPolicies] | + * +---------+-----------------------+-----------------------------------------------+ + * | | TLV[TAG_1] | 4-byte object identifier | + * +---------+-----------------------+-----------------------------------------------+ + * | | TLV[TAG_2] | 4-byte KEK identifier [Conditional: only | + * | | | when the key value is RFC3394 wrapped] | + * +---------+-----------------------+-----------------------------------------------+ + * | | TLV[TAG_3] | Key value, either plain or RFC3394 wrapped. | + * +---------+-----------------------+-----------------------------------------------+ + * | | TLV[TAG_4] | Tag length for GCM/GMAC. Will only be used if | + * | | | the object is an AESKey. [Optional] | + * +---------+-----------------------+-----------------------------------------------+ + * | | TLV[TAG_11] | 4-byte version [Optional] | + * +---------+-----------------------+-----------------------------------------------+ + * @endrst + * + * @param[in] session_ctx The session context + * @param[in] policy The policy + * @param[in] maxAttempt The maximum attempt + * @param[in] objectID The object id + * @param[in] kekID The kek id + * @param[in] keyValue The key value (Supported lengths - 128, 192 or 256 bits) + * @param[in] keyValueLen The key value length + * @param[in] ins_type The insert type + * @param[in] type The type + * + * @return The sm status. + */ +smStatus_t Se05x_API_WriteSymmKey(pSe05xSession_t session_ctx, + pSe05xPolicy_t policy, + SE05x_MaxAttemps_t maxAttempt, + uint32_t objectID, + SE05x_KeyID_t kekID, + const uint8_t *keyValue, + size_t keyValueLen, + const SE05x_INS_t ins_type, + const SE05x_SymmKeyType_t type); + +/** Se05x_API_DeleteSecureObject + * + * Deletes a Secure Object. + * + * If the object origin = ORIGIN_PROVISIONED, an error will be returned and the + * object is not deleted. + * + * + * Command to Applet + * + * @rst + * +-------+------------------+-------------------------------------------+ + * | Field | Value | Description | + * +=======+==================+===========================================+ + * | CLA | 0x80 | | + * +-------+------------------+-------------------------------------------+ + * | INS | INS_MGMT | See :cpp:type:`SE05x_INS_t` | + * +-------+------------------+-------------------------------------------+ + * | P1 | P1_DEFAULT | See :cpp:type:`SE05x_P1_t` | + * +-------+------------------+-------------------------------------------+ + * | P2 | P2_DELETE_OBJECT | See :cpp:type:`SE05x_P2_t` | + * +-------+------------------+-------------------------------------------+ + * | Lc | #(Payload) | | + * +-------+------------------+-------------------------------------------+ + * | | TLV[TAG_1] | 4-byte existing Secure Object identifier. | + * +-------+------------------+-------------------------------------------+ + * | Le | - | | + * +-------+------------------+-------------------------------------------+ + * @endrst + * + * R-APDU Body + * + * NA + * + * R-APDU Trailer + * + * @rst + * +-------------+----------------------------------------------+ + * | SW | Description | + * +=============+==============================================+ + * | SW_NO_ERROR | The file is created or updated successfully. | + * +-------------+----------------------------------------------+ + * @endrst + * + * + * @param[in] session_ctx Session Context [0:kSE05x_pSession] + * @param[in] objectID object id [1:kSE05x_TAG_1] + */ +smStatus_t Se05x_API_DeleteSecureObject(pSe05xSession_t session_ctx, uint32_t objectID); + +/** Se05x_API_CreateSession + * + * Creates a session on SE05X . + * + * Depending on the authentication object being referenced, a specific method of + * authentication applies. The response needs to adhere to this authentication + * method. + * + * + * # Command to Applet + * + * @rst + * +---------+-------------------+------------------------------+ + * | Field | Value | Description | + * +=========+===================+==============================+ + * | CLA | 0x80 | | + * +---------+-------------------+------------------------------+ + * | INS | INS_MGMT | See :cpp:type:`SE05x_INS_t` | + * +---------+-------------------+------------------------------+ + * | P1 | P1_DEFAULT | See :cpp:type:`SE05x_P1_t` | + * +---------+-------------------+------------------------------+ + * | P2 | P2_SESSION_CREATE | See :cpp:type:`SE05x_P2_t` | + * +---------+-------------------+------------------------------+ + * | Lc | #(Payload) | Payload length. | + * +---------+-------------------+------------------------------+ + * | Payload | TLV[TAG_1] | 4-byte authentication object | + * | | | identifier. | + * +---------+-------------------+------------------------------+ + * | Le | 0x0A | Expecting TLV with 8-byte | + * | | | session ID. | + * +---------+-------------------+------------------------------+ + * @endrst + * + * # R-APDU Body + * + * @rst + * +------------+----------------------------+ + * | Value | Description | + * +============+============================+ + * | TLV[TAG_1] | 8-byte session identifier. | + * +------------+----------------------------+ + * @endrst + * + * # R-APDU Trailer + * + * SW_NO_ERROR: + * * The command is handled successfully. + * + * SW_CONDITIONS_NOT_SATISFIED: + * * The authenticator does not exist + * * The provided input data are incorrect. + * * The session is invalid. + * + * @param[in] session_ctx Session Context [0:kSE05x_pSession] + * @param[in] authObjectID auth [1:kSE05x_TAG_1] + * @param[out] sessionId [0:kSE05x_TAG_1] + * @param[in,out] psessionIdLen Length for sessionId + * + * + */ +smStatus_t Se05x_API_CreateSession( + pSe05xSession_t session_ctx, uint32_t authObjectID, uint8_t *sessionId, size_t *psessionIdLen); + +/** Se05x_API_ReadIDList + * + * Get a list of present Secure Object identifiers. + * + * # Command to Applet + * + * @rst + * +-------+------------+-----------------------------------------------+ + * | Field | Value | Description | + * +=======+============+===============================================+ + * | CLA | 0x80 | | + * +-------+------------+-----------------------------------------------+ + * | INS | INS_READ | See :cpp:type:`SE05x_INS_t` | + * +-------+------------+-----------------------------------------------+ + * | P1 | P1_DEFAULT | See :cpp:type:`SE05x_P1_t` | + * +-------+------------+-----------------------------------------------+ + * | P2 | P2_LIST | See :cpp:type:`SE05x_P2_t` | + * +-------+------------+-----------------------------------------------+ + * | Lc | #(Payload) | | + * +-------+------------+-----------------------------------------------+ + * | | TLV[TAG_1] | 2-byte offset | + * +-------+------------+-----------------------------------------------+ + * | | TLV[TAG_2] | 1-byte type filter: 1 byte from | + * | | | :cpp:type:`SE05x_SecObjTyp_t` or 0xFF for all | + * | | | types. | + * +-------+------------+-----------------------------------------------+ + * | Le | 0x00 | | + * +-------+------------+-----------------------------------------------+ + * @endrst + * + * # R-APDU Body + * + * @rst + * +------------+-------------------------------------------+ + * | Value | Description | + * +============+===========================================+ + * | TLV[TAG_1] | 1-byte :cpp:type:`MoreIndicatorRef` | + * +------------+-------------------------------------------+ + * | TLV[TAG_2] | Byte array containing 4-byte identifiers. | + * +------------+-------------------------------------------+ + * @endrst + * + * # R-APDU Trailer + * + * @rst + * +-------------+--------------------------------+ + * | SW | Description | + * +=============+================================+ + * | SW_NO_ERROR | Data is returned successfully. | + * +-------------+--------------------------------+ + * @endrst + * + * + * + * @param[in] session_ctx Session Context [0:kSE05x_pSession] + * @param[in] outputOffset output offset [1:kSE05x_TAG_1] + * @param[in] filter filter [2:kSE05x_TAG_2] + * @param[out] pmore If more ids are present [0:kSE05x_TAG_1] + * @param[out] idlist Byte array containing 4-byte identifiers [1:kSE05x_TAG_2] + * @param[in,out] pidlistLen Length for idlist + */ +smStatus_t Se05x_API_ReadIDList(pSe05xSession_t session_ctx, + uint16_t outputOffset, + uint8_t filter, + uint8_t *pmore, + uint8_t *idlist, + size_t *pidlistLen); + +/** Se05x_API_ReadSize + * + * ReadSize + * + * Get the size of a Secure Object (in bytes): + * + * * For EC keys: the size of the curve is returned. + * + * * For RSA keys: the key size is returned. + * + * * For AES/DES/HMAC keys, the key size is returned. + * + * * For binary files: the file size is returned + * + * * For userIDs: nothing is returned (SW_CONDITIONS_NOT_SATISFIED). + * + * * For counters: the counter length is returned. + * + * * For PCR: the PCR length is returned. + * + * # Command to Applet + * + * @rst + * +-------+------------+-----------------------------+ + * | Field | Value | Description | + * +=======+============+=============================+ + * | CLA | 0x80 | | + * +-------+------------+-----------------------------+ + * | INS | INS_READ | See :cpp:type:`SE05x_INS_t` | + * +-------+------------+-----------------------------+ + * | P1 | P1_DEFAULT | See :cpp:type:`SE05x_P1_t` | + * +-------+------------+-----------------------------+ + * | P2 | P2_SIZE | See :cpp:type:`SE05x_P2_t` | + * +-------+------------+-----------------------------+ + * | Lc | #(Payload) | | + * +-------+------------+-----------------------------+ + * | | TLV[TAG_1] | 4-byte object identifier. | + * +-------+------------+-----------------------------+ + * | Le | 0x00 | | + * +-------+------------+-----------------------------+ + * @endrst + * + * # R-APDU Body + * + * @rst + * +------------+-----------------------------+ + * | Value | Description | + * +============+=============================+ + * | TLV[TAG_1] | Byte array containing size. | + * +------------+-----------------------------+ + * @endrst + * + * # R-APDU Trailer + * + * @rst + * +-------------+--------------------------------+ + * | SW | Description | + * +=============+================================+ + * | SW_NO_ERROR | Data is returned successfully. | + * +-------------+--------------------------------+ + * @endrst + * + * + * @param[in] session_ctx The session context + * @param[in] objectID The object id + * @param psize The psize + * + * @return The sm status. + */ +smStatus_t Se05x_API_ReadSize(pSe05xSession_t session_ctx, uint32_t objectID, uint16_t *psize); + +/** Se05x_API_ReadType + * + * Get the type of a Secure Object. + * + * # Command to Applet + * + * @rst + * +-------+------------+-----------------------------+ + * | Field | Value | Description | + * +=======+============+=============================+ + * | CLA | 0x80 | | + * +-------+------------+-----------------------------+ + * | INS | INS_READ | See :cpp:type:`SE05x_INS_t` | + * +-------+------------+-----------------------------+ + * | P1 | P1_DEFAULT | See :cpp:type:`SE05x_P1_t` | + * +-------+------------+-----------------------------+ + * | P2 | P2_TYPE | See :cpp:type:`SE05x_P2_t` | + * +-------+------------+-----------------------------+ + * | Lc | #(Payload) | | + * +-------+------------+-----------------------------+ + * | | TLV[TAG_1] | 4-byte object identifier. | + * +-------+------------+-----------------------------+ + * | Le | 0x00 | | + * +-------+------------+-----------------------------+ + * @endrst + * + + * # R-APDU Body + * + * @rst + * +------------+-----------------------------------+ + * | Value | Description | + * +============+===================================+ + * | TLV[TAG_1] | Type of the Secure Object: one of | + * | | :cpp:type:`SE05x_SecObjTyp_t` | + * +------------+-----------------------------------+ + * | TLV[TAG_2] | :cpp:type:`TransientIndicatorRef` | + * +------------+-----------------------------------+ + * @endrst + * + * + * # R-APDU Trailer + * + * @rst + * +-------------+--------------------------------+ + * | SW | Description | + * +=============+================================+ + * | SW_NO_ERROR | Data is returned successfully. | + * +-------------+--------------------------------+ + * @endrst + * + * + * @param[in] session_ctx The session context + * @param[in] objectID The object id + * @param ptype The ptype + * @param pisTransient The pis transient + * @param[in] attestation_type The attestation type + * + * @return The sm status. + */ +smStatus_t Se05x_API_ReadType(pSe05xSession_t session_ctx, + uint32_t objectID, + SE05x_SecureObjectType_t *ptype, + uint8_t *pisTransient, + const SE05x_AttestationType_t attestation_type); + +/** Se05x_API_CreateECCurve + * + * Create an EC curve listed in ECCurve. + * + * + * # Command to Applet + * + * @rst + * +-------+------------+-------------------------------+ + * | Field | Value | Description | + * +=======+============+===============================+ + * | CLA | 0x80 | | + * +-------+------------+-------------------------------+ + * | INS | INS_WRITE | See :cpp:type:`SE05x_INS_t` | + * +-------+------------+-------------------------------+ + * | P1 | P1_CURVE | See :cpp:type:`SE05x_P1_t` | + * +-------+------------+-------------------------------+ + * | P2 | P2_CREATE | See :cpp:type:`SE05x_P2_t` | + * +-------+------------+-------------------------------+ + * | Lc | #(Payload) | | + * +-------+------------+-------------------------------+ + * | | TLV[TAG_1] | 1-byte curve identifier (from | + * | | | :cpp:type:`SE05x_ECCurve_t`). | + * +-------+------------+-------------------------------+ + * | Le | | | + * +-------+------------+-------------------------------+ + * @endrst + * + * # R-APDU Body + * + * NA + * + * # R-APDU Trailer + * + * @rst + * +-------------+--------------------------------+ + * | SW | Description | + * +=============+================================+ + * | SW_NO_ERROR | Data is returned successfully. | + * +-------------+--------------------------------+ + * @endrst + * + * + * + * @param[in] session_ctx Session Context [0:kSE05x_pSession] + * @param[in] curveID curve id [1:kSE05x_TAG_1] + */ +smStatus_t Se05x_API_CreateECCurve(pSe05xSession_t session_ctx, SE05x_ECCurve_t curveID); + +/** Se05x_API_DeleteECCurve + * + * Deletes an EC curve. + * + * # Command to Applet + * + * @rst + * +-------+------------------+-------------------------------+ + * | Field | Value | Description | + * +=======+==================+===============================+ + * | CLA | 0x80 | | + * +-------+------------------+-------------------------------+ + * | INS | INS_MGMT | See :cpp:type:`SE05x_INS_t` | + * +-------+------------------+-------------------------------+ + * | P1 | P1_CURVE | See :cpp:type:`SE05x_P1_t` | + * +-------+------------------+-------------------------------+ + * | P2 | P2_DELETE_OBJECT | See :cpp:type:`SE05x_P2_t` | + * +-------+------------------+-------------------------------+ + * | Lc | #(Payload) | | + * +-------+------------------+-------------------------------+ + * | | TLV[TAG_1] | 1-byte curve identifier (from | + * | | | :cpp:type:`SE05x_ECCurve_t`) | + * +-------+------------------+-------------------------------+ + * @endrst + * + * # R-APDU Body + * + * NA + * + * # R-APDU Trailer + * + * @rst + * +-------------+--------------------------------+ + * | SW | Description | + * +=============+================================+ + * | SW_NO_ERROR | Data is returned successfully. | + * +-------------+--------------------------------+ + * @endrst + * + * + * + * @param[in] session_ctx Session Context [0:kSE05x_pSession] + * @param[in] curveID curve id [1:kSE05x_TAG_1] + */ +smStatus_t Se05x_API_DeleteECCurve(pSe05xSession_t session_ctx, SE05x_ECCurve_t curveID); + +/** Se05x_API_SetECCurveParam + * + * Set a curve parameter. The curve must have been created first by + * CreateEcCurve. + * + * All parameters must match the expected value for the listed curves. If the + * curve parameters are not correct, the curve cannot be used. + * + * Users have to set all 5 curve parameters for the curve to be usable. Once all + * curve parameters are given, the secure element will check if all parameters + * are correct and return SW_NO_ERROR.. + * + * # Command to Applet + * + * @rst + * +-------+------------+----------------------------------------------+ + * | Field | Value | Description | + * +=======+============+==============================================+ + * | CLA | 0x80 | | + * +-------+------------+----------------------------------------------+ + * | INS | INS_WRITE | See :cpp:type:`SE05x_INS_t` | + * +-------+------------+----------------------------------------------+ + * | P1 | P1_CURVE | See :cpp:type:`SE05x_P1_t` | + * +-------+------------+----------------------------------------------+ + * | P2 | P2_PARAM | See :cpp:type:`SE05x_P2_t` | + * +-------+------------+----------------------------------------------+ + * | Lc | #(Payload) | | + * +-------+------------+----------------------------------------------+ + * | | TLV[TAG_1] | 1-byte curve identifier, from | + * | | | :cpp:type:`SE05x_ECCurve_t` | + * +-------+------------+----------------------------------------------+ + * | | TLV[TAG_2] | 1-byte :cpp:type:`SE05x_ECCurveParam_t` | + * +-------+------------+----------------------------------------------+ + * | | TLV[TAG_3] | Bytestring containing curve parameter value. | + * +-------+------------+----------------------------------------------+ + * @endrst + * + * # R-APDU Body + * + * NA + * + * # R-APDU Trailer + * + * @rst + * +-------------+--------------------------------+ + * | SW | Description | + * +=============+================================+ + * | SW_NO_ERROR | Data is returned successfully. | + * +-------------+--------------------------------+ + * @endrst + * + * + * + * @param[in] session_ctx Session Context [0:kSE05x_pSession] + * @param[in] curveID curve id [1:kSE05x_TAG_1] + * @param[in] ecCurveParam ecCurveParam [2:kSE05x_TAG_2] + * @param[in] inputData inputData [3:kSE05x_TAG_3] + * @param[in] inputDataLen Length of inputData + */ +smStatus_t Se05x_API_SetECCurveParam(pSe05xSession_t session_ctx, + SE05x_ECCurve_t curveID, + SE05x_ECCurveParam_t ecCurveParam, + const uint8_t *inputData, + size_t inputDataLen); + +/** Se05x_API_ReadECCurveList + * + * Get a list of (Weierstrass) EC curves that are instantiated. + * + * + * # Command to Applet + * + * @rst + * +-------+----------+-----------------------------+ + * | Field | Value | Description | + * +=======+==========+=============================+ + * | CLA | 0x80 | | + * +-------+----------+-----------------------------+ + * | INS | INS_READ | See :cpp:type:`SE05x_INS_t` | + * +-------+----------+-----------------------------+ + * | P1 | P1_CURVE | See :cpp:type:`SE05x_P1_t` | + * +-------+----------+-----------------------------+ + * | P2 | P2_LIST | See :cpp:type:`SE05x_P2_t` | + * +-------+----------+-----------------------------+ + * | Le | 0x00 | | + * +-------+----------+-----------------------------+ + * @endrst + * + * # R-APDU Body + * + * @rst + * +------------+------------------------------------------------+ + * | Value | Description | + * +============+================================================+ + * | TLV[TAG_1] | Byte array listing all curve identifiers in | + * | | :cpp:type:`SE05x_ECCurve_t` (excluding UNUSED) | + * | | where the curve identifier < 0x40; for each | + * | | curve, a 1-byte :cpp:type:`SetIndicatorRef` is | + * | | returned. | + * +------------+------------------------------------------------+ + * @endrst + * + * # R-APDU Trailer + * + * @rst + * +-------------+--------------------------------+ + * | SW | Description | + * +=============+================================+ + * | SW_NO_ERROR | Data is returned successfully. | + * +-------------+--------------------------------+ + * @endrst + * + * + * + * @param[in] session_ctx Session Context [0:kSE05x_pSession] + * @param[out] curveList [0:kSE05x_TAG_1] + * @param[in,out] pcurveListLen Length for curveList + */ +smStatus_t Se05x_API_ReadECCurveList(pSe05xSession_t session_ctx, uint8_t *curveList, size_t *pcurveListLen); + +/** Se05x_API_ReadObject_W_Attst + * + * Read with attestation + * + * See @ref Se05x_API_ReadObject_W_Attst + * + * When INS_ATTEST is set in addition to INS_READ, the secure object is read with + * attestation. In addition to the response in TLV[TAG_1], there are additional + * tags: + * + * TLV[TAG_2] will hold the object attributes (see ObjectAttributes). + * + * TLV[TAG_3] relative timestamp when the object has been retrieved + * + * TLV[TAG_4] will hold freshness random data + * + * TLV[TAG_5] will hold the unique ID of the device. + * + * TLV[TAG_6] will hold the signature over all concatenated Value fields tags of + * the response (TAG_1 until and including TAG_5). + * + * # Command to Applet + * + * @rst + * +-------+------------+----------------------------------------------+ + * | Field | Value | Description | + * +=======+============+==============================================+ + * | CLA | 0x80 | | + * +-------+------------+----------------------------------------------+ + * | INS | INS_READ | See :cpp:type:`SE05x_INS_t`, in addition to | + * | | | INS_READ, users can set the INS_ATTEST flag. | + * | | | In that case, attestation applies. | + * +-------+------------+----------------------------------------------+ + * | P1 | P1_DEFAULT | See :cpp:type:`SE05x_P1_t` | + * +-------+------------+----------------------------------------------+ + * | P2 | P2_DEFAULT | See :cpp:type:`SE05x_P2_t` | + * +-------+------------+----------------------------------------------+ + * | Lc | #(Payload) | Payload Length. | + * +-------+------------+----------------------------------------------+ + * | | TLV[TAG_1] | 4-byte object identifier | + * +-------+------------+----------------------------------------------+ + * | | TLV[TAG_2] | 2-byte offset [Optional: default 0] | + * | | | [Conditional: only when the object is a | + * | | | BinaryFile object] | + * +-------+------------+----------------------------------------------+ + * | | TLV[TAG_3] | 2-byte length [Optional: default 0] | + * | | | [Conditional: only when the object is a | + * | | | BinaryFile object] | + * +-------+------------+----------------------------------------------+ + * | | TLV[TAG_4] | 1-byte :cpp:type:`SE05x_RSAKeyComponent_t`: | + * | | | either RSA_COMP_MOD or RSA_COMP_PUB_EXP. | + * | | | [Optional] [Conditional: only for RSA key | + * | | | components] | + * +-------+------------+----------------------------------------------+ + * | | TLV[TAG_5] | 4-byte attestation object identifier. | + * | | | [Optional] [Conditional: only when | + * | | | INS_ATTEST is set] | + * +-------+------------+----------------------------------------------+ + * | | TLV[TAG_6] | 1-byte :cpp:type:`SE05x_AttestationAlgo_t` | + * | | | [Optional] [Conditional: only when | + * | | | INS_ATTEST is set] | + * +-------+------------+----------------------------------------------+ + * | | TLV[TAG_7] | 16-byte freshness random [Optional] | + * | | | [Conditional: only when INS_ATTEST is set] | + * +-------+------------+----------------------------------------------+ + * | Le | 0x00 | | + * +-------+------------+----------------------------------------------+ + * @endrst + * + * + * @param[in] session_ctx The session context + * @param[in] objectID The object id + * @param[in] offset The offset + * @param[in] length The length + * @param[in] attestID The attest id + * @param[in] attestAlgo The attest algorithm + * @param[in] random The random + * @param[in] randomLen The random length + * @param pCmd The pointer to command buffer + * @param pCmdLen The length of Command Buffer + * @param pRspBuf The Response Buffer + * @param pRspBufLen The length of response Buffer + * + * @return The sm status. + */ +smStatus_t Se05x_API_ReadObject_W_Attst(pSe05xSession_t session_ctx, + uint32_t objectID, + uint16_t offset, + uint16_t length, + uint32_t attestID, + SE05x_AttestationAlgo_t attestAlgo, + const uint8_t *random, + size_t randomLen, + uint8_t *pCmdapdu, + size_t *pCmdapduLen, + uint8_t *pRspBuf, + size_t *pRspBufLen); + +/** Se05x_API_PBKDF2_extended + * + * Password Based Key Derivation Function 2 (PBKDF2) according [RFC8018]. + * + * The password is an input to the KDF and must be stored inside the . + * + * The output is returned to the host. + * + * + * # Command to Applet + * + * @rst + * +-------+------------+----------------------------------------------+ + * | Field | Value | Description | + * +=======+============+==============================================+ + * | CLA | 0x80 | | + * +-------+------------+----------------------------------------------+ + * | INS | INS_CRYPTO | :cpp:type:`SE05x_INS_t` | + * +-------+------------+----------------------------------------------+ + * | P1 | P1_DEFAULT | See :cpp:type:`SE05x_P1_t` | + * +-------+------------+----------------------------------------------+ + * | P2 | P2_PBKDF | See :cpp:type:`SE05x_P2_t` | + * +-------+------------+----------------------------------------------+ + * | Lc | #(Payload) | | + * +-------+------------+----------------------------------------------+ + * | | TLV[TAG_1] | 4-byte password identifier (object type must | + * | | | be HMACKey) | + * +-------+------------+----------------------------------------------+ + * | | TLV[TAG_2] | Salt (0 to 64 bytes) [Optional] | + * +-------+------------+----------------------------------------------+ + * | | TLV[TAG_3] | 2-byte Iteration count: 1 up to 0x7FFF. | + * +-------+------------+----------------------------------------------+ + * | | TLV[TAG_4] | 2-byte Requested length: 1 up to 512 bytes. | + * +-------+------------+----------------------------------------------+ + * | | TLV[TAG_5] | 1-byte MACAlgo | + * +-------+------------+----------------------------------------------+ + * | | TLV[TAG_6] | 4-byte HMACKey identifier containing salt. | + * +-------+------------+----------------------------------------------+ + * | | TLV[TAG_7] | 4-byte identifier of the target Secure Object| + * +-------+------------+----------------------------------------------+ + * | Le | 0x00 | Expecting derived key material. | + * +-------+------------+----------------------------------------------+ + * @endrst + * + * # R-APDU Body + * + * @rst + * +------------+-------------------------------------+ + * | Value | Description | + * +============+=====================================+ + * | TLV[TAG_1] | Derived key material (session key). | + * +------------+-------------------------------------+ + * @endrst + * + * # R-APDU Trailer + * + * @rst + * +-------------+--------------------------------------+ + * | SW | Description | + * +=============+======================================+ + * | SW_NO_ERROR | The command is handled successfully. | + * +-------------+--------------------------------------+ + * @endrst + * + * + * + * @param[in] session_ctx The session context + * @param[in] objectID HMAC key object id + * @para m[in] salt Salt data + * @param[in] saltLen Salt length + * @param[in] saltID Object id with salt data + * @param[in] count Iteration count + * @param[in] macAlgo MAC Algorithm + * @param[in] requestedLen Requested derived session key length + * @param[in, out] derivedSessionKeyID HMAC object id to store output derived session key + * @param[in, out] derivedSessionKey Buffer to store derived session key on host + * @param[in, out] pderivedSessionKeyLen DerivedSessionKey buffer length + */ +smStatus_t Se05x_API_PBKDF2_extended(pSe05xSession_t session_ctx, + uint32_t objectID, + const uint8_t *salt, + size_t saltLen, + uint32_t saltID, + uint16_t count, + SE05x_MACAlgo_t macAlgo, + uint16_t requestedLen, + uint32_t derivedSessionKeyID, + uint8_t *derivedSessionKey, + size_t *pderivedSessionKeyLen); + +#endif //#ifndef SE05X_APDU_APIS_H_INC diff --git a/src/lib/apdu/se05x_APDU_impl.c b/src/lib/apdu/se05x_APDU_impl.c new file mode 100644 index 0000000..8e5b026 --- /dev/null +++ b/src/lib/apdu/se05x_APDU_impl.c @@ -0,0 +1,1208 @@ +/** @file se05x_APDU_impl.c + * @brief Se05x APDU function implementation. + * + * Copyright 2021,2022,2024,2026 NXP + * SPDX-License-Identifier: Apache-2.0 + */ + +/* ********************** Include files ********************** */ +#include "smCom.h" +#include "lib/platform/arduino/sm_port.h" +#include "lib/apdu/se05x_types.h" +#include "lib/t1oi2c/phNxpEse_Api.h" +#include + +/* ********************** Defines ********************** */ +#define kSE05x_CLA 0x80 +#define CLA_ISO7816 (0x00) //!< ISO7816-4 defined CLA byte +#define INS_GP_SELECT (0xA4) //!< Global platform defined instruction + +/* clang-format off */ +#define APPLET_NAME { 0xa0, 0x00, 0x00, 0x03, 0x96, 0x54, 0x53, 0x00, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00, 0x00, 0x00 } +#define SSD_NAME {0xD2, 0x76, 0x00, 0x00, 0x85, 0x30, 0x4A, 0x43, 0x4F, 0x90, 0x03} +/* clang-format on */ + +/* ********************** Function Prototypes ********************** */ +#if defined(WITH_PLATFORM_SCP03) || defined(WITH_ECKEY_SCP03_SESSION) +smStatus_t Se05x_API_SCP03_CreateSession(pSe05xSession_t session_ctx); +#endif //#if defined(WITH_ECKEY_SESSION) || defined(WITH_ECKEY_SCP03_SESSION) + +#if defined(WITH_ECKEY_SESSION) || defined(WITH_ECKEY_SCP03_SESSION) +smStatus_t Se05x_API_ECKey_CreateSession(pSe05xSession_t session_ctx); +smStatus_t Se05x_API_ECKey_CloseSession(pSe05xSession_t session_ctx); +#endif //#if defined(WITH_ECKEY_SESSION) || defined(WITH_ECKEY_SCP03_SESSION) + +/* ********************** Functions ********************** */ + +bool Se05x_IsInValidRangeOfUID(uint32_t uid) +{ + // Block required keyids + (void)uid; + return FALSE; +} + +smStatus_t Se05x_API_SessionOpen(pSe05xSession_t session_ctx) +{ + size_t buff_len = 0; + size_t tx_len = 0; + smStatus_t ret = SM_NOT_OK; + unsigned char appletName[] = APPLET_NAME; +#if defined(WITH_PLATFORM_SCP03) + unsigned char ssdName[] = SSD_NAME; +#endif + unsigned char *appSsdName = NULL; + size_t appSsdNameLen = 0; + + SMLOG_I("Plug and Trust nano package - version: %d.%d.%d \n", VERSION_MAJOR, VERSION_MINOR, VERSION_DEV); + + ENSURE_OR_GO_CLEANUP(session_ctx != NULL); + + buff_len = sizeof(session_ctx->apdu_buffer); + + ret = smComT1oI2C_Init(&session_ctx->conn_context, NULL); + ENSURE_OR_GO_CLEANUP(SM_OK == ret); + + if (session_ctx->session_resume == 1) { + ret = smComT1oI2C_Open(session_ctx->conn_context, ESE_MODE_RESUME, 0x00, session_ctx->apdu_buffer, &buff_len); + } + else { + ret = smComT1oI2C_Open(session_ctx->conn_context, ESE_MODE_NORMAL, 0x00, session_ctx->apdu_buffer, &buff_len); + } + ENSURE_OR_GO_CLEANUP(SM_OK == ret); + + if (session_ctx->skip_applet_select == 1) { +#if !defined(WITH_PLATFORM_SCP03) + return ret; +#else + appSsdName = &ssdName[0]; + appSsdNameLen = sizeof(ssdName); +#endif + } + else { + appSsdName = &appletName[0]; + appSsdNameLen = sizeof(appletName); + } + + if (!session_ctx->session_resume) { + /* Select applet / ssd */ + session_ctx->apdu_buffer[0] = CLA_ISO7816; + session_ctx->apdu_buffer[1] = INS_GP_SELECT; + session_ctx->apdu_buffer[2] = 4; + session_ctx->apdu_buffer[3] = 0; + + tx_len = 1 /* CLA */ + 1 /* INS */ + 1 /* P1 */ + 1 /* P2 */; + + session_ctx->apdu_buffer[4] = appSsdNameLen; + tx_len = tx_len + 1 /* Lc */ + appSsdNameLen /* Payload */ + 1 /* Le */; + memcpy(&session_ctx->apdu_buffer[5], appSsdName, appSsdNameLen); + session_ctx->apdu_buffer[tx_len - 1] = 0; /* Le */ + + buff_len = sizeof(session_ctx->apdu_buffer); + ret = smComT1oI2C_TransceiveRaw( + session_ctx->conn_context, session_ctx->apdu_buffer, tx_len, session_ctx->apdu_buffer, &buff_len); + if (ret != SM_OK) { + SMLOG_E("Se05x_API_SessionOpen failed"); + goto cleanup; + } + session_ctx->applet_version = (session_ctx->apdu_buffer[0] << 24) | (session_ctx->apdu_buffer[1] << 16) | + (session_ctx->apdu_buffer[2] << 8) | session_ctx->apdu_buffer[3]; + if (ret == SM_OK && buff_len >= 2) { + ret = session_ctx->apdu_buffer[buff_len - 2]; + ret <<= 8; + ret |= session_ctx->apdu_buffer[buff_len - 1]; + } + ENSURE_OR_GO_CLEANUP(SM_OK == ret); + } + +#if defined(WITH_PLATFORM_SCP03) + + if (session_ctx->session_resume) { + SMLOG_I("Resuming Secure Channel to SE05x !\n"); + } + else { + SMLOG_I("Establish Secure Channel to SE05x !\n"); + ret = Se05x_API_SCP03_CreateSession(session_ctx); + if (ret == SM_OK) { + SMLOG_I("Created scp03 Session\n"); + } + } + +#elif defined(WITH_ECKEY_SESSION) + + ret = Se05x_API_ECKey_CreateSession(session_ctx); + if (ret == SM_OK) { + SMLOG_I("Created ECKey Session\n"); + } + +#elif defined(WITH_ECKEY_SCP03_SESSION) + + if (session_ctx->session_resume) { + SMLOG_I("Resuming Secure Channel to SE05x !\n"); + } + else { + SMLOG_I("Establish Secure Channel to SE05x !\n"); + ret = Se05x_API_SCP03_CreateSession(session_ctx); + if (ret == SM_OK) { + SMLOG_I("Created scp03 Session\n"); + } + else { + goto cleanup; + } + } + + ret = Se05x_API_ECKey_CreateSession(session_ctx); + if (ret == SM_OK) { + SMLOG_I("Created ECKey Session\n"); + } + +#endif + +cleanup: + if (ret != SM_OK) { + if (session_ctx != NULL) { + memset(session_ctx, 0, sizeof(Se05xSession_t)); + } + } + return ret; +} + +smStatus_t Se05x_API_SessionClose(pSe05xSession_t session_ctx) +{ + smStatus_t retStatus = SM_NOT_OK; +#if defined(WITH_ECKEY_SESSION) || defined(WITH_ECKEY_SCP03_SESSION) + tlvHeader_t hdr = {{kSE05x_CLA, kSE05x_INS_MGMT, kSE05x_P1_DEFAULT, kSE05x_P2_SESSION_CLOSE}}; +#endif + + ENSURE_OR_GO_CLEANUP(session_ctx != NULL); + + SMLOG_D("APDU - Se05x_API_SessionClose [] \n"); + +#if defined(WITH_ECKEY_SESSION) || defined(WITH_ECKEY_SCP03_SESSION) + if (session_ctx->ecKey_session == 1) { + retStatus = DoAPDUTx(session_ctx, &hdr, session_ctx->apdu_buffer, 0, 0); + ENSURE_OR_GO_CLEANUP(retStatus == SM_OK); + } + + Se05x_API_ECKey_CloseSession(session_ctx); +#endif + +#if defined(WITH_PLATFORM_SCP03) || defined(WITH_ECKEY_SCP03_SESSION) + //Se05x_API_SCP03_CloseSession(session_ctx); +#endif + + retStatus = smComT1oI2C_Close(session_ctx->conn_context, 0); + ENSURE_OR_GO_CLEANUP(retStatus == SM_OK); + + if (session_ctx != NULL) { + memset(session_ctx, 0, sizeof(Se05xSession_t)); + } + +cleanup: + return retStatus; +} + +smStatus_t Se05x_API_WriteECKey(pSe05xSession_t session_ctx, + pSe05xPolicy_t policy, + SE05x_MaxAttemps_t maxAttempt, + uint32_t objectID, + SE05x_ECCurve_t curveID, + const uint8_t *privKey, + size_t privKeyLen, + const uint8_t *pubKey, + size_t pubKeyLen, + const SE05x_INS_t ins_type, + const SE05x_KeyPart_t key_part) +{ + smStatus_t retStatus = SM_NOT_OK; + tlvHeader_t hdr = {{kSE05x_CLA, kSE05x_INS_WRITE | ins_type, kSE05x_P1_EC | key_part, kSE05x_P2_DEFAULT}}; + size_t cmdbufLen = 0; + uint8_t *pCmdbuf = NULL; + int tlvRet = 0; + + ENSURE_OR_GO_CLEANUP(session_ctx != NULL); + + pCmdbuf = &session_ctx->apdu_buffer[0]; + + if (Se05x_IsInValidRangeOfUID(objectID)) { + return SM_NOT_OK; + } + + SMLOG_D("APDU - WriteECKey [] \n"); + + tlvRet = TLVSET_Se05xPolicy("policy", &pCmdbuf, &cmdbufLen, kSE05x_TAG_POLICY, policy); + if (0 != tlvRet) { + goto cleanup; + } + tlvRet = TLVSET_MaxAttemps("maxAttempt", &pCmdbuf, &cmdbufLen, kSE05x_TAG_MAX_ATTEMPTS, maxAttempt); + if (0 != tlvRet) { + goto cleanup; + } + tlvRet = TLVSET_U32("object id", &pCmdbuf, &cmdbufLen, kSE05x_TAG_1, objectID); + if (0 != tlvRet) { + goto cleanup; + } + tlvRet = TLVSET_ECCurve("curveID", &pCmdbuf, &cmdbufLen, kSE05x_TAG_2, curveID); + if (0 != tlvRet) { + goto cleanup; + } + tlvRet = TLVSET_u8bufOptional("privKey", &pCmdbuf, &cmdbufLen, kSE05x_TAG_3, privKey, privKeyLen); + if (0 != tlvRet) { + goto cleanup; + } + tlvRet = TLVSET_u8bufOptional("pubKey", &pCmdbuf, &cmdbufLen, kSE05x_TAG_4, pubKey, pubKeyLen); + if (0 != tlvRet) { + goto cleanup; + } + + retStatus = DoAPDUTx(session_ctx, &hdr, session_ctx->apdu_buffer, cmdbufLen, 0); + +cleanup: + return retStatus; +} + +smStatus_t Se05x_API_ReadObject( + pSe05xSession_t session_ctx, uint32_t objectID, uint16_t offset, uint16_t length, uint8_t *data, size_t *pdataLen) +{ + smStatus_t retStatus = SM_NOT_OK; + tlvHeader_t hdr = {{kSE05x_CLA, kSE05x_INS_READ, kSE05x_P1_DEFAULT, kSE05x_P2_DEFAULT}}; + size_t cmdbufLen = 0; + uint8_t *pCmdbuf = NULL; + int tlvRet = 0; + uint8_t *pRspbuf = NULL; + size_t rspbufLen = 0; + + ENSURE_OR_GO_CLEANUP(session_ctx != NULL); + + pCmdbuf = &session_ctx->apdu_buffer[0]; + pRspbuf = &session_ctx->apdu_buffer[0]; + rspbufLen = sizeof(session_ctx->apdu_buffer); + + SMLOG_D("APDU - ReadObject [] \n"); + + tlvRet = TLVSET_U32("object id", &pCmdbuf, &cmdbufLen, kSE05x_TAG_1, objectID); + if (0 != tlvRet) { + goto cleanup; + } + tlvRet = TLVSET_U16Optional("offset", &pCmdbuf, &cmdbufLen, kSE05x_TAG_2, offset); + if (0 != tlvRet) { + goto cleanup; + } + tlvRet = TLVSET_U16Optional("length", &pCmdbuf, &cmdbufLen, kSE05x_TAG_3, length); + if (0 != tlvRet) { + goto cleanup; + } + retStatus = DoAPDUTxRx(session_ctx, &hdr, session_ctx->apdu_buffer, cmdbufLen, pRspbuf, &rspbufLen, 1); + if (retStatus == SM_OK) { + retStatus = SM_NOT_OK; + size_t rspIndex = 0; + tlvRet = tlvGet_u8buf(pRspbuf, &rspIndex, rspbufLen, kSE05x_TAG_1, data, pdataLen); /* */ + if (0 != tlvRet) { + goto cleanup; + } + if ((rspIndex + 2) == rspbufLen) { + retStatus = (pRspbuf[rspIndex] << 8) | (pRspbuf[rspIndex + 1]); + } + } + + if (retStatus == SM_ERR_ACCESS_DENIED_BASED_ON_POLICY) { + SMLOG_I("Denied to read object %08X bases on policy.", objectID); + } + +cleanup: + return retStatus; +} + +smStatus_t Se05x_API_GetVersion(pSe05xSession_t session_ctx, uint8_t *pappletVersion, size_t *appletVersionLen) +{ + smStatus_t retStatus = SM_NOT_OK; + tlvHeader_t hdr = {{kSE05x_CLA, kSE05x_INS_MGMT, kSE05x_P1_DEFAULT, kSE05x_P2_VERSION}}; + int tlvRet = 0; + uint8_t *pRspbuf = NULL; + size_t rspbufLen = 0; + + ENSURE_OR_GO_CLEANUP(session_ctx != NULL); + + pRspbuf = &session_ctx->apdu_buffer[0]; + rspbufLen = sizeof(session_ctx->apdu_buffer); + + SMLOG_D("APDU - GetVersion [] \n"); + + retStatus = DoAPDUTxRx(session_ctx, &hdr, session_ctx->apdu_buffer, 0, pRspbuf, &rspbufLen, 0); + if (retStatus == SM_OK) { + retStatus = SM_NOT_OK; + size_t rspIndex = 0; + tlvRet = tlvGet_u8buf(pRspbuf, &rspIndex, rspbufLen, kSE05x_TAG_1, pappletVersion, appletVersionLen); + if (0 != tlvRet) { + goto cleanup; + } + if ((rspIndex + 2) == rspbufLen) { + retStatus = (pRspbuf[rspIndex] << 8) | (pRspbuf[rspIndex + 1]); + } + } + +cleanup: + return retStatus; +} + +smStatus_t Se05x_API_ECDSASign(pSe05xSession_t session_ctx, + uint32_t objectID, + SE05x_ECSignatureAlgo_t ecSignAlgo, + const uint8_t *inputData, + size_t inputDataLen, + uint8_t *signature, + size_t *psignatureLen) +{ + smStatus_t retStatus = SM_NOT_OK; + tlvHeader_t hdr = {{kSE05x_CLA, kSE05x_INS_CRYPTO, kSE05x_P1_SIGNATURE, kSE05x_P2_SIGN}}; + size_t cmdbufLen = 0; + uint8_t *pCmdbuf = NULL; + int tlvRet = 0; + uint8_t *pRspbuf = NULL; + size_t rspbufLen = 0; + + ENSURE_OR_GO_CLEANUP(session_ctx != NULL); + + pCmdbuf = &session_ctx->apdu_buffer[0]; + pRspbuf = &session_ctx->apdu_buffer[0]; + rspbufLen = sizeof(session_ctx->apdu_buffer); + + SMLOG_D("APDU - ECDSASign [] \n"); + + tlvRet = TLVSET_U32("objectID", &pCmdbuf, &cmdbufLen, kSE05x_TAG_1, objectID); + if (0 != tlvRet) { + goto cleanup; + } + tlvRet = TLVSET_ECSignatureAlgo("ecSignAlgo", &pCmdbuf, &cmdbufLen, kSE05x_TAG_2, ecSignAlgo); + if (0 != tlvRet) { + goto cleanup; + } + tlvRet = TLVSET_u8bufOptional("inputData", &pCmdbuf, &cmdbufLen, kSE05x_TAG_3, inputData, inputDataLen); + if (0 != tlvRet) { + goto cleanup; + } + retStatus = DoAPDUTxRx(session_ctx, &hdr, session_ctx->apdu_buffer, cmdbufLen, pRspbuf, &rspbufLen, 0); + if (retStatus == SM_OK) { + retStatus = SM_NOT_OK; + size_t rspIndex = 0; + tlvRet = tlvGet_u8buf(pRspbuf, &rspIndex, rspbufLen, kSE05x_TAG_1, signature, psignatureLen); /* */ + if (0 != tlvRet) { + goto cleanup; + } + if ((rspIndex + 2) == rspbufLen) { + retStatus = (pRspbuf[rspIndex] << 8) | (pRspbuf[rspIndex + 1]); + } + } + +cleanup: + return retStatus; +} + +smStatus_t Se05x_API_ECDSAVerify(pSe05xSession_t session_ctx, + uint32_t objectID, + SE05x_ECSignatureAlgo_t ecSignAlgo, + const uint8_t *inputData, + size_t inputDataLen, + const uint8_t *signature, + size_t signatureLen, + SE05x_Result_t *presult) +{ + smStatus_t retStatus = SM_NOT_OK; + tlvHeader_t hdr = {{kSE05x_CLA, kSE05x_INS_CRYPTO, kSE05x_P1_SIGNATURE, kSE05x_P2_VERIFY}}; + size_t cmdbufLen = 0; + uint8_t *pCmdbuf = NULL; + int tlvRet = 0; + uint8_t *pRspbuf = NULL; + size_t rspbufLen = 0; + + ENSURE_OR_GO_CLEANUP(session_ctx != NULL); + + pCmdbuf = &session_ctx->apdu_buffer[0]; + pRspbuf = &session_ctx->apdu_buffer[0]; + rspbufLen = sizeof(session_ctx->apdu_buffer); + + SMLOG_D("APDU - ECDSAVerify [] \n"); + + tlvRet = TLVSET_U32("objectID", &pCmdbuf, &cmdbufLen, kSE05x_TAG_1, objectID); + if (0 != tlvRet) { + goto cleanup; + } + tlvRet = TLVSET_ECSignatureAlgo("ecSignAlgo", &pCmdbuf, &cmdbufLen, kSE05x_TAG_2, ecSignAlgo); + if (0 != tlvRet) { + goto cleanup; + } + tlvRet = TLVSET_u8bufOptional("inputData", &pCmdbuf, &cmdbufLen, kSE05x_TAG_3, inputData, inputDataLen); + if (0 != tlvRet) { + goto cleanup; + } + tlvRet = TLVSET_u8bufOptional("signature", &pCmdbuf, &cmdbufLen, kSE05x_TAG_5, signature, signatureLen); + if (0 != tlvRet) { + goto cleanup; + } + retStatus = DoAPDUTxRx(session_ctx, &hdr, session_ctx->apdu_buffer, cmdbufLen, pRspbuf, &rspbufLen, 0); + if (retStatus == SM_OK) { + retStatus = SM_NOT_OK; + size_t rspIndex = 0; + tlvRet = tlvGet_Result(pRspbuf, &rspIndex, rspbufLen, kSE05x_TAG_1, presult); /* - */ + if (0 != tlvRet) { + goto cleanup; + } + if ((rspIndex + 2) == rspbufLen) { + retStatus = (pRspbuf[rspIndex] << 8) | (pRspbuf[rspIndex + 1]); + } + } + +cleanup: + return retStatus; +} + +smStatus_t Se05x_API_CheckObjectExists(pSe05xSession_t session_ctx, uint32_t objectID, SE05x_Result_t *presult) +{ + smStatus_t retStatus = SM_NOT_OK; + tlvHeader_t hdr = {{kSE05x_CLA, kSE05x_INS_MGMT, kSE05x_P1_DEFAULT, kSE05x_P2_EXIST}}; + size_t cmdbufLen = 0; + uint8_t *pCmdbuf = NULL; + int tlvRet = 0; + uint8_t *pRspbuf = NULL; + size_t rspbufLen = 0; + + ENSURE_OR_GO_CLEANUP(session_ctx != NULL); + + pCmdbuf = &session_ctx->apdu_buffer[0]; + pRspbuf = &session_ctx->apdu_buffer[0]; + rspbufLen = sizeof(session_ctx->apdu_buffer); + + SMLOG_D("APDU - CheckObjectExists [] \n"); + + tlvRet = TLVSET_U32("object id", &pCmdbuf, &cmdbufLen, kSE05x_TAG_1, objectID); + if (0 != tlvRet) { + goto cleanup; + } + retStatus = DoAPDUTxRx(session_ctx, &hdr, session_ctx->apdu_buffer, cmdbufLen, pRspbuf, &rspbufLen, 0); + if (retStatus == SM_OK) { + retStatus = SM_NOT_OK; + size_t rspIndex = 0; + tlvRet = tlvGet_Result(pRspbuf, &rspIndex, rspbufLen, kSE05x_TAG_1, presult); /* - */ + if (0 != tlvRet) { + goto cleanup; + } + if ((rspIndex + 2) == rspbufLen) { + retStatus = (pRspbuf[rspIndex] << 8) | (pRspbuf[rspIndex + 1]); + } + } + +cleanup: + return retStatus; +} + +smStatus_t Se05x_API_WriteBinary(pSe05xSession_t session_ctx, + pSe05xPolicy_t policy, + uint32_t objectID, + uint16_t offset, + uint16_t length, + const uint8_t *inputData, + size_t inputDataLen) +{ + smStatus_t retStatus = SM_NOT_OK; + tlvHeader_t hdr = {{kSE05x_CLA, kSE05x_INS_WRITE, kSE05x_P1_BINARY, kSE05x_P2_DEFAULT}}; + size_t cmdbufLen = 0; + uint8_t *pCmdbuf = NULL; + int tlvRet = 0; + + ENSURE_OR_GO_CLEANUP(session_ctx != NULL); + + pCmdbuf = &session_ctx->apdu_buffer[0]; + + if (Se05x_IsInValidRangeOfUID(objectID)) { + return SM_NOT_OK; + } + + SMLOG_D("APDU - WriteBinary [] \n"); + + tlvRet = TLVSET_Se05xPolicy("policy", &pCmdbuf, &cmdbufLen, kSE05x_TAG_POLICY, policy); + if (0 != tlvRet) { + goto cleanup; + } + tlvRet = TLVSET_U32("object id", &pCmdbuf, &cmdbufLen, kSE05x_TAG_1, objectID); + if (0 != tlvRet) { + goto cleanup; + } + tlvRet = TLVSET_U16Optional("offset", &pCmdbuf, &cmdbufLen, kSE05x_TAG_2, offset); + if (0 != tlvRet) { + goto cleanup; + } + tlvRet = TLVSET_U16Optional("length", &pCmdbuf, &cmdbufLen, kSE05x_TAG_3, length); + if (0 != tlvRet) { + goto cleanup; + } + tlvRet = TLVSET_u8bufOptional("input data", &pCmdbuf, &cmdbufLen, kSE05x_TAG_4, inputData, inputDataLen); + if (0 != tlvRet) { + goto cleanup; + } + retStatus = DoAPDUTx(session_ctx, &hdr, session_ctx->apdu_buffer, cmdbufLen, 0); + +cleanup: + return retStatus; +} + +smStatus_t Se05x_API_ECDHGenerateSharedSecret(pSe05xSession_t session_ctx, + uint32_t objectID, + const uint8_t *pubKey, + size_t pubKeyLen, + uint8_t *sharedSecret, + size_t *psharedSecretLen) +{ + smStatus_t retStatus = SM_NOT_OK; + tlvHeader_t hdr = {{kSE05x_CLA, kSE05x_INS_CRYPTO, kSE05x_P1_EC, kSE05x_P2_DH}}; + size_t cmdbufLen = 0; + uint8_t *pCmdbuf = NULL; + int tlvRet = 0; + uint8_t *pRspbuf = NULL; + size_t rspbufLen = 0; + + ENSURE_OR_GO_CLEANUP(session_ctx != NULL); + + pCmdbuf = &session_ctx->apdu_buffer[0]; + pRspbuf = &session_ctx->apdu_buffer[0]; + rspbufLen = sizeof(session_ctx->apdu_buffer); + + SMLOG_D("APDU -ECDHGenerateSharedSecret [] \n"); + + tlvRet = TLVSET_U32("objectID", &pCmdbuf, &cmdbufLen, kSE05x_TAG_1, objectID); + if (0 != tlvRet) { + goto cleanup; + } + tlvRet = TLVSET_u8bufOptional("pubKey", &pCmdbuf, &cmdbufLen, kSE05x_TAG_2, pubKey, pubKeyLen); + if (0 != tlvRet) { + goto cleanup; + } + retStatus = DoAPDUTxRx(session_ctx, &hdr, session_ctx->apdu_buffer, cmdbufLen, pRspbuf, &rspbufLen, 0); + if (retStatus == SM_OK) { + retStatus = SM_NOT_OK; + size_t rspIndex = 0; + tlvRet = tlvGet_u8buf(pRspbuf, &rspIndex, rspbufLen, kSE05x_TAG_1, sharedSecret, psharedSecretLen); /* */ + if (0 != tlvRet) { + goto cleanup; + } + if ((rspIndex + 2) == rspbufLen) { + retStatus = (pRspbuf[rspIndex] << 8) | (pRspbuf[rspIndex + 1]); + } + } + +cleanup: + return retStatus; +} + +smStatus_t Se05x_API_CipherOneShot(pSe05xSession_t session_ctx, + uint32_t objectID, + SE05x_CipherMode_t cipherMode, + const uint8_t *inputData, + size_t inputDataLen, + uint8_t *IV, + size_t IVLen, + uint8_t *outputData, + size_t *poutputDataLen, + const SE05x_Cipher_Oper_OneShot_t operation) +{ + smStatus_t retStatus = SM_NOT_OK; + tlvHeader_t hdr = {{kSE05x_CLA, kSE05x_INS_CRYPTO, kSE05x_P1_CIPHER, operation}}; + size_t cmdbufLen = 0; + uint8_t *pCmdbuf = NULL; + int tlvRet = 0; + uint8_t *pRspbuf = NULL; + size_t rspbufLen = 0; + + ENSURE_OR_GO_CLEANUP(session_ctx != NULL); + + pCmdbuf = &session_ctx->apdu_buffer[0]; + pRspbuf = &session_ctx->apdu_buffer[0]; + rspbufLen = sizeof(session_ctx->apdu_buffer); + + SMLOG_D("APDU - CipherOneShot [] \n"); + + tlvRet = TLVSET_U32("objectID", &pCmdbuf, &cmdbufLen, kSE05x_TAG_1, objectID); + if (0 != tlvRet) { + goto cleanup; + } + tlvRet = TLVSET_CipherMode("cipherMode", &pCmdbuf, &cmdbufLen, kSE05x_TAG_2, cipherMode); + if (0 != tlvRet) { + goto cleanup; + } + tlvRet = TLVSET_u8bufOptional("inputData", &pCmdbuf, &cmdbufLen, kSE05x_TAG_3, inputData, inputDataLen); + if (0 != tlvRet) { + goto cleanup; + } + tlvRet = TLVSET_u8bufOptional("IV", &pCmdbuf, &cmdbufLen, kSE05x_TAG_4, IV, IVLen); + if (0 != tlvRet) { + goto cleanup; + } + + retStatus = DoAPDUTxRx(session_ctx, &hdr, session_ctx->apdu_buffer, cmdbufLen, pRspbuf, &rspbufLen, 0); + if (retStatus == SM_OK) { + retStatus = SM_NOT_OK; + size_t rspIndex = 0; + tlvRet = tlvGet_u8buf(pRspbuf, &rspIndex, rspbufLen, kSE05x_TAG_1, outputData, poutputDataLen); /* */ + if (0 != tlvRet) { + goto cleanup; + } + if ((rspIndex + 2) == rspbufLen) { + retStatus = (pRspbuf[rspIndex] << 8) | (pRspbuf[rspIndex + 1]); + } + } + +cleanup: + return retStatus; +} + +smStatus_t Se05x_API_WriteSymmKey(pSe05xSession_t session_ctx, + pSe05xPolicy_t policy, + SE05x_MaxAttemps_t maxAttempt, + uint32_t objectID, + SE05x_KeyID_t kekID, + const uint8_t *keyValue, + size_t keyValueLen, + const SE05x_INS_t ins_type, + const SE05x_SymmKeyType_t type) +{ + smStatus_t retStatus = SM_NOT_OK; + tlvHeader_t hdr = {{kSE05x_CLA, kSE05x_INS_WRITE | ins_type, type, kSE05x_P2_DEFAULT}}; + size_t cmdbufLen = 0; + uint8_t *pCmdbuf = NULL; + int tlvRet = 0; + + ENSURE_OR_GO_CLEANUP(session_ctx != NULL); + + pCmdbuf = &session_ctx->apdu_buffer[0]; + + if (Se05x_IsInValidRangeOfUID(objectID)) { + return SM_NOT_OK; + } + + SMLOG_D("APDU - WriteSymmKey [] \n"); + + tlvRet = TLVSET_Se05xPolicy("policy", &pCmdbuf, &cmdbufLen, kSE05x_TAG_POLICY, policy); + if (0 != tlvRet) { + goto cleanup; + } + tlvRet = TLVSET_MaxAttemps("maxAttempt", &pCmdbuf, &cmdbufLen, kSE05x_TAG_MAX_ATTEMPTS, maxAttempt); + if (0 != tlvRet) { + goto cleanup; + } + tlvRet = TLVSET_U32("object id", &pCmdbuf, &cmdbufLen, kSE05x_TAG_1, objectID); + if (0 != tlvRet) { + goto cleanup; + } + tlvRet = TLVSET_KeyID("KEK id", &pCmdbuf, &cmdbufLen, kSE05x_TAG_2, kekID); + if (0 != tlvRet) { + goto cleanup; + } + tlvRet = TLVSET_u8bufOptional("key value", &pCmdbuf, &cmdbufLen, kSE05x_TAG_3, keyValue, keyValueLen); + if (0 != tlvRet) { + goto cleanup; + } + retStatus = DoAPDUTx(session_ctx, &hdr, session_ctx->apdu_buffer, cmdbufLen, 0); + +cleanup: + return retStatus; +} + +smStatus_t Se05x_API_DeleteSecureObject(pSe05xSession_t session_ctx, uint32_t objectID) +{ + smStatus_t retStatus = SM_NOT_OK; + tlvHeader_t hdr = {{kSE05x_CLA, kSE05x_INS_MGMT, kSE05x_P1_DEFAULT, kSE05x_P2_DELETE_OBJECT}}; + size_t cmdbufLen = 0; + uint8_t *pCmdbuf = NULL; + int tlvRet = 0; + + ENSURE_OR_GO_CLEANUP(session_ctx != NULL); + + SMLOG_D("APDU - Se05x_API_DeleteSecureObject [] \n"); + + pCmdbuf = &session_ctx->apdu_buffer[0]; + + tlvRet = TLVSET_U32("object id", &pCmdbuf, &cmdbufLen, kSE05x_TAG_1, objectID); + if (0 != tlvRet) { + goto cleanup; + } + retStatus = DoAPDUTx(session_ctx, &hdr, session_ctx->apdu_buffer, cmdbufLen, 0); + +cleanup: + return retStatus; +} + +smStatus_t Se05x_API_CreateSession( + pSe05xSession_t session_ctx, uint32_t authObjectID, uint8_t *sessionId, size_t *psessionIdLen) +{ + smStatus_t retStatus = SM_NOT_OK; + tlvHeader_t hdr = {{0x80 /*kSE05x_CLA*/, kSE05x_INS_MGMT, kSE05x_P1_DEFAULT, kSE05x_P2_SESSION_CREATE}}; + size_t cmdbufLen = 0; + uint8_t *pCmdbuf = NULL; + int tlvRet = 0; + uint8_t *pRspbuf = NULL; + size_t rspbufLen = 0; + + ENSURE_OR_GO_CLEANUP(session_ctx != NULL); + + pCmdbuf = &session_ctx->apdu_buffer[0]; + pRspbuf = &session_ctx->apdu_buffer[0]; + rspbufLen = sizeof(session_ctx->apdu_buffer); + + SMLOG_D("APDU - Se05x_API_CreateSession [] \n"); + + tlvRet = TLVSET_U32("auth", &pCmdbuf, &cmdbufLen, kSE05x_TAG_1, authObjectID); + if (0 != tlvRet) { + goto cleanup; + } + retStatus = DoAPDUTxRx(session_ctx, &hdr, &session_ctx->apdu_buffer[0], cmdbufLen, pRspbuf, &rspbufLen, 0); + if (retStatus == SM_OK) { + retStatus = SM_NOT_OK; + size_t rspIndex = 0; + tlvRet = tlvGet_u8buf(pRspbuf, &rspIndex, rspbufLen, kSE05x_TAG_1, sessionId, psessionIdLen); /* */ + if (0 != tlvRet) { + goto cleanup; + } + if ((rspIndex + 2) == rspbufLen) { + retStatus = (pRspbuf[rspIndex] << 8) | (pRspbuf[rspIndex + 1]); + } + } + +cleanup: + return retStatus; +} + +smStatus_t Se05x_API_ReadIDList(pSe05xSession_t session_ctx, + uint16_t outputOffset, + uint8_t filter, + uint8_t *pmore, + uint8_t *idlist, + size_t *pidlistLen) +{ + smStatus_t retStatus = SM_NOT_OK; + tlvHeader_t hdr = {{kSE05x_CLA, kSE05x_INS_READ, kSE05x_P1_DEFAULT, kSE05x_P2_LIST}}; + size_t cmdbufLen = 0; + uint8_t *pCmdbuf = &session_ctx->apdu_buffer[0]; + int tlvRet = 0; + uint8_t *pRspbuf = NULL; + size_t rspIndex = 0; + size_t rspbufLen = 0; + + ENSURE_OR_GO_CLEANUP(session_ctx != NULL); + + SMLOG_D("APDU - Se05x_API_ReadIDList [] \n"); + + pCmdbuf = &session_ctx->apdu_buffer[0]; + pRspbuf = &session_ctx->apdu_buffer[0]; + rspbufLen = sizeof(session_ctx->apdu_buffer); + + tlvRet = TLVSET_U16("output offset", &pCmdbuf, &cmdbufLen, kSE05x_TAG_1, outputOffset); + if (0 != tlvRet) { + goto cleanup; + } + tlvRet = TLVSET_U8("filter", &pCmdbuf, &cmdbufLen, kSE05x_TAG_2, filter); + if (0 != tlvRet) { + goto cleanup; + } + retStatus = DoAPDUTxRx(session_ctx, &hdr, &session_ctx->apdu_buffer[0], cmdbufLen, pRspbuf, &rspbufLen, 0); + if (retStatus == SM_OK) { + retStatus = SM_NOT_OK; + tlvRet = tlvGet_U8(pRspbuf, &rspIndex, rspbufLen, kSE05x_TAG_1, pmore); /* - */ + if (0 != tlvRet) { + goto cleanup; + } + tlvRet = tlvGet_u8buf(pRspbuf, + &rspIndex, + rspbufLen, + kSE05x_TAG_2, + idlist, + pidlistLen); /* Byte array containing 4-byte identifiers */ + if (0 != tlvRet) { + goto cleanup; + } + if ((rspIndex + 2) == rspbufLen) { + retStatus = (smStatus_t)((pRspbuf[rspIndex] << 8) | (pRspbuf[rspIndex + 1])); + } + } + +cleanup: + return retStatus; +} + +smStatus_t Se05x_API_ReadSize(pSe05xSession_t session_ctx, uint32_t objectID, uint16_t *psize) +{ + smStatus_t retStatus = SM_NOT_OK; + tlvHeader_t hdr = {{kSE05x_CLA, kSE05x_INS_READ, kSE05x_P1_DEFAULT, kSE05x_P2_SIZE}}; + size_t cmdbufLen = 0; + uint8_t *pCmdbuf = &session_ctx->apdu_buffer[0]; + int tlvRet = 0; + uint8_t *pRspbuf = NULL; + size_t rspIndex = 0; + size_t rspbufLen = 0; + + SMLOG_D("APDU - Se05x_API_ReadSize [] \n"); + + pCmdbuf = &session_ctx->apdu_buffer[0]; + pRspbuf = &session_ctx->apdu_buffer[0]; + rspbufLen = sizeof(session_ctx->apdu_buffer); + + tlvRet = TLVSET_U32("object id", &pCmdbuf, &cmdbufLen, kSE05x_TAG_1, objectID); + if (0 != tlvRet) { + goto cleanup; + } + retStatus = DoAPDUTxRx(session_ctx, &hdr, &session_ctx->apdu_buffer[0], cmdbufLen, pRspbuf, &rspbufLen, 0); + if (retStatus == SM_OK) { + retStatus = SM_NOT_OK; + tlvRet = tlvGet_U16(pRspbuf, &rspIndex, rspbufLen, kSE05x_TAG_1, psize); /* - */ + if (0 != tlvRet) { + goto cleanup; + } + if ((rspIndex + 2) == rspbufLen) { + retStatus = (smStatus_t)((pRspbuf[rspIndex] << 8) | (pRspbuf[rspIndex + 1])); + } + } + +cleanup: + return retStatus; +} + +smStatus_t Se05x_API_ReadType(pSe05xSession_t session_ctx, + uint32_t objectID, + SE05x_SecureObjectType_t *ptype, + uint8_t *pisTransient, + const SE05x_AttestationType_t attestation_type) +{ + smStatus_t retStatus = SM_NOT_OK; + tlvHeader_t hdr = {{kSE05x_CLA, (uint8_t)kSE05x_INS_READ | attestation_type, kSE05x_P1_DEFAULT, kSE05x_P2_TYPE}}; + uint8_t uType = 0; + size_t cmdbufLen = 0; + uint8_t *pCmdbuf = &session_ctx->apdu_buffer[0]; + int tlvRet = 0; + uint8_t *pRspbuf = NULL; + size_t rspIndex = 0; + size_t rspbufLen = 0; + + SMLOG_D("APDU - Se05x_API_ReadType [] \n"); + + pCmdbuf = &session_ctx->apdu_buffer[0]; + pRspbuf = &session_ctx->apdu_buffer[0]; + rspbufLen = sizeof(session_ctx->apdu_buffer); + + tlvRet = TLVSET_U32("object id", &pCmdbuf, &cmdbufLen, kSE05x_TAG_1, objectID); + if (0 != tlvRet) { + goto cleanup; + } + retStatus = DoAPDUTxRx(session_ctx, &hdr, &session_ctx->apdu_buffer[0], cmdbufLen, pRspbuf, &rspbufLen, 0); + if (retStatus == SM_OK) { + retStatus = SM_NOT_OK; + if (ptype != NULL) { + tlvRet = tlvGet_U8(pRspbuf, &rspIndex, rspbufLen, kSE05x_TAG_1, &uType); + *ptype = (SE05x_SecureObjectType_t)uType; + if (0 != tlvRet) { + goto cleanup; + } + } + tlvRet = tlvGet_U8(pRspbuf, &rspIndex, rspbufLen, kSE05x_TAG_2, pisTransient); /* - */ + if (0 != tlvRet) { + goto cleanup; + } + if ((rspIndex + 2) == rspbufLen) { + retStatus = (smStatus_t)((pRspbuf[rspIndex] << 8) | (pRspbuf[rspIndex + 1])); + } + } + +cleanup: + return retStatus; +} + +smStatus_t Se05x_API_CreateECCurve(pSe05xSession_t session_ctx, SE05x_ECCurve_t curveID) +{ + smStatus_t retStatus = SM_NOT_OK; + tlvHeader_t hdr = {{kSE05x_CLA, kSE05x_INS_WRITE, kSE05x_P1_CURVE, kSE05x_P2_CREATE}}; + size_t cmdbufLen = 0; + uint8_t *pCmdbuf = NULL; + int tlvRet = 0; + + ENSURE_OR_GO_CLEANUP(session_ctx != NULL); + + SMLOG_D("APDU - Se05x_API_CreateECCurve [] \n"); + + pCmdbuf = &session_ctx->apdu_buffer[0]; + + tlvRet = TLVSET_ECCurve("curve id", &pCmdbuf, &cmdbufLen, kSE05x_TAG_1, curveID); + if (0 != tlvRet) { + goto cleanup; + } + retStatus = DoAPDUTx(session_ctx, &hdr, session_ctx->apdu_buffer, cmdbufLen, 0); + +cleanup: + return retStatus; +} + +smStatus_t Se05x_API_DeleteECCurve(pSe05xSession_t session_ctx, SE05x_ECCurve_t curveID) +{ + smStatus_t retStatus = SM_NOT_OK; + tlvHeader_t hdr = {{kSE05x_CLA, kSE05x_INS_MGMT, kSE05x_P1_CURVE, kSE05x_P2_DELETE_OBJECT}}; + size_t cmdbufLen = 0; + uint8_t *pCmdbuf = NULL; + int tlvRet = 0; + + ENSURE_OR_GO_CLEANUP(session_ctx != NULL); + + SMLOG_D("APDU - Se05x_API_DeleteECCurve [] \n"); + + pCmdbuf = &session_ctx->apdu_buffer[0]; + + tlvRet = TLVSET_ECCurve("curve id", &pCmdbuf, &cmdbufLen, kSE05x_TAG_1, curveID); + if (0 != tlvRet) { + goto cleanup; + } + retStatus = DoAPDUTx(session_ctx, &hdr, session_ctx->apdu_buffer, cmdbufLen, 0); + +cleanup: + return retStatus; +} + +smStatus_t Se05x_API_SetECCurveParam(pSe05xSession_t session_ctx, + SE05x_ECCurve_t curveID, + SE05x_ECCurveParam_t ecCurveParam, + const uint8_t *inputData, + size_t inputDataLen) +{ + smStatus_t retStatus = SM_NOT_OK; + tlvHeader_t hdr = {{kSE05x_CLA, kSE05x_INS_WRITE, kSE05x_P1_CURVE, kSE05x_P2_PARAM}}; + + size_t cmdbufLen = 0; + uint8_t *pCmdbuf = NULL; + int tlvRet = 0; + + SMLOG_D("APDU - Se05x_API_SetECCurveParam [] \n"); + + pCmdbuf = &session_ctx->apdu_buffer[0]; + + tlvRet = TLVSET_ECCurve("curve id", &pCmdbuf, &cmdbufLen, kSE05x_TAG_1, curveID); + if (0 != tlvRet) { + goto cleanup; + } + tlvRet = TLVSET_ECCurveParam("ecCurveParam", &pCmdbuf, &cmdbufLen, kSE05x_TAG_2, ecCurveParam); + if (0 != tlvRet) { + goto cleanup; + } + tlvRet = TLVSET_u8bufOptional("inputData", &pCmdbuf, &cmdbufLen, kSE05x_TAG_3, inputData, inputDataLen); + if (0 != tlvRet) { + goto cleanup; + } + retStatus = DoAPDUTx(session_ctx, &hdr, session_ctx->apdu_buffer, cmdbufLen, 0); + +cleanup: + return retStatus; +} + +smStatus_t Se05x_API_ReadECCurveList(pSe05xSession_t session_ctx, uint8_t *curveList, size_t *pcurveListLen) +{ + smStatus_t retStatus = SM_NOT_OK; + tlvHeader_t hdr = {{kSE05x_CLA, kSE05x_INS_READ, kSE05x_P1_CURVE, kSE05x_P2_LIST}}; + size_t cmdbufLen = 0; + int tlvRet = 0; + uint8_t *pRspbuf = NULL; + size_t rspbufLen = 0; + + ENSURE_OR_GO_CLEANUP(session_ctx != NULL); + + pRspbuf = &session_ctx->apdu_buffer[0]; + rspbufLen = sizeof(session_ctx->apdu_buffer); + + SMLOG_D("APDU - Se05x_API_ReadECCurveList [] \n"); + + retStatus = DoAPDUTxRx(session_ctx, &hdr, session_ctx->apdu_buffer, cmdbufLen, pRspbuf, &rspbufLen, 0); + if (retStatus == SM_OK) { + retStatus = SM_NOT_OK; + size_t rspIndex = 0; + tlvRet = tlvGet_u8buf(pRspbuf, &rspIndex, rspbufLen, kSE05x_TAG_1, curveList, pcurveListLen); /* */ + if (0 != tlvRet) { + goto cleanup; + } + if ((rspIndex + 2) == rspbufLen) { + retStatus = (pRspbuf[rspIndex] << 8) | (pRspbuf[rspIndex + 1]); + } + } +cleanup: + return retStatus; +} + +smStatus_t Se05x_API_ReadObject_W_Attst(pSe05xSession_t session_ctx, + uint32_t objectID, + uint16_t offset, + uint16_t length, + uint32_t attestID, + SE05x_AttestationAlgo_t attestAlgo, + const uint8_t *random, + size_t randomLen, + uint8_t *pCmdapdu, + size_t *pCmdapduLen, + uint8_t *pRspBuf, + size_t *pRspBufLen) +{ + smStatus_t retStatus = SM_NOT_OK; + tlvHeader_t hdr = {{kSE05x_CLA, kSE05x_INS_READ_With_Attestation, kSE05x_P1_DEFAULT, kSE05x_P2_DEFAULT}}; + + size_t cmdbufLen = 0; + uint8_t *pCmdbuf = &session_ctx->apdu_buffer[0]; + int tlvRet = 0; + size_t rspbufLen = 0; + + ENSURE_OR_GO_CLEANUP(session_ctx != NULL); + ENSURE_OR_GO_CLEANUP(pRspBuf != NULL); + ENSURE_OR_GO_CLEANUP(pRspBufLen != NULL); + + SMLOG_D("APDU - Se05x_API_ReadObject_W_Attst [] \n"); + SMLOG_D( + "NOTE: Se05x_API_ReadObject_W_Attst API will return the secure element response as is. No parsing of the TLV " + "is done.\n"); + + pCmdbuf = &session_ctx->apdu_buffer[0]; + rspbufLen = *pRspBufLen; + + tlvRet = TLVSET_U32("object id", &pCmdbuf, &cmdbufLen, kSE05x_TAG_1, objectID); + if (0 != tlvRet) { + goto cleanup; + } + + tlvRet = TLVSET_U16Optional("offset", &pCmdbuf, &cmdbufLen, kSE05x_TAG_2, offset); + if (0 != tlvRet) { + goto cleanup; + } + + tlvRet = TLVSET_U16Optional("length", &pCmdbuf, &cmdbufLen, kSE05x_TAG_3, length); + if (0 != tlvRet) { + goto cleanup; + } + + tlvRet = TLVSET_U32("attestID", &pCmdbuf, &cmdbufLen, kSE05x_TAG_5, attestID); + if (0 != tlvRet) { + goto cleanup; + } + + tlvRet = TLVSET_AttestationAlgo("attestAlgo", &pCmdbuf, &cmdbufLen, kSE05x_TAG_6, attestAlgo); + if (0 != tlvRet) { + goto cleanup; + } + + tlvRet = TLVSET_u8bufOptional("random", &pCmdbuf, &cmdbufLen, kSE05x_TAG_7, random, randomLen); + if (0 != tlvRet) { + goto cleanup; + } + + if ((pCmdapdu != NULL) && (pCmdapduLen != NULL)) { + if (*pCmdapduLen < 6) { + goto cleanup; + } + memcpy(pCmdapdu, &hdr, 4); + + //As length is extended + pCmdapdu[4] = 0x00; + pCmdapdu[5] = 0x00; + + if (cmdbufLen == 0) { + goto cleanup; + } + if (*pCmdapduLen < (cmdbufLen + 7)) { + goto cleanup; + } + + pCmdapdu[6] = (uint8_t)cmdbufLen; + memcpy(pCmdapdu + 7, &session_ctx->apdu_buffer[0], cmdbufLen); + *pCmdapduLen = cmdbufLen + 7; + } + + retStatus = DoAPDUTxRx(session_ctx, &hdr, &session_ctx->apdu_buffer[0], cmdbufLen, pRspBuf, &rspbufLen, 1); + if (retStatus == SM_OK) { + *pRspBufLen = rspbufLen; + } + else { + *pRspBufLen = 0; + } + +cleanup: + return retStatus; +} + +smStatus_t Se05x_API_PBKDF2_extended(pSe05xSession_t session_ctx, + uint32_t objectID, + const uint8_t *salt, + size_t saltLen, + uint32_t saltID, + uint16_t count, + SE05x_MACAlgo_t macAlgo, + uint16_t requestedLen, + uint32_t derivedSessionKeyID, + uint8_t *derivedSessionKey, + size_t *pderivedSessionKeyLen) +{ + smStatus_t retStatus = SM_NOT_OK; + tlvHeader_t hdr = {{kSE05x_CLA, kSE05x_INS_CRYPTO, kSE05x_P1_DEFAULT, kSE05x_P2_PBKDF}}; + size_t cmdbufLen = 0; + uint8_t *pCmdbuf = &session_ctx->apdu_buffer[0]; + int tlvRet = 0; + size_t rspIndex = 0; + uint8_t *pRspbuf = &session_ctx->apdu_buffer[0]; + size_t rspbufLen = sizeof(session_ctx->apdu_buffer); + + ENSURE_OR_GO_CLEANUP(session_ctx != NULL); + + SMLOG_D("APDU - Se05x_API_PBKDF2_extended [] \n"); + + tlvRet = TLVSET_U32( + "4-byte password identifier (object type must be HMACKey)", &pCmdbuf, &cmdbufLen, kSE05x_TAG_1, objectID); + if (0 != tlvRet) { + goto cleanup; + } + tlvRet = TLVSET_u8bufOptional("salt", &pCmdbuf, &cmdbufLen, kSE05x_TAG_2, salt, saltLen); + if (0 != tlvRet) { + goto cleanup; + } + tlvRet = TLVSET_U16("count", &pCmdbuf, &cmdbufLen, kSE05x_TAG_3, count); + if (0 != tlvRet) { + goto cleanup; + } + tlvRet = TLVSET_U16("requestedLen", &pCmdbuf, &cmdbufLen, kSE05x_TAG_4, requestedLen); + if (0 != tlvRet) { + goto cleanup; + } + tlvRet = TLVSET_U8("MacAlgo", &pCmdbuf, &cmdbufLen, kSE05x_TAG_5, macAlgo); + if (0 != tlvRet) { + goto cleanup; + } + if (salt == NULL) { + tlvRet = TLVSET_U32("saltID", &pCmdbuf, &cmdbufLen, kSE05x_TAG_6, saltID); + if (0 != tlvRet) { + goto cleanup; + } + } + if (derivedSessionKey == NULL) { + tlvRet = TLVSET_U32("derivedSessionKeyID", &pCmdbuf, &cmdbufLen, kSE05x_TAG_7, derivedSessionKeyID); + if (0 != tlvRet) { + goto cleanup; + } + } + retStatus = DoAPDUTxRx(session_ctx, &hdr, &session_ctx->apdu_buffer[0], cmdbufLen, pRspbuf, &rspbufLen, 0); + if (retStatus == SM_OK) { + if (derivedSessionKey == NULL) { + retStatus = SM_NOT_OK; + if (2 == rspbufLen) { + retStatus = (smStatus_t)((pRspbuf[0] << 8) | (pRspbuf[1])); + } + } + else { + retStatus = SM_NOT_OK; + tlvRet = + tlvGet_u8buf(pRspbuf, &rspIndex, rspbufLen, kSE05x_TAG_1, derivedSessionKey, pderivedSessionKeyLen); + if (0 != tlvRet) { + goto cleanup; + } + if ((rspIndex + 2) == rspbufLen) { + retStatus = (smStatus_t)((pRspbuf[rspIndex] << 8) | (pRspbuf[rspIndex + 1])); + } + } + } + +cleanup: + return retStatus; +} diff --git a/src/lib/apdu/se05x_tlv.c b/src/lib/apdu/se05x_tlv.c new file mode 100644 index 0000000..81b1920 --- /dev/null +++ b/src/lib/apdu/se05x_tlv.c @@ -0,0 +1,674 @@ +/** @file se05x_tlv.c + * @brief TLV utils functions. + * + * Copyright 2021,2022, 2024 NXP + * SPDX-License-Identifier: Apache-2.0 + */ + +/* ********************** Include files ********************** */ +#include "lib/apdu/se05x_tlv.h" +#include "smCom.h" +#include "lib/platform/arduino/sm_port.h" +#include "lib/apdu/se05x_types.h" +#include + +/* ********************** Global vaiables ********************** */ + +#ifdef ENABLE_SM_APDU_MUTEX +/* + Mutex used at the se05x_tlv.c (DoAPDUTxRx/DoAPDUTx functions) layer + Use this feature, in case multiple tasks call Se05x_API_* APIs. + Set `PLUGANDTRUST_ENABLE_SM_APDU_MUTEX` cmake option to ON to enable this feature. +*/ +SM_MUTEX_EXTERN_DEFINE(g_sm_apdu_mutex); +#endif + +/* ********************** Function ********************** */ + +int tlvSet_U8(uint8_t **buf, size_t *bufLen, SE05x_TAG_t tag, uint8_t value) +{ + uint8_t *pBuf = NULL; + const size_t size_of_tlv = 1 + 1 + 1; + + ENSURE_OR_RETURN_ON_ERROR(buf != NULL, 1); + ENSURE_OR_RETURN_ON_ERROR(bufLen != NULL, 1); + + pBuf = *buf; + ENSURE_OR_RETURN_ON_ERROR(pBuf != NULL, 1); + + if ((*bufLen) > (MAX_APDU_BUFFER - size_of_tlv)) { + return 1; + } + if (UINTPTR_MAX - 3 < (uintptr_t)pBuf) { + return 1; + } + *pBuf++ = (uint8_t)tag; + *pBuf++ = 1; + *pBuf++ = value; + *buf = pBuf; + *bufLen += size_of_tlv; + return 0; +} + +int tlvSet_U16(uint8_t **buf, size_t *bufLen, SE05x_TAG_t tag, uint16_t value) +{ + const size_t size_of_tlv = 1 + 1 + 2; + uint8_t *pBuf = NULL; + + ENSURE_OR_RETURN_ON_ERROR(buf != NULL, 1); + ENSURE_OR_RETURN_ON_ERROR(bufLen != NULL, 1); + + pBuf = *buf; + ENSURE_OR_RETURN_ON_ERROR(pBuf != NULL, 1); + + if ((*bufLen) > (MAX_APDU_BUFFER - size_of_tlv)) { + return 1; + } + *pBuf++ = (uint8_t)tag; + *pBuf++ = 2; + *pBuf++ = (uint8_t)((value >> 1 * 8) & 0xFF); + *pBuf++ = (uint8_t)((value >> 0 * 8) & 0xFF); + *buf = pBuf; + *bufLen += size_of_tlv; + return 0; +} + +int tlvSet_U32(uint8_t **buf, size_t *bufLen, SE05x_TAG_t tag, uint32_t value) +{ + const size_t size_of_tlv = 1 + 1 + 4; + uint8_t *pBuf = NULL; + + ENSURE_OR_RETURN_ON_ERROR(buf != NULL, 1); + ENSURE_OR_RETURN_ON_ERROR(bufLen != NULL, 1); + + pBuf = *buf; + ENSURE_OR_RETURN_ON_ERROR(pBuf != NULL, 1); + + if ((*bufLen) > (MAX_APDU_BUFFER - size_of_tlv)) { + return 1; + } + if (UINTPTR_MAX - 6 < (uintptr_t)pBuf) { + return 1; + } + *pBuf++ = (uint8_t)tag; + *pBuf++ = 4; + *pBuf++ = (uint8_t)((value >> 3 * 8) & 0xFF); + *pBuf++ = (uint8_t)((value >> 2 * 8) & 0xFF); + *pBuf++ = (uint8_t)((value >> 1 * 8) & 0xFF); + *pBuf++ = (uint8_t)((value >> 0 * 8) & 0xFF); + *buf = pBuf; + *bufLen += size_of_tlv; + return 0; +} + +int tlvSet_u8buf(uint8_t **buf, size_t *bufLen, SE05x_TAG_t tag, const uint8_t *cmd, size_t cmdLen) +{ + uint8_t *pBuf = NULL; + + ENSURE_OR_RETURN_ON_ERROR(buf != NULL, 1); + ENSURE_OR_RETURN_ON_ERROR(bufLen != NULL, 1); + + pBuf = *buf; + ENSURE_OR_RETURN_ON_ERROR(pBuf != NULL, 1); + + /* if < 0x7F + * len = 1 byte + * elif if < 0xFF + * '0x81' + len == 2 Bytes + * elif if < 0xFFFF + * '0x82' + len_msb + len_lsb == 3 Bytes + */ + const size_t size_of_length = (cmdLen <= 0x7f ? 1 : (cmdLen <= 0xFf ? 2 : 3)); + const size_t size_of_tlv = 1 + size_of_length + cmdLen; + + if ((UINT_MAX - size_of_tlv) < (*bufLen)) { + return 1; + } + + if (((*bufLen) + size_of_tlv) > MAX_APDU_BUFFER) { + SMLOG_E("Not enough buffer \n"); + return 1; + } + + if (UINTPTR_MAX - 1 < (uintptr_t)pBuf) { + return 1; + } + *pBuf++ = (uint8_t)tag; + + if (cmdLen <= 0x7Fu) { + if (UINTPTR_MAX - 1 < (uintptr_t)pBuf) { + return 1; + } + *pBuf++ = (uint8_t)cmdLen; + } + else if (cmdLen <= 0xFFu) { + if (UINTPTR_MAX - 2 < (uintptr_t)pBuf) { + return 1; + } + *pBuf++ = (uint8_t)(0x80 /* Extended */ | 0x01 /* Additional Length */); + *pBuf++ = (uint8_t)((cmdLen >> 0 * 8) & 0xFF); + } + else if (cmdLen <= 0xFFFFu) { + if (UINTPTR_MAX - 3 < (uintptr_t)pBuf) { + return 1; + } + *pBuf++ = (uint8_t)(0x80 /* Extended */ | 0x02 /* Additional Length */); + *pBuf++ = (uint8_t)((cmdLen >> 1 * 8) & 0xFF); + *pBuf++ = (uint8_t)((cmdLen >> 0 * 8) & 0xFF); + } + else { + return 1; + } + if ((cmdLen > 0) && (cmd != NULL)) { + while (cmdLen-- > 0) { + if (UINTPTR_MAX - 1 < (uintptr_t)pBuf) { + return 1; + } + *pBuf++ = *cmd++; + } + } + + *bufLen += size_of_tlv; + *buf = pBuf; + + return 0; +} + +int tlvSet_u8bufOptional(uint8_t **buf, size_t *bufLen, SE05x_TAG_t tag, const uint8_t *cmd, size_t cmdLen) +{ + if (cmdLen == 0) { + return 0; + } + else { + return tlvSet_u8buf(buf, bufLen, tag, cmd, cmdLen); + } +} + +int tlvSet_U16Optional(uint8_t **buf, size_t *bufLen, SE05x_TAG_t tag, uint16_t value) +{ + if (value == 0) { + return 0; + } + else { + return tlvSet_U16(buf, bufLen, tag, value); + } +} + +int tlvSet_Se05xPolicy(const char *description, uint8_t **buf, size_t *bufLen, SE05x_TAG_t tag, Se05xPolicy_t *policy) +{ + int tlvRet = 0; + (void)description; + if ((policy != NULL) && (policy->value != NULL)) { + tlvRet = tlvSet_u8buf(buf, bufLen, tag, policy->value, policy->value_len); + return tlvRet; + } + return tlvRet; +} + +int tlvSet_MaxAttemps(uint8_t **buf, size_t *bufLen, SE05x_TAG_t tag, uint16_t maxAttemps) +{ + int retVal = 0; + if (maxAttemps != 0) { + retVal = tlvSet_U16(buf, bufLen, tag, maxAttemps); + } + return retVal; +} + +int tlvSet_ECCurve(uint8_t **buf, size_t *bufLen, SE05x_TAG_t tag, SE05x_ECCurve_t value) +{ + int retVal = 0; + if (value != kSE05x_ECCurve_NA) { + retVal = tlvSet_U8(buf, bufLen, tag, (uint8_t)value); + } + return retVal; +} + +int tlvSet_KeyID(uint8_t **buf, size_t *bufLen, SE05x_TAG_t tag, uint32_t keyID) +{ + int retVal = 0; + if (keyID != 0) { + retVal = tlvSet_U32(buf, bufLen, tag, keyID); + } + return retVal; +} + +int tlvSet_header(uint8_t **buf, size_t *bufLen, tlvHeader_t *hdr) +{ + uint8_t *pBuf = NULL; + + ENSURE_OR_RETURN_ON_ERROR(buf != NULL, 1); + ENSURE_OR_RETURN_ON_ERROR(bufLen != NULL, 1); + ENSURE_OR_RETURN_ON_ERROR(hdr != NULL, 1); + ENSURE_OR_RETURN_ON_ERROR(((UINT_MAX - 5) >= *bufLen), 1); + + pBuf = *buf; + + memcpy(pBuf, hdr, 4); + *buf = pBuf + (4 + 1); + *bufLen += (4 + 1); + return 0; +} + +int tlvGet_U8(uint8_t *buf, size_t *pBufIndex, const size_t bufLen, SE05x_TAG_t tag, uint8_t *pRsp) +{ + int retVal = 1; + uint8_t *pBuf = buf + (*pBufIndex); + uint8_t got_tag = 0; + size_t rspLen; + + if (UINTPTR_MAX - 2 < (uintptr_t)pBuf) { + goto cleanup; + } + got_tag = *pBuf++; + + if ((*pBufIndex) > bufLen) { + goto cleanup; + } + + if (got_tag != tag) { + goto cleanup; + } + rspLen = *pBuf++; + if (rspLen > 1) { + goto cleanup; + } + *pRsp = *pBuf; + *pBufIndex += (1 + 1 + (rspLen)); + retVal = 0; +cleanup: + return retVal; +} + +int tlvGet_U16(uint8_t *buf, size_t *pBufIndex, const size_t bufLen, SE05x_TAG_t tag, uint16_t *pRsp) +{ + int retVal = 1; + uint8_t *pBuf = buf + (*pBufIndex); + uint8_t got_tag = *pBuf++; + size_t rspLen; + + if ((*pBufIndex) > bufLen) { + goto cleanup; + } + + if (got_tag != tag) { + goto cleanup; + } + rspLen = *pBuf++; + if (rspLen > 2) { + goto cleanup; + } + *pRsp = (*pBuf++) << 8; + *pRsp |= *pBuf++; + *pBufIndex += (1 + 1 + (rspLen)); + retVal = 0; +cleanup: + return retVal; +} + +int tlvGet_u8buf(uint8_t *buf, size_t *pBufIndex, const size_t bufLen, SE05x_TAG_t tag, uint8_t *rsp, size_t *pRspLen) +{ + int retVal = 1; + uint8_t *pBuf = buf + (*pBufIndex); + uint8_t got_tag = *pBuf++; + size_t extendedLen; + size_t rspLen; + //size_t len; + + if (rsp == NULL) { + goto cleanup; + } + + if (pRspLen == NULL) { + goto cleanup; + } + + if ((*pBufIndex) > bufLen) { + goto cleanup; + } + + if (got_tag != tag) { + goto cleanup; + } + rspLen = *pBuf++; + + if (rspLen <= 0x7FU) { + extendedLen = rspLen; + *pBufIndex += (1 + 1); + } + else if (rspLen == 0x81) { + extendedLen = *pBuf++; + *pBufIndex += (1 + 1 + 1); + } + else if (rspLen == 0x82) { + extendedLen = *pBuf++; + extendedLen = (extendedLen << 8) | *pBuf++; + *pBufIndex += (1 + 1 + 2); + } + else { + goto cleanup; + } + + if (extendedLen > *pRspLen) { + goto cleanup; + } + if (extendedLen > bufLen) { + goto cleanup; + } + + *pRspLen = extendedLen; + *pBufIndex += extendedLen; + while (extendedLen-- > 0) { + *rsp++ = *pBuf++; + } + retVal = 0; +cleanup: + if (retVal != 0) { + if (pRspLen != NULL) { + *pRspLen = 0; + } + } + return retVal; +} + +int tlvGet_Result(uint8_t *buf, size_t *pBufIndex, size_t bufLen, SE05x_TAG_t tag, SE05x_Result_t *presult) +{ + uint8_t uType = 0; + size_t uTypeLen = 1; + int retVal = tlvGet_u8buf(buf, pBufIndex, bufLen, tag, &uType, &uTypeLen); + *presult = (SE05x_Result_t)uType; + return retVal; +} + +smStatus_t DoAPDUTx( + pSe05xSession_t session_ctx, const tlvHeader_t *hdr, uint8_t *cmdBuf, size_t cmdBufLen, uint8_t length_extended) +{ + smStatus_t apduStatus = SM_NOT_OK; +#if (defined(WITH_ECKEY_SCP03_SESSION) || defined(WITH_ECKEY_SESSION)) + tlvHeader_t outHdr = { + 0, + }; +#endif + size_t rxBufLen = MAX_APDU_BUFFER; + uint8_t *rspBuf = &session_ctx->apdu_buffer[0]; +#if (defined(WITH_ECKEY_SCP03_SESSION) || defined(WITH_PLATFORM_SCP03)) + size_t org_cmd_len = cmdBufLen; +#endif + ENSURE_OR_GO_EXIT(hdr != NULL); + if (cmdBufLen > 0) { + ENSURE_OR_GO_EXIT(cmdBuf != NULL); + } + +#ifdef ENABLE_SM_APDU_MUTEX + SM_MUTEX_LOCK(g_sm_apdu_mutex); +#endif + +#if defined(WITH_PLATFORM_SCP03) + if (session_ctx->scp03_session) { + apduStatus = Se05x_API_SCP03_Encrypt(session_ctx, hdr, cmdBuf, cmdBufLen, length_extended, cmdBuf, &cmdBufLen); + ENSURE_OR_GO_EXIT(apduStatus == SM_OK); + + apduStatus = smComT1oI2C_TransceiveRaw(session_ctx->conn_context, cmdBuf, cmdBufLen, cmdBuf, &rxBufLen); + ENSURE_OR_GO_EXIT(apduStatus == SM_OK); + ENSURE_OR_RETURN_ON_ERROR((rxBufLen >= SCP_GP_SW_LEN), SM_NOT_OK); + + apduStatus = Se05x_API_SCP03_Decrypt(session_ctx, org_cmd_len, cmdBuf, rxBufLen, rspBuf, &rxBufLen); + ENSURE_OR_GO_EXIT(apduStatus == SM_OK); + } + else +#endif //#if defined(WITH_PLATFORM_SCP03) + +#if defined(WITH_ECKEY_SCP03_SESSION) + if (session_ctx->ecKey_session == 0 && session_ctx->scp03_session == 1) { + apduStatus = Se05x_API_SCP03_Encrypt(session_ctx, hdr, cmdBuf, cmdBufLen, length_extended, cmdBuf, &cmdBufLen); + ENSURE_OR_GO_EXIT(apduStatus == SM_OK); + + apduStatus = smComT1oI2C_TransceiveRaw(session_ctx->conn_context, cmdBuf, cmdBufLen, cmdBuf, &rxBufLen); + ENSURE_OR_GO_EXIT(apduStatus == SM_OK); + ENSURE_OR_RETURN_ON_ERROR((rxBufLen >= SCP_GP_SW_LEN), SM_NOT_OK); + + apduStatus = Se05x_API_SCP03_Decrypt(session_ctx, org_cmd_len, cmdBuf, rxBufLen, rspBuf, &rxBufLen); + ENSURE_OR_GO_EXIT(apduStatus == SM_OK); + } + else if (session_ctx->ecKey_session == 1 && session_ctx->scp03_session == 1) { + size_t cmd_index = 0; + + apduStatus = Se05x_API_ECKeyAuth_Encrypt( + session_ctx, hdr, cmdBuf, cmdBufLen, length_extended, &outHdr, cmdBuf, &cmdBufLen); + ENSURE_OR_GO_EXIT(apduStatus == SM_OK); + + cmd_index = (cmdBuf[4] == 0) ? (7) : (5); + + apduStatus = Se05x_API_SCP03_Encrypt( + session_ctx, &outHdr, &cmdBuf[cmd_index], cmdBufLen - cmd_index, length_extended, cmdBuf, &cmdBufLen); + ENSURE_OR_GO_EXIT(apduStatus == SM_OK); + + apduStatus = smComT1oI2C_TransceiveRaw(session_ctx->conn_context, cmdBuf, cmdBufLen, cmdBuf, &rxBufLen); + ENSURE_OR_GO_EXIT(apduStatus == SM_OK); + ENSURE_OR_RETURN_ON_ERROR((rxBufLen >= SCP_GP_SW_LEN), SM_NOT_OK); + + apduStatus = Se05x_API_SCP03_Decrypt(session_ctx, org_cmd_len, cmdBuf, rxBufLen, rspBuf, &rxBufLen); + if (apduStatus != SM_OK) { + Se05x_API_Auth_IncCommandCounter(&session_ctx->eckey_counter[0]); + goto exit; + } + else { + apduStatus = Se05x_API_ECKeyAuth_Decrypt(session_ctx, rspBuf, rxBufLen, rspBuf, &rxBufLen); + } + } + else +#endif //#if defined(WITH_ECKEY_SCP03_SESSION) + +#if defined(WITH_ECKEY_SESSION) + if (session_ctx->ecKey_session == 1) { + apduStatus = Se05x_API_ECKeyAuth_Encrypt( + session_ctx, hdr, cmdBuf, cmdBufLen, length_extended, &outHdr, cmdBuf, &cmdBufLen); + ENSURE_OR_GO_EXIT(apduStatus == SM_OK); + + apduStatus = smComT1oI2C_TransceiveRaw(session_ctx->conn_context, cmdBuf, cmdBufLen, cmdBuf, &rxBufLen); + ENSURE_OR_GO_EXIT(apduStatus == SM_OK); + ENSURE_OR_RETURN_ON_ERROR((rxBufLen >= SCP_GP_SW_LEN), SM_NOT_OK); + + apduStatus = Se05x_API_ECKeyAuth_Decrypt(session_ctx, cmdBuf, rxBufLen, rspBuf, &rxBufLen); + ENSURE_OR_GO_EXIT(apduStatus == SM_OK); + } + else +#endif //#if defined(WITH_ECKEY_SESSION) + { + (void)length_extended; + if (cmdBufLen > 0) { + if ((cmdBufLen < 0xFF) && !length_extended) { + ENSURE_OR_GO_EXIT((MAX_APDU_BUFFER - 5) >= cmdBufLen); + memmove((cmdBuf + 5), cmdBuf, cmdBufLen); + memcpy(cmdBuf, hdr, 4); + cmdBuf[4] = cmdBufLen; + ENSURE_OR_GO_EXIT((UINT_MAX - 5) >= cmdBufLen); + cmdBufLen += 5; + } + else { + ENSURE_OR_GO_EXIT((MAX_APDU_BUFFER - 7) >= cmdBufLen); + memmove((cmdBuf + 7), cmdBuf, cmdBufLen); + memcpy(cmdBuf, hdr, 4); + + cmdBuf[4] = 0x00; + cmdBuf[5] = 0xFFu & (cmdBufLen >> 8); + cmdBuf[6] = 0xFFu & (cmdBufLen); + + ENSURE_OR_GO_EXIT((UINT_MAX - 7) >= cmdBufLen); + cmdBufLen += 7; + } + } + else { + memcpy(cmdBuf, hdr, 4); + cmdBufLen = 4; + } + if (length_extended) { + ENSURE_OR_GO_EXIT((MAX_APDU_BUFFER - 2) >= cmdBufLen); + ENSURE_OR_GO_EXIT((UINT_MAX - 2) >= cmdBufLen); + cmdBuf[cmdBufLen++] = 0x00; + cmdBuf[cmdBufLen++] = 0x00; + } + apduStatus = smComT1oI2C_TransceiveRaw(session_ctx->conn_context, cmdBuf, cmdBufLen, rspBuf, &rxBufLen); + if (rxBufLen >= 2) { + apduStatus = rspBuf[(rxBufLen)-2] << 8 | rspBuf[(rxBufLen)-1]; + } + } + +exit: +#ifdef ENABLE_SM_APDU_MUTEX + SM_MUTEX_UNLOCK(g_sm_apdu_mutex); +#endif + return apduStatus; +} + +smStatus_t DoAPDUTxRx(pSe05xSession_t session_ctx, + const tlvHeader_t *hdr, + uint8_t *cmdBuf, + size_t cmdBufLen, + uint8_t *rspBuf, + size_t *pRspBufLen, + uint8_t length_extended) +{ + smStatus_t apduStatus = SM_NOT_OK; +#if (defined(WITH_ECKEY_SCP03_SESSION) || defined(WITH_ECKEY_SESSION)) + tlvHeader_t outHdr = { + 0, + }; +#endif +#if (defined(WITH_PLATFORM_SCP03) || defined(WITH_ECKEY_SCP03_SESSION) || defined(WITH_ECKEY_SESSION)) + size_t rxBufLen = MAX_APDU_BUFFER; +#endif + +#if (defined(WITH_PLATFORM_SCP03) || defined(WITH_ECKEY_SCP03_SESSION)) + size_t org_cmd_len = cmdBufLen; +#endif + + ENSURE_OR_GO_EXIT(hdr != NULL); + if (cmdBufLen > 0) { + ENSURE_OR_GO_EXIT(cmdBuf != NULL); + } + ENSURE_OR_GO_EXIT(pRspBufLen != NULL); + ENSURE_OR_GO_EXIT(rspBuf != NULL); + +#ifdef ENABLE_SM_APDU_MUTEX + SM_MUTEX_LOCK(g_sm_apdu_mutex); +#endif + +#if defined(WITH_PLATFORM_SCP03) + if (session_ctx->scp03_session) { + apduStatus = Se05x_API_SCP03_Encrypt(session_ctx, hdr, cmdBuf, cmdBufLen, length_extended, cmdBuf, &cmdBufLen); + ENSURE_OR_GO_EXIT(apduStatus == SM_OK); + + apduStatus = smComT1oI2C_TransceiveRaw(session_ctx->conn_context, cmdBuf, cmdBufLen, cmdBuf, &rxBufLen); + ENSURE_OR_GO_EXIT(apduStatus == SM_OK); + ENSURE_OR_RETURN_ON_ERROR((rxBufLen >= SCP_GP_SW_LEN), SM_NOT_OK); + + apduStatus = Se05x_API_SCP03_Decrypt(session_ctx, org_cmd_len, cmdBuf, rxBufLen, rspBuf, pRspBufLen); + ENSURE_OR_GO_EXIT(apduStatus == SM_OK); + } + else +#endif //#if defined(WITH_PLATFORM_SCP03) + +#if defined(WITH_ECKEY_SCP03_SESSION) + /*Only PlatformSCP session is opened*/ + if (session_ctx->ecKey_session == 0 && session_ctx->scp03_session == 1) { + apduStatus = + Se05x_API_SCP03_Encrypt(session_ctx, hdr, cmdBuf, cmdBufLen, length_extended, cmdBuf, &cmdBufLen); + ENSURE_OR_GO_EXIT(apduStatus == SM_OK); + + apduStatus = smComT1oI2C_TransceiveRaw(session_ctx->conn_context, cmdBuf, cmdBufLen, cmdBuf, &rxBufLen); + ENSURE_OR_GO_EXIT(apduStatus == SM_OK); + ENSURE_OR_RETURN_ON_ERROR((rxBufLen >= SCP_GP_SW_LEN), SM_NOT_OK); + + apduStatus = Se05x_API_SCP03_Decrypt(session_ctx, org_cmd_len, cmdBuf, rxBufLen, rspBuf, pRspBufLen); + ENSURE_OR_GO_EXIT(apduStatus == SM_OK); + } + /*Both PlatformSCP and ECKey sessions are opened*/ + else if (session_ctx->ecKey_session == 1 && session_ctx->scp03_session == 1) { + size_t cmd_index = 0; + + apduStatus = Se05x_API_ECKeyAuth_Encrypt( + session_ctx, hdr, cmdBuf, cmdBufLen, length_extended, &outHdr, cmdBuf, &cmdBufLen); + ENSURE_OR_GO_EXIT(apduStatus == SM_OK); + + cmd_index = (cmdBuf[4] == 0) ? (7) : (5); + + apduStatus = Se05x_API_SCP03_Encrypt( + session_ctx, &outHdr, &cmdBuf[cmd_index], cmdBufLen - cmd_index, length_extended, cmdBuf, &cmdBufLen); + + apduStatus = smComT1oI2C_TransceiveRaw(session_ctx->conn_context, cmdBuf, cmdBufLen, cmdBuf, &rxBufLen); + ENSURE_OR_RETURN_ON_ERROR((apduStatus == SM_OK), apduStatus); + ENSURE_OR_RETURN_ON_ERROR((rxBufLen >= SCP_GP_SW_LEN), SM_NOT_OK); + + apduStatus = Se05x_API_SCP03_Decrypt(session_ctx, org_cmd_len, cmdBuf, rxBufLen, rspBuf, pRspBufLen); + if (apduStatus != SM_OK) { + Se05x_API_Auth_IncCommandCounter(&session_ctx->eckey_counter[0]); + goto exit; + } + else { + apduStatus = Se05x_API_ECKeyAuth_Decrypt(session_ctx, rspBuf, *pRspBufLen, rspBuf, pRspBufLen); + } + } + else +#endif //#if defined(WITH_ECKEY_SCP03_SESSION) + +#if defined(WITH_ECKEY_SESSION) + if (session_ctx->ecKey_session == 1) { + apduStatus = Se05x_API_ECKeyAuth_Encrypt( + session_ctx, hdr, cmdBuf, cmdBufLen, length_extended, &outHdr, cmdBuf, &cmdBufLen); + ENSURE_OR_GO_EXIT(apduStatus == SM_OK); + + apduStatus = smComT1oI2C_TransceiveRaw(session_ctx->conn_context, cmdBuf, cmdBufLen, cmdBuf, &rxBufLen); + ENSURE_OR_GO_EXIT(apduStatus == SM_OK); + ENSURE_OR_RETURN_ON_ERROR((rxBufLen >= SCP_GP_SW_LEN), SM_NOT_OK); + + apduStatus = Se05x_API_ECKeyAuth_Decrypt(session_ctx, cmdBuf, rxBufLen, rspBuf, pRspBufLen); + ENSURE_OR_GO_EXIT(apduStatus == SM_OK); + } + else +#endif //#if defined(WITH_ECKEY_SESSION) + + { + if (cmdBufLen > 0) { + if ((cmdBufLen < 0xFF) && !length_extended) { + ENSURE_OR_GO_EXIT((MAX_APDU_BUFFER - 5) >= cmdBufLen); + memmove((cmdBuf + 5), cmdBuf, cmdBufLen); + memcpy(cmdBuf, hdr, 4); + cmdBuf[4] = cmdBufLen; + ENSURE_OR_GO_EXIT((UINT_MAX - 5) >= cmdBufLen); + cmdBufLen += 5; + } + else { + ENSURE_OR_GO_EXIT((MAX_APDU_BUFFER - 7) >= cmdBufLen); + memmove((cmdBuf + 7), cmdBuf, cmdBufLen); + memcpy(cmdBuf, hdr, 4); + + cmdBuf[4] = 0x00; + cmdBuf[5] = 0xFFu & (cmdBufLen >> 8); + cmdBuf[6] = 0xFFu & (cmdBufLen); + + ENSURE_OR_GO_EXIT((UINT_MAX - 7) >= cmdBufLen); + cmdBufLen += 7; + } + } + else { + memcpy(cmdBuf, hdr, 4); + cmdBufLen = 4; + } + if (length_extended) { + ENSURE_OR_GO_EXIT((MAX_APDU_BUFFER - 2) >= cmdBufLen); + ENSURE_OR_GO_EXIT((UINT_MAX - 2) >= cmdBufLen); + cmdBuf[cmdBufLen++] = 0x00; + cmdBuf[cmdBufLen++] = 0x00; + } + apduStatus = smComT1oI2C_TransceiveRaw(session_ctx->conn_context, cmdBuf, cmdBufLen, rspBuf, pRspBufLen); + if (*pRspBufLen >= 2) { + apduStatus = rspBuf[(*pRspBufLen) - 2] << 8 | rspBuf[(*pRspBufLen) - 1]; + } + } + +exit: +#ifdef ENABLE_SM_APDU_MUTEX + SM_MUTEX_UNLOCK(g_sm_apdu_mutex); +#endif + return apduStatus; +} diff --git a/src/lib/apdu/se05x_tlv.h b/src/lib/apdu/se05x_tlv.h new file mode 100644 index 0000000..f9909db --- /dev/null +++ b/src/lib/apdu/se05x_tlv.h @@ -0,0 +1,108 @@ +/** @file se05x_tlv.h + * @brief TLV utils functions. + * + * Copyright 2021,2022,2024 NXP + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef SE05X_TLV_H_INC +#define SE05X_TLV_H_INC + +/* ********************** Include files ********************** */ +#include "lib/apdu/se05x_types.h" + +/* ********************** Constants ********************** */ +typedef enum +{ + SM_NOT_OK = 0xFFFF, + SM_OK = 0x9000, + SM_ERR_CONDITIONS_OF_USE_NOT_SATISFIED = 0x6985, + SM_ERR_ACCESS_DENIED_BASED_ON_POLICY = 0x6986, + SM_ERR_APDU_THROUGHPUT = 0x66A6, + SM_ERR_WRONG_DATA = 0x6A80, +} smStatus_t; + +/* ********************** Function Prototypes ********************** */ + +int tlvSet_U8(uint8_t **buf, size_t *bufLen, SE05x_TAG_t tag, uint8_t value); +int tlvSet_U16(uint8_t **buf, size_t *bufLen, SE05x_TAG_t tag, uint16_t value); +int tlvSet_U32(uint8_t **buf, size_t *bufLen, SE05x_TAG_t tag, uint32_t value); +int tlvSet_u8buf(uint8_t **buf, size_t *bufLen, SE05x_TAG_t tag, const uint8_t *cmd, size_t cmdLen); +int tlvSet_u8bufOptional(uint8_t **buf, size_t *bufLen, SE05x_TAG_t tag, const uint8_t *cmd, size_t cmdLen); +int tlvSet_U16Optional(uint8_t **buf, size_t *bufLen, SE05x_TAG_t tag, uint16_t value); +int tlvSet_Se05xPolicy(const char *description, uint8_t **buf, size_t *bufLen, SE05x_TAG_t tag, Se05xPolicy_t *policy); +int tlvSet_MaxAttemps(uint8_t **buf, size_t *bufLen, SE05x_TAG_t tag, uint16_t maxAttemps); +int tlvSet_ECCurve(uint8_t **buf, size_t *bufLen, SE05x_TAG_t tag, SE05x_ECCurve_t value); +int tlvSet_KeyID(uint8_t **buf, size_t *bufLen, SE05x_TAG_t tag, uint32_t keyID); +int tlvSet_header(uint8_t **buf, size_t *bufLen, tlvHeader_t *hdr); +int tlvGet_U8(uint8_t *buf, size_t *pBufIndex, const size_t bufLen, SE05x_TAG_t tag, uint8_t *pRsp); +int tlvGet_U16(uint8_t *buf, size_t *pBufIndex, const size_t bufLen, SE05x_TAG_t tag, uint16_t *pRsp); +int tlvGet_u8buf(uint8_t *buf, size_t *pBufIndex, const size_t bufLen, SE05x_TAG_t tag, uint8_t *rsp, size_t *pRspLen); +int tlvGet_Result(uint8_t *buf, size_t *pBufIndex, size_t bufLen, SE05x_TAG_t tag, SE05x_Result_t *presult); +smStatus_t DoAPDUTx( + pSe05xSession_t session_ctx, const tlvHeader_t *hdr, uint8_t *cmdBuf, size_t cmdBufLen, uint8_t hasle); +smStatus_t DoAPDUTxRx(pSe05xSession_t session_ctx, + const tlvHeader_t *hdr, + uint8_t *cmdBuf, + size_t cmdBufLen, + uint8_t *rspBuf, + size_t *pRspBufLen, + uint8_t hasle); + +/* ********************** Defines ********************** */ + +#define DO_LOG_V(TAG, DESCRIPTION, VALUE) \ + SMLOG_D("APDU :DEBUG:" #TAG "[" #DESCRIPTION \ + "]" \ + " = 0x%X \n", \ + VALUE); +#define DO_LOG_A(TAG, DESCRIPTION, ARRAY, ARRAY_LEN) \ + SMLOG_MAU8_D("APDU :DEBUG:" #TAG "[" #DESCRIPTION "]", ARRAY, ARRAY_LEN); + +#define TLVSET_U8(DESCRIPTION, PBUF, PBUFLEN, TAG, VALUE) \ + tlvSet_U8(PBUF, PBUFLEN, TAG, VALUE); \ + DO_LOG_V(TAG, DESCRIPTION, VALUE) + +#define TLVSET_U16(DESCRIPTION, PBUF, PBUFLEN, TAG, VALUE) \ + tlvSet_U16(PBUF, PBUFLEN, TAG, VALUE); \ + DO_LOG_V(TAG, DESCRIPTION, VALUE) + +#define TLVSET_U32(DESCRIPTION, PBUF, PBUFLEN, TAG, VALUE) \ + tlvSet_U32(PBUF, PBUFLEN, TAG, VALUE); \ + DO_LOG_V(TAG, DESCRIPTION, VALUE) + +#define TLVSET_u8buf(DESCRIPTION, PBUF, PBUFLEN, TAG, CMD, CMDLEN) \ + tlvSet_u8buf(PBUF, PBUFLEN, TAG, CMD, CMDLEN); \ + DO_LOG_A(TAG, DESCRIPTION, CMD, CMDLEN) + +#define TLVSET_u8bufOptional(DESCRIPTION, PBUF, PBUFLEN, TAG, CMD, CMDLEN) \ + tlvSet_u8bufOptional(PBUF, PBUFLEN, TAG, CMD, CMDLEN); \ + DO_LOG_A(TAG, DESCRIPTION, CMD, CMDLEN) + +#define TLVSET_U16Optional(DESCRIPTION, PBUF, PBUFLEN, TAG, VALUE) \ + tlvSet_U16Optional(PBUF, PBUFLEN, TAG, VALUE); \ + DO_LOG_V(TAG, DESCRIPTION, VALUE) + +#define TLVSET_KeyID(DESCRIPTION, PBUF, PBUFLEN, TAG, VALUE) \ + tlvSet_KeyID(PBUF, PBUFLEN, TAG, VALUE); \ + DO_LOG_V(TAG, DESCRIPTION, VALUE) + +#define TLVSET_Se05xPolicy(DESCRIPTION, PBUF, PBUFLEN, TAG, POLICY) \ + tlvSet_Se05xPolicy(DESCRIPTION, PBUF, PBUFLEN, TAG, POLICY) + +#define TLVSET_MaxAttemps(DESCRIPTION, PBUF, PBUFLEN, TAG, VALUE) \ + tlvSet_MaxAttemps(PBUF, PBUFLEN, TAG, VALUE); \ + DO_LOG_V(TAG, DESCRIPTION, VALUE) + +#define TLVSET_ECCurve(DESCRIPTION, PBUF, PBUFLEN, TAG, VALUE) \ + tlvSet_ECCurve(PBUF, PBUFLEN, TAG, VALUE); \ + DO_LOG_V(TAG, DESCRIPTION, VALUE) + +#define TLVSET_Header(PBUF, PBUFLEN, HDR) tlvSet_header(PBUF, PBUFLEN, HDR); + +#define TLVSET_ECSignatureAlgo TLVSET_U8 +#define TLVSET_CipherMode TLVSET_U8 +#define TLVSET_ECCurveParam TLVSET_U8 +#define TLVSET_AttestationAlgo TLVSET_U8 + +#endif // #ifndef SE05X_TLV_H_INC diff --git a/src/lib/apdu/se05x_types.h b/src/lib/apdu/se05x_types.h new file mode 100644 index 0000000..446a7da --- /dev/null +++ b/src/lib/apdu/se05x_types.h @@ -0,0 +1,529 @@ +/** @file se05x_types.h + * @brief . + * + * Copyright 2021,2022,2024,2026 NXP + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef SE05X_TYPES_H_INC +#define SE05X_TYPES_H_INC + +/* ********************** Include files ********************** */ +#include +#include +#include +#include + +/* ********************** Constants ********************** */ + +/** Plug and Trust Nano package version */ +#define VERSION_MAJOR 1 +#define VERSION_MINOR 6 +#define VERSION_DEV 0 + +/** +* APDU buffer size. +* The stack is tested with Buffer size of 255 Bytes. +*/ +#if defined(CONFIG_PLUGANDTRUST_APDU_BUFFER_SIZE) && CONFIG_PLUGANDTRUST_APDU_BUFFER_SIZE > 0 +#define MAX_APDU_BUFFER CONFIG_PLUGANDTRUST_APDU_BUFFER_SIZE +#else +#define MAX_APDU_BUFFER 512 +#endif + +/** NXP reserved object id */ +#define SE05X_OBJID_SE05X_APPLET_RES_START 0x7FFF0000u +#define SE05X_OBJID_SE05X_APPLET_RES_MASK(X) (0xFFFF0000u & (X)) +#define SE05X_OBJID_SE05X_APPLET_RES_END 0x7FFFFFFFu + +/* IoT Hub Access */ +#define EX_SSS_OBJID_IOT_HUB_A_START 0xF0000000u +#define EX_SSS_OBJID_IOT_HUB_A_MASK(X) (0xF0000000u & (X)) + +/** When we want to read with attestation */ +#define kSE05x_INS_READ_With_Attestation (kSE05x_INS_READ | kSE05x_INS_ATTEST) + +/** Policy constants */ +/* Access Rules for Object Policy*/ +#define POLICY_OBJ_FORBID_ALL 0x20000000 +#define POLICY_OBJ_ALLOW_SIGN 0x10000000 +#define POLICY_OBJ_ALLOW_VERIFY 0x08000000 +#define POLICY_OBJ_ALLOW_KA 0x04000000 +#define POLICY_OBJ_ALLOW_ENC 0x02000000 +#define POLICY_OBJ_ALLOW_DEC 0x01000000 +#define POLICY_OBJ_ALLOW_KDF 0x00800000 // Only applicable for applet < 7.2 +#define POLICY_OBJ_ALLOW_WRAP 0x00400000 +#define POLICY_OBJ_ALLOW_READ 0x00200000 +#define POLICY_OBJ_ALLOW_WRITE 0x00100000 +#define POLICY_OBJ_ALLOW_GEN 0x00080000 +#define POLICY_OBJ_ALLOW_DELETE 0x00040000 +#define POLICY_OBJ_REQUIRE_SM 0x00020000 +#define POLICY_OBJ_REQUIRE_PCR_VALUE 0x00010000 +#define POLICY_OBJ_ALLOW_ATTESTATION 0x00008000 +#define POLICY_OBJ_ALLOW_DESFIRE_AUTHENTICATION 0x00004000 +#define POLICY_OBJ_ALLOW_DESFIRE_DUMP_SESSION_KEYS 0x00002000 +#define POLICY_OBJ_ALLOW_IMPORT_EXPORT 0x00001000 +#define POLICY_OBJ_FORBID_DERIVED_OUTPUT 0x00000800 // Only applicable for applet >= 6.0 +#define POLICY_OBJ_ALLOW_KDF_EXT_RANDOM 0x00000400 // Only applicable for applet >= 6.0 +#define POLICY_OBJ_ALLOW_TLS_KDF 0x80000000 // Only applicable for applet >= 7.2 +#define POLICY_OBJ_ALLOW_TLS_PMS 0x40000000 // Only applicable for applet >= 7.2 +#define POLICY_OBJ_ALLOW_HKDF 0x00800000 // Only applicable for applet >= 7.2 +#define POLICY_OBJ_ALLOW_DESFIRE_CHANGEKEY 0x00000200 // Only applicable for applet >= 7.2 +#define POLICY_OBJ_ALLOW_DERIVED_INPUT 0x00000100 // Only applicable for applet >= 7.2 +#define POLICY_OBJ_ALLOW_PBKDF 0x00000080 // Only applicable for applet >= 7.2 +#define POLICY_OBJ_ALLOW_DESFIRE_KDF 0x00000040 // Only applicable for applet >= 7.2 +#define POLICY_OBJ_FORBID_EXTERNAL_IV 0x00000020 // Only applicable for applet >= 7.2 +#define POLICY_OBJ_ALLOW_USAGE_AS_HMAC_PEPPER 0x00000010 // Only applicable for applet >= 7.2 + +#define ENSURE_OR_GO_EXIT(CONDITION) \ + if (!(CONDITION)) { \ + goto exit; \ + } + +#define ENSURE_OR_GO_CLEANUP(CONDITION) \ + if (!(CONDITION)) { \ + goto cleanup; \ + } + +#define ENSURE_OR_RETURN_ON_ERROR(CONDITION, RETURN_VALUE) \ + if (!(CONDITION)) { \ + return RETURN_VALUE; \ + } + +/* ********************** SE05x Types ********************** */ + +typedef uint16_t SE05x_MaxAttemps_t; + +typedef struct +{ + /** ISO 7816 APDU Header */ + uint8_t hdr[0 /* For Indentation */ + + 1 /* CLA */ + + 1 /* INS */ + + 1 /* P1 */ + + 1 /* P2 */ + ]; +} tlvHeader_t; + +/** Se05x session context */ +typedef struct +{ + /** I2C connection context */ + void *conn_context; + /** Set skip_applet_select = 1, to skip the se05x applet selection.*/ + uint8_t skip_applet_select; + /** Applet Version*/ + uint32_t applet_version; + /** Apdu buffer used for Tx/Rx */ + uint8_t apdu_buffer[MAX_APDU_BUFFER]; + /** PlatformSCP03 ENC key. Set to NULL in case of plain session */ + uint8_t *pScp03_enc_key; + /** PlatformSCP03 ENC key length. Set to 0 in case of plain session */ + size_t scp03_enc_key_len; + /** PlatformSCP03 MAC key. Set to NULL in case of plain session */ + uint8_t *pScp03_mac_key; + /** PlatformSCP03 MAC key length. Set to 0 in case of plain session */ + size_t scp03_mac_key_len; + /** PlatformSCP03 DEK key. Set to NULL in case of plain session */ + uint8_t *pScp03_dek_key; + /** PlatformSCP03 DEK key length. Set to 0 in case of plain session */ + size_t scp03_dek_key_len; + /** EC Auth key */ + uint8_t *pEc_auth_key; + /** EC Auth key length */ + size_t ec_auth_key_len; + /** Set 1 to resume session */ + uint8_t session_resume; + /** PlatformSCP03 session status */ + uint8_t scp03_session; + /** Eckey session status*/ + uint8_t ecKey_session; + + /** PlatformSCP03 dynamic keys */ + uint8_t scp03_session_enc_Key[16]; + uint8_t scp03_session_mac_Key[16]; + uint8_t scp03_session_rmac_Key[16]; + uint8_t scp03_counter[16]; + uint8_t scp03_mcv[16]; + + /** ECKeys dynamic keys */ + uint8_t eckey_session_enc_Key[16]; + uint8_t eckey_session_mac_Key[16]; + uint8_t eckey_session_rmac_Key[16]; + uint8_t eckey_counter[16]; + uint8_t eckey_mcv[16]; + uint8_t eckey_applet_session_value[8]; + +} Se05xSession_t; + +typedef Se05xSession_t *pSe05xSession_t; + +typedef struct +{ + uint8_t *value; + size_t value_len; +} Se05xPolicy_t; +typedef Se05xPolicy_t *pSe05xPolicy_t; + +/** Values for P1 in ISO7816 APDU */ +typedef enum +{ + /** Invalid */ + kSE05x_P1_NA = 0, + /** Highest bit not used */ + kSE05x_P1_UNUSED = 0x80, + /** 2 MSBit for key type */ + kSE05x_P1_MASK_KEY_TYPE = 0x60, + /** 5 LSBit for credential type */ + kSE05x_P1_MASK_CRED_TYPE = 0x1F, + /** Key pair (private key + public key) */ + kSE05x_P1_KEY_PAIR = 0x60, + /** Private key */ + kSE05x_P1_PRIVATE = 0x40, + /** Public key */ + kSE05x_P1_PUBLIC = 0x20, + kSE05x_P1_DEFAULT = 0x00, + kSE05x_P1_EC = 0x01, + kSE05x_P1_AES = 0x03, + kSE05x_P1_DES = 0x04, + kSE05x_P1_HMAC = 0x05, + kSE05x_P1_BINARY = 0x06, + kSE05x_P1_UserID = 0x07, + kSE05x_P1_CURVE = 0x0B, + kSE05x_P1_SIGNATURE = 0x0C, + kSE05x_P1_MAC = 0x0D, + kSE05x_P1_CIPHER = 0x0E, +} SE05x_P1_t; + +/** Values for P2 in ISO7816 APDU */ +typedef enum +{ + /** Invalid */ + kSE05x_P2_DEFAULT = 0x00, + kSE05x_P2_GENERATE = 0x03, + kSE05x_P2_CREATE = 0x04, + kSE05x_P2_SIZE = 0x07, + kSE05x_P2_SIGN = 0x09, + kSE05x_P2_VERIFY = 0x0A, + kSE05x_P2_SESSION_CREATE = 0x1B, + kSE05x_P2_SESSION_CLOSE = 0x1C, + kSE05x_P2_VERSION = 0x20, + kSE05x_P2_LIST = 0x25, + kSE05x_P2_TYPE = 0x26, + kSE05x_P2_EXIST = 0x27, + kSE05x_P2_DELETE_OBJECT = 0x28, + kSE05x_P2_SESSION_UserID = 0x2C, + kSE05x_P2_PBKDF = 0x2E, + kSE05x_P2_DH = 0x0F, + kSE05x_P2_ENCRYPT_ONESHOT = 0x37, + kSE05x_P2_DECRYPT_ONESHOT = 0x38, + kSE05x_P2_SCP = 0x52, + kSE05x_P2_ONESHOT = 0x0E, + kSE05x_P2_ID = 0x36, + kSE05x_P2_PARAM = 0x40, +} SE05x_P2_t; + +/** ECC Curve Identifiers */ +typedef enum +{ + /** Invalid */ + kSE05x_ECCurve_NA = 0x00, + kSE05x_ECCurve_NIST_P256 = 0x03, + kSE05x_ECCurve_NIST_P384 = 0x04, +} SE05x_ECCurve_t; + +typedef enum +{ + /** Invalid */ + kSE05x_SetIndicator_NA = 0, + kSE05x_SetIndicator_NOT_SET = 0x01, + kSE05x_SetIndicator_SET = 0x02, +} SE05x_SetIndicator_t; + +/** Parameters while setting the curve */ +typedef enum +{ /** Invalid */ + kSE05x_ECCurveParam_NA = 0, + kSE05x_ECCurveParam_PARAM_A = 0x01, + kSE05x_ECCurveParam_PARAM_B = 0x02, + kSE05x_ECCurveParam_PARAM_G = 0x04, + kSE05x_ECCurveParam_PARAM_N = 0x08, + kSE05x_ECCurveParam_PARAM_PRIME = 0x10, +} SE05x_ECCurveParam_t; + +/** Values for INS in ISO7816 APDU */ +typedef enum +{ + /** Invalid */ + kSE05x_INS_NA = 0, + /** 3 MSBit for instruction characteristics. */ + kSE05x_INS_MASK_INS_CHAR = 0xE0, + /** 5 LSBit for instruction */ + kSE05x_INS_MASK_INSTRUCTION = 0x1F, + + /** Mask for transient object creation, can only be combined with INS_WRITE. */ + kSE05x_INS_TRANSIENT = 0x80, + /** Mask for authentication object creation, can only be combined with INS_WRITE */ + kSE05x_INS_AUTH_OBJECT = 0x40, + /** Mask for getting attestation data. */ + kSE05x_INS_ATTEST = 0x20, + + /** Write or create a persistent object. */ + kSE05x_INS_WRITE = 0x01, + /** Read the object */ + kSE05x_INS_READ = 0x02, + /** Perform Security Operation */ + kSE05x_INS_CRYPTO = 0x03, + /** General operation */ + kSE05x_INS_MGMT = 0x04, + /** Process session command */ + kSE05x_INS_PROCESS = 0x05, +} SE05x_INS_t; + +/** Part of the asymmetric key */ +typedef enum +{ + kSE05x_KeyPart_NA = kSE05x_P1_DEFAULT, + /** Key pair (private key + public key) */ + kSE05x_KeyPart_Pair = kSE05x_P1_KEY_PAIR, + /** Private key */ + kSE05x_KeyPart_Private = kSE05x_P1_PRIVATE, + /** Public key */ + kSE05x_KeyPart_Public = kSE05x_P1_PUBLIC, +} SE05x_KeyPart_t; + +/** Different TAG Values to talk to SE05X IoT Applet */ +typedef enum +{ + /** Invalid */ + kSE05x_TAG_NA = 0, + kSE05x_TAG_SESSION_ID = 0x10, + kSE05x_TAG_POLICY = 0x11, + kSE05x_TAG_MAX_ATTEMPTS = 0x12, + kSE05x_TAG_IMPORT_AUTH_DATA = 0x13, + kSE05x_TAG_IMPORT_AUTH_KEY_ID = 0x14, + kSE05x_TAG_POLICY_CHECK = 0x15, + kSE05x_TAG_1 = 0x41, + kSE05x_TAG_2 = 0x42, + kSE05x_TAG_3 = 0x43, + kSE05x_TAG_4 = 0x44, + kSE05x_TAG_5 = 0x45, + kSE05x_TAG_6 = 0x46, + kSE05x_TAG_7 = 0x47, + kSE05x_TAG_8 = 0x48, + kSE05x_TAG_9 = 0x49, + kSE05x_TAG_10 = 0x4A, + kSE05x_TAG_11 = 0x4B, + kSE05x_TAG_TIMESTAMP = 0x4F, + kSE05x_TAG_SIGNATURE = 0x52, +} SE05x_TAG_t; + +/** Different signature algorithms for EC */ +typedef enum +{ + /** Invalid */ + kSE05x_ECSignatureAlgo_NA = 0, + /** NOT SUPPORTED */ + kSE05x_ECSignatureAlgo_PLAIN = 0x09, + kSE05x_ECSignatureAlgo_SHA = 0x11, + kSE05x_ECSignatureAlgo_SHA_224 = 0x25, + kSE05x_ECSignatureAlgo_SHA_256 = 0x21, + kSE05x_ECSignatureAlgo_SHA_384 = 0x22, + kSE05x_ECSignatureAlgo_SHA_512 = 0x26, +} SE05x_ECSignatureAlgo_t; + +/** Different signature algorithms for ED */ +typedef enum +{ + /** Invalid */ + kSE05x_EDSignatureAlgo_NA = 0, + /** Message input must be plain Data. Pure EDDSA algorithm */ + kSE05x_EDSignatureAlgo_ED25519PURE_SHA_512 = 0xA3, +} SE05x_EDSignatureAlgo_t; + +/** Result of operations */ +typedef enum +{ + /** Invalid */ + kSE05x_Result_NA = 0, + kSE05x_Result_SUCCESS = 0x01, + kSE05x_Result_FAILURE = 0x02, +} SE05x_Result_t; + +/** Symmetric cipher modes */ +typedef enum +{ + /** Invalid */ + kSE05x_CipherMode_NA = 0, + /** Typically using AESKey identifiers */ + kSE05x_CipherMode_AES_CBC_NOPAD = 0x0D, + /** Typically using AESKey identifiers */ + kSE05x_CipherMode_AES_ECB_NOPAD = 0x0E, + /** Typically using AESKey identifiers */ + kSE05x_CipherMode_AES_CTR = 0xF0, +} SE05x_CipherMode_t; + +/** One Shot operations helper */ +typedef enum +{ + kSE05x_Cipher_Oper_OneShot_NA = 0, + kSE05x_Cipher_Oper_OneShot_Encrypt = kSE05x_P2_ENCRYPT_ONESHOT, + kSE05x_Cipher_Oper_OneShot_Decrypt = kSE05x_P2_DECRYPT_ONESHOT, +} SE05x_Cipher_Oper_OneShot_t; + +/** SE05X's key IDs */ +typedef uint32_t SE05x_KeyID_t; +/** Case when there is no KEK */ +#define SE05x_KeyID_KEK_NONE 0 + +/** Symmetric keys */ +typedef enum +{ + kSE05x_SymmKeyType_NA = 0, + kSE05x_SymmKeyType_AES = kSE05x_P1_AES, + kSE05x_SymmKeyType_DES = kSE05x_P1_DES, + kSE05x_SymmKeyType_HMAC = kSE05x_P1_HMAC, + kSE05x_SymmKeyType_CMAC = kSE05x_P1_AES, +} SE05x_SymmKeyType_t; + +/** Mandate platform SCP or not */ +typedef enum +{ + /** Invalid */ + kSE05x_PlatformSCPRequest_NA = 0, + /** Platform SCP is required (full enc & MAC) */ + kSE05x_PlatformSCPRequest_REQUIRED = 0x01, + /** No platform SCP required. */ + kSE05x_PlatformSCPRequest_NOT_REQUIRED = 0x02, +} SE05x_PlatformSCPRequest_t; + +/** In case the read is attested */ +typedef enum +{ + kSE05x_AttestationType_None = 0, + kSE05x_AttestationType_AUTH = kSE05x_INS_AUTH_OBJECT, +} SE05x_AttestationType_t; + +/** When there are more entries yet to be fetched from the APIs */ +typedef enum +{ + /** Invalid */ + kSE05x_MoreIndicator_NA = 0, + /** No more data available */ + kSE05x_MoreIndicator_NO_MORE = 0x01, + /** More data available */ + kSE05x_MoreIndicator_MORE = 0x02, +} SE05x_MoreIndicator_t; + +/** Type of Object */ +typedef enum +{ + kSE05x_SecObjTyp_NA = 0x00, + kSE05x_SecObjTyp_EC_KEY_PAIR = 0x01, + kSE05x_SecObjTyp_EC_PRIV_KEY = 0x02, + kSE05x_SecObjTyp_EC_PUB_KEY = 0x03, + kSE05x_SecObjTyp_RSA_KEY_PAIR = 0x04, + kSE05x_SecObjTyp_RSA_KEY_PAIR_CRT = 0x05, + kSE05x_SecObjTyp_RSA_PRIV_KEY = 0x06, + kSE05x_SecObjTyp_RSA_PRIV_KEY_CRT = 0x07, + kSE05x_SecObjTyp_RSA_PUB_KEY = 0x08, + kSE05x_SecObjTyp_AES_KEY = 0x09, + kSE05x_SecObjTyp_DES_KEY = 0x0A, + kSE05x_SecObjTyp_BINARY_FILE = 0x0B, + kSE05x_SecObjTyp_UserID = 0x0C, + kSE05x_SecObjTyp_COUNTER = 0x0D, + kSE05x_SecObjTyp_PCR = 0x0F, + kSE05x_SecObjTyp_CURVE = 0x10, + kSE05x_SecObjTyp_HMAC_KEY = 0x11, + kSE05x_SecObjTyp_EC_KEY_PAIR_NIST_P192 = 0x21, + kSE05x_SecObjTyp_EC_PRIV_KEY_NIST_P192 = 0x22, + kSE05x_SecObjTyp_EC_PUB_KEY_NIST_P192 = 0x23, + kSE05x_SecObjTyp_EC_KEY_PAIR_NIST_P224 = 0x25, + kSE05x_SecObjTyp_EC_PRIV_KEY_NIST_P224 = 0x26, + kSE05x_SecObjTyp_EC_PUB_KEY_NIST_P224 = 0x27, + kSE05x_SecObjTyp_EC_KEY_PAIR_NIST_P256 = 0x29, + kSE05x_SecObjTyp_EC_PRIV_KEY_NIST_P256 = 0x2A, + kSE05x_SecObjTyp_EC_PUB_KEY_NIST_P256 = 0x2B, + kSE05x_SecObjTyp_EC_KEY_PAIR_NIST_P384 = 0x2D, + kSE05x_SecObjTyp_EC_PRIV_KEY_NIST_P384 = 0x2E, + kSE05x_SecObjTyp_EC_PUB_KEY_NIST_P384 = 0x2F, + kSE05x_SecObjTyp_EC_KEY_PAIR_NIST_P521 = 0x31, + kSE05x_SecObjTyp_EC_PRIV_KEY_NIST_P521 = 0x32, + kSE05x_SecObjTyp_EC_PUB_KEY_NIST_P521 = 0x33, + kSE05x_SecObjTyp_EC_KEY_PAIR_Brainpool160 = 0x35, + kSE05x_SecObjTyp_EC_PRIV_KEY_Brainpool160 = 0x36, + kSE05x_SecObjTyp_EC_PUB_KEY_Brainpool160 = 0x37, + kSE05x_SecObjTyp_EC_KEY_PAIR_Brainpool192 = 0x39, + kSE05x_SecObjTyp_EC_PRIV_KEY_Brainpool192 = 0x3A, + kSE05x_SecObjTyp_EC_PUB_KEY_Brainpool192 = 0x3B, + kSE05x_SecObjTyp_EC_KEY_PAIR_Brainpool224 = 0x3D, + kSE05x_SecObjTyp_EC_PRIV_KEY_Brainpool224 = 0x3E, + kSE05x_SecObjTyp_EC_PUB_KEY_Brainpool224 = 0x3F, + kSE05x_SecObjTyp_EC_KEY_PAIR_Brainpool256 = 0x41, + kSE05x_SecObjTyp_EC_PRIV_KEY_Brainpool256 = 0x42, + kSE05x_SecObjTyp_EC_PUB_KEY_Brainpool256 = 0x43, + kSE05x_SecObjTyp_EC_KEY_PAIR_Brainpool320 = 0x45, + kSE05x_SecObjTyp_EC_PRIV_KEY_Brainpool320 = 0x46, + kSE05x_SecObjTyp_EC_PUB_KEY_Brainpool320 = 0x47, + kSE05x_SecObjTyp_EC_KEY_PAIR_Brainpool384 = 0x49, + kSE05x_SecObjTyp_EC_PRIV_KEY_Brainpool384 = 0x4A, + kSE05x_SecObjTyp_EC_PUB_KEY_Brainpool384 = 0x4B, + kSE05x_SecObjTyp_EC_KEY_PAIR_Brainpool512 = 0x4D, + kSE05x_SecObjTyp_EC_PRIV_KEY_Brainpool512 = 0x4E, + kSE05x_SecObjTyp_EC_PUB_KEY_Brainpool512 = 0x4F, + kSE05x_SecObjTyp_EC_KEY_PAIR_Secp160k1 = 0x51, + kSE05x_SecObjTyp_EC_PRIV_KEY_Secp160k1 = 0x52, + kSE05x_SecObjTyp_EC_PUB_KEY_Secp160k1 = 0x53, + kSE05x_SecObjTyp_EC_KEY_PAIR_Secp192k1 = 0x55, + kSE05x_SecObjTyp_EC_PRIV_KEY_Secp192k1 = 0x56, + kSE05x_SecObjTyp_EC_PUB_KEY_Secp192k1 = 0x57, + kSE05x_SecObjTyp_EC_KEY_PAIR_Secp224k1 = 0x59, + kSE05x_SecObjTyp_EC_PRIV_KEY_Secp224k1 = 0x5A, + kSE05x_SecObjTyp_EC_PUB_KEY_Secp224k1 = 0x5B, + kSE05x_SecObjTyp_EC_KEY_PAIR_Secp256k1 = 0x5D, + kSE05x_SecObjTyp_EC_PRIV_KEY_Secp256k1 = 0x5E, + kSE05x_SecObjTyp_EC_PUB_KEY_Secp256k1 = 0x5F, + kSE05x_SecObjTyp_EC_KEY_PAIR_BN_P256 = 0x61, + kSE05x_SecObjTyp_EC_PRIV_KEY_BN_P256 = 0x62, + kSE05x_SecObjTyp_EC_PUB_KEY_BN_P256 = 0x63, + kSE05x_SecObjTyp_EC_KEY_PAIR_ED25519 = 0x65, + kSE05x_SecObjTyp_EC_PRIV_KEY_ED25519 = 0x66, + kSE05x_SecObjTyp_EC_PUB_KEY_ED25519 = 0x67, + kSE05x_SecObjTyp_EC_KEY_PAIR_MONT_DH_25519 = 0x69, + kSE05x_SecObjTyp_EC_PRIV_KEY_MONT_DH_25519 = 0x6A, + kSE05x_SecObjTyp_EC_PUB_KEY_MONT_DH_25519 = 0x6B, + kSE05x_SecObjTyp_EC_KEY_PAIR_MONT_DH_448 = 0x71, + kSE05x_SecObjTyp_EC_PRIV_KEY_MONT_DH_448 = 0x72, + kSE05x_SecObjTyp_EC_PUB_KEY_MONT_DH_448 = 0x73, +} SE05x_SecObjTyp_t; + +/** @copydoc SE05x_SecObjTyp_t */ +typedef SE05x_SecObjTyp_t SE05x_SecureObjectType_t; + +/** Attestation */ +typedef enum +{ + kSE05x_AttestationAlgo_NA = 0, + kSE05x_AttestationAlgo_EC_PLAIN = kSE05x_ECSignatureAlgo_PLAIN, + kSE05x_AttestationAlgo_EC_SHA = kSE05x_ECSignatureAlgo_SHA, + kSE05x_AttestationAlgo_EC_SHA_224 = kSE05x_ECSignatureAlgo_SHA_224, + kSE05x_AttestationAlgo_EC_SHA_256 = kSE05x_ECSignatureAlgo_SHA_256, + kSE05x_AttestationAlgo_EC_SHA_384 = kSE05x_ECSignatureAlgo_SHA_384, + kSE05x_AttestationAlgo_EC_SHA_512 = kSE05x_ECSignatureAlgo_SHA_512, + kSE05x_AttestationAlgo_ED25519PURE_SHA_512 = kSE05x_EDSignatureAlgo_ED25519PURE_SHA_512, +} SE05x_AttestationAlgo_t; + +/** HMAC/CMAC Algorithms */ +typedef enum +{ + /** Invalid */ + kSE05x_MACAlgo_NA = 0, + kSE05x_MACAlgo_HMAC_SHA1 = 0x18, + kSE05x_MACAlgo_HMAC_SHA256 = 0x19, + kSE05x_MACAlgo_HMAC_SHA384 = 0x1A, + kSE05x_MACAlgo_HMAC_SHA512 = 0x1B, + kSE05x_MACAlgo_CMAC_128 = 0x31, + kSE05x_MACAlgo_DES_CMAC8 = 0x7A, +} SE05x_MACAlgo_t; + +#endif //#ifndef SE05X_TYPES_H_INC diff --git a/src/lib/apdu/smCom.c b/src/lib/apdu/smCom.c new file mode 100644 index 0000000..a404679 --- /dev/null +++ b/src/lib/apdu/smCom.c @@ -0,0 +1,130 @@ +/** @file smCom.c + * @brief SmCom APIs. + * + * Copyright 2021,2022,2024 NXP + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @par Description + * This file implements the SmCom T1oI2C communication layer. + * + *****************************************************************************/ + +/* ********************** Include files ********************** */ +#include "lib/t1oi2c/phNxpEseProto7816_3.h" +#include "lib/t1oi2c/phEseStatus.h" +#include "smCom.h" +#include "lib/platform/arduino/sm_port.h" +#include + +/* ********************** Global vaiables ********************** */ +SM_MUTEX_DEFINE(g_sm_mutex); +#ifdef ENABLE_SM_APDU_MUTEX +SM_MUTEX_DEFINE(g_sm_apdu_mutex); +#endif + +/* ********************** Functions ********************** */ + +smStatus_t smComT1oI2C_Close(void *conn_ctx, uint8_t mode) +{ + ESESTATUS status; + (void)mode; + + ENSURE_OR_RETURN_ON_ERROR((conn_ctx != NULL), SM_NOT_OK); + + status = phNxpEse_EndOfApdu(conn_ctx); + ENSURE_OR_RETURN_ON_ERROR((status == ESESTATUS_SUCCESS), SM_NOT_OK); + + status = phNxpEse_close(conn_ctx); + ENSURE_OR_RETURN_ON_ERROR((status == ESESTATUS_SUCCESS), SM_NOT_OK); + + SM_MUTEX_DEINIT(g_sm_mutex); +#ifdef ENABLE_SM_APDU_MUTEX + SM_MUTEX_DEINIT(g_sm_apdu_mutex); +#endif + + return SM_OK; +} + +smStatus_t smComT1oI2C_Init(void **conn_ctx, const char *pConnString) +{ + ESESTATUS status; + phNxpEse_initParams initParams; + initParams.initMode = ESE_MODE_NORMAL; + + status = phNxpEse_open(conn_ctx, initParams, pConnString); + ENSURE_OR_RETURN_ON_ERROR((status == ESESTATUS_SUCCESS), SM_NOT_OK); + + SM_MUTEX_INIT(g_sm_mutex); +#ifdef ENABLE_SM_APDU_MUTEX + SM_MUTEX_INIT(g_sm_apdu_mutex); +#endif + + return SM_OK; +} + +smStatus_t smComT1oI2C_Open(void *conn_ctx, uint8_t mode, uint8_t seqCnt, uint8_t *T1oI2Catr, size_t *T1oI2CatrLen) +{ + ESESTATUS status; + phNxpEse_data AtrRsp; + phNxpEse_initParams initParams; + initParams.initMode = mode; + AtrRsp.len = *T1oI2CatrLen; + AtrRsp.p_data = T1oI2Catr; + + (void)mode; + (void)seqCnt; + + ENSURE_OR_RETURN_ON_ERROR((conn_ctx != NULL), SM_NOT_OK); + + status = phNxpEse_init(conn_ctx, initParams, &AtrRsp); + ENSURE_OR_RETURN_ON_ERROR((status == ESESTATUS_SUCCESS), SM_NOT_OK); + + *T1oI2CatrLen = AtrRsp.len; /*Retrive INF FIELD*/ + + return SM_OK; +} + +smStatus_t smComT1oI2C_TransceiveRaw(void *conn_ctx, uint8_t *pTx, size_t txLen, uint8_t *pRx, size_t *pRxLen) +{ + phNxpEse_data pCmdTrans; + phNxpEse_data pRspTrans = {0}; + ESESTATUS status; + + ENSURE_OR_RETURN_ON_ERROR((txLen <= UINT32_MAX), SM_NOT_OK); + pCmdTrans.len = txLen; + pCmdTrans.p_data = pTx; + + ENSURE_OR_RETURN_ON_ERROR((*pRxLen <= UINT32_MAX), SM_NOT_OK); + pRspTrans.len = *pRxLen; + pRspTrans.p_data = pRx; + + ENSURE_OR_RETURN_ON_ERROR((conn_ctx != NULL), SM_NOT_OK); + ENSURE_OR_RETURN_ON_ERROR((pTx != NULL), SM_NOT_OK); + ENSURE_OR_RETURN_ON_ERROR((pRx != NULL), SM_NOT_OK); + ENSURE_OR_RETURN_ON_ERROR((pRxLen != NULL), SM_NOT_OK); + + SMLOG_MAU8_D("APDU Tx>", pTx, txLen); + + SM_MUTEX_LOCK(g_sm_mutex); + status = phNxpEse_Transceive(conn_ctx, &pCmdTrans, &pRspTrans); + SM_MUTEX_UNLOCK(g_sm_mutex); + ENSURE_OR_RETURN_ON_ERROR((status == ESESTATUS_SUCCESS), SM_NOT_OK); + + *pRxLen = pRspTrans.len; + SMLOG_MAU8_D("APDU Rx<", pRx, pRspTrans.len); + + return SM_OK; +} + +smStatus_t smComT1oI2C_ComReset(void *conn_ctx) +{ + ESESTATUS status = ESESTATUS_SUCCESS; + status = phNxpEse_deInit(conn_ctx); + if (status != ESESTATUS_SUCCESS) { + SMLOG_E("Failed to Reset 7816 protocol instance "); + return SM_NOT_OK; + } + return SM_OK; +} diff --git a/src/lib/apdu/smCom.h b/src/lib/apdu/smCom.h new file mode 100644 index 0000000..052f317 --- /dev/null +++ b/src/lib/apdu/smCom.h @@ -0,0 +1,34 @@ +/** @file smCom.h + * @brief SmCom APIs. + * + * Copyright 2021,2022 NXP + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @par Description + * Interface of installable communication layer to exchange APDU's between Host and Secure Module. + */ + +#ifndef SMCOM_H_INC +#define SMCOM_H_INC + +/* ********************** Include files ********************** */ +#include "lib/apdu/se05x_tlv.h" + +/* ********************** Function Prototypes ********************** */ +#ifdef __cplusplus +extern "C" { +#endif + +smStatus_t smComT1oI2C_Close(void *conn_ctx, uint8_t mode); +smStatus_t smComT1oI2C_Init(void **conn_ctx, const char *pConnString); +smStatus_t smComT1oI2C_Open(void *conn_ctx, uint8_t mode, uint8_t seqCnt, uint8_t *T1oI2Catr, size_t *T1oI2CatrLen); +smStatus_t smComT1oI2C_TransceiveRaw(void *conn_ctx, uint8_t *pTx, size_t txLen, uint8_t *pRx, size_t *pRxLen); +smStatus_t smComT1oI2C_ComReset(void *conn_ctx); + +#ifdef __cplusplus +} +#endif + +#endif //#ifndef SMCOM_H_INC diff --git a/src/lib/t1oi2c/phEseStatus.h b/src/lib/t1oi2c/phEseStatus.h new file mode 100644 index 0000000..a1aa34c --- /dev/null +++ b/src/lib/t1oi2c/phEseStatus.h @@ -0,0 +1,411 @@ +/* + * Copyright 2010-2014,2018-2019,2022,2026 NXP + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * ESE Status Values - Function Return Codes + */ + +#ifndef PHESESTATUS_H +#define PHESESTATUS_H + +#include "lib/t1oi2c/phEseTypes.h" + +/* Internally required by PHESESTVAL. */ +#define PHESESTSHL8 (8U) +/* Required by PHESESTVAL. */ +#define PHESESTBLOWER ((ESESTATUS)(0x00FFU)) + +/* + * ESE Status Composition Macro + * + * This is the macro which must be used to compose status values. + * + * phEseCompID Component ID, as defined in phEseCompId.h . + * phEseStatus Status values, as defined in phEseStatus.h . + * + * The macro is not required for the ESESTATUS_SUCCESS value. + * This is the only return value to be used directly. + * For all other values it shall be used in assignment and conditional statements, e.g.: + * ESESTATUS status = PHESESTVAL(phEseCompID, phEseStatus); ... + * if (status == PHESESTVAL(phEseCompID, phEseStatus)) ... + */ +#define PHESESTVAL(phEseCompID, phEseStatus) \ + (((phEseStatus) == (ESESTATUS_SUCCESS)) ? \ + (ESESTATUS_SUCCESS) : \ + ((((ESESTATUS)(phEseStatus)) & (PHESESTBLOWER)) | (((uint16_t)(phEseCompID)) << (PHESESTSHL8)))) + +/* + * PHESESTATUS + * Get grp_retval from Status Code + */ +#define PHESESTATUS(phEseStatus) ((phEseStatus) & 0x00FFU) +#define PHESECID(phEseStatus) (((phEseStatus) & 0xFF00U) >> 8) + +/* + * Status Codes + * + * Generic Status codes for the ESE components. Combined with the Component ID + * they build the value (status) returned by each function. + * Example: + * grp_comp_id "Component ID" - e.g. 0x10, plus + * status code as listed in this file - e.g. 0x03 + * result in a status value of 0x0003. + */ + +/* + * The function indicates successful completion + */ +#define ESESTATUS_SUCCESS (0x0000) + +/* + * The function indicates successful completion + */ +#define ESESTATUS_OK (ESESTATUS_SUCCESS) + +/* + * At least one parameter could not be properly interpreted + */ +#define ESESTATUS_INVALID_PARAMETER (0x0001) + +/* + * Invalid buffer provided by application + * */ +#define ESESTATUS_INVALID_BUFFER (0x0002) + +/* + * The buffer provided by the caller is too small + */ +#define ESESTATUS_BUFFER_TOO_SMALL (0x0003) + +/* + * Invalid class byte provided by application + * */ +#define ESESTATUS_INVALID_CLA (0x0004) + +/* + * Invalid command pdu type provided by application + * */ +#define ESESTATUS_INVALID_CPDU_TYPE (0x0005) + +/* + * Invalid command LE type provided by application + * */ +#define ESESTATUS_INVALID_LE_TYPE (0x0007) + +/* + * Device specifier/handle value is invalid for the operation + */ +#define ESESTATUS_INVALID_DEVICE (0x0006) + +/* + * The function executed successfully but could have returned + * more information than space provided by the caller + */ +#define ESESTATUS_MORE_FRAME (0x0008) + +/* + * No response from the remote device received: Time-out + */ +#define ESESTATUS_LAST_FRAME (0x0009) + +/* + * CRC Error during data transaction with the device + */ +#define ESESTATUS_CRC_ERROR (0x000A) + +/* + * SOF Error during data transaction with the device + */ +#define ESESTATUS_SOF_ERROR (0x000B) + +/* + * Not enough resources Memory, Timer etc(e.g. allocation failed.) + */ +#define ESESTATUS_INSUFFICIENT_RESOURCES (0x000C) + +/* + * A non-blocking function returns this immediately to indicate + * that an internal operation is in progress + */ +#define ESESTATUS_PENDING (0x000D) + +/* + * A board communication error occurred + * (e.g. Configuration went wrong) + */ +#define ESESTATUS_BOARD_COMMUNICATION_ERROR (0x000F) + +/* + * Invalid State of the particular state machine + */ +#define ESESTATUS_INVALID_STATE (0x0011) + +/* + * This Layer is Not initialized, hence initialization required. + */ +#define ESESTATUS_NOT_INITIALISED (0x0031) + +/* + * The Layer is already initialized, hence initialization repeated. + */ +#define ESESTATUS_ALREADY_INITIALISED (0x0032) + +/* + * Feature not supported + */ +#define ESESTATUS_FEATURE_NOT_SUPPORTED (0x0033) + +/* + * Parity Error + */ +#define ESESTATUS_PARITY_ERROR (0x0034) + +/* The Registration command has failed because the user wants to register on + * an element for which he is already registered + */ +#define ESESTATUS_ALREADY_REGISTERED (0x0035) + +/* Chained frame is being sent */ +#define ESESTATUS_CHAINED_FRAME (0x0036) + +/* + * Single frame is sent + */ +#define ESESTATUS_SINGLE_FRAME (0x0037) + +/* + * A DESELECT event has occurred + */ +#define ESESTATUS_DESELECTED (0x0038) + +/* + * A RELEASE event has occurred + */ +#define ESESTATUS_RELEASED (0x0039) + +/* + * The operation is currently not possible or not allowed + */ +#define ESESTATUS_NOT_ALLOWED (0x003A) + +/* + * Other indicaated error sent by JCOP. + */ +#define ESESTATUS_OTHER_ERROR (0x003C) +/* + * The system is busy with the firmware download operation. + */ +#define ESESTATUS_DWNLD_BUSY (0x006E) + +/* + * The system is busy with the previous operation. + */ +#define ESESTATUS_BUSY (0x006F) + +/* NDEF Mapping error codes */ + +/* The remote device (type) is not valid for this request. */ +#define ESESTATUS_INVALID_REMOTE_DEVICE (0x001D) + +/* Read operation failed */ +#define ESESTATUS_READ_FAILED (0x0014) + +/* + * Write operation failed + */ +#define ESESTATUS_WRITE_FAILED (0x0015) + +/* Non Ndef Compliant */ +#define ESESTATUS_NO_NDEF_SUPPORT (0x0016) + +/* resend the frame with seq_counter 0*/ +#define ESESTATUS_RESET_SEQ_COUNTER_FRAME_RESEND (0x001A) + +/* Incorrect number of bytes received from the card*/ +#define ESESTATUS_INVALID_RECEIVE_LENGTH (0x001B) + +/* The data format/composition is not understood/correct. */ +#define ESESTATUS_INVALID_FORMAT (0x001C) + +/* There is not sufficient storage available. */ +#define ESESTATUS_INSUFFICIENT_STORAGE (0x001F) + +/* The last command would be re-sent */ +#define ESESTATUS_FRAME_RESEND (0x0023) + +/* The write timeout error */ +#define ESESTATUS_WRITE_TIMEOUT (0x0024) + +/* + * Response Time out for the control message(ESEC not responded) + */ +#define ESESTATUS_RESPONSE_TIMEOUT (0x0025) + +/* + * Resend the last R Frame + */ +#define ESESTATUS_FRAME_RESEND_R_FRAME (0x0026) + +/* + * Send next chained frame + */ +#define ESESTATUS_SEND_NEXT_FRAME (0x0027) + +/* + * Protocol revovery started + */ +#define ESESTATUS_REVOCERY_STARTED (0x0028) + +/* + * Single Target Detected + */ +#define ESESTATUS_SEND_R_FRAME (0x0029) + +/* + * Resend the RNAK + */ + +#define ESESTATUS_FRAME_RESEND_RNAK (0x0030) + +/* + * Resend the last R Frame + */ +#define ESESTATUS_FRAME_SEND_R_FRAME (0x003B) + +/* + * Unknown error Status Codes + */ +#define ESESTATUS_UNKNOWN_ERROR (0x00FE) + +/* + * Status code for failure + */ +#define ESESTATUS_FAILED (0x00FF) + +/* + * The function/command has been aborted + */ +#define ESESTATUS_CMD_ABORTED (0x0002) + +/* + * No target found after poll + */ +#define ESESTATUS_NO_TARGET_FOUND (0x000A) + +/* Attempt to disconnect a not connected remote device. */ +#define ESESTATUS_NO_DEVICE_CONNECTED (0x000B) + +/* requesting a resynchronization */ +#define ESESTATUS_RESYNCH_REQ (0x000E) + +/* + * acknowledging resynchronization + */ +#define ESESTATUS_RESYNCH_RES (0x0010) + +/* + * S-block offering a maximum size of the information field + */ +#define ESESTATUS_IFS_REQ (0x001E) + +/* S-block offering a maximum size of the information field */ +#define ESESTATUS_IFS_RES (0x0017) + +/* S-block requesting a chain abortion */ +#define ESESTATUS_ABORT_REQ (0x00F0) + +/*S-block acknowledging the chain abortion*/ +#define ESESTATUS_ABORT_RES (0x00F2) + +/* S-block requesting a waiting time extension*/ +#define ESESTATUS_WTX_REQ (0x00F5) + +/* S-block acknowledging the waiting time extension */ +#define ESESTATUS_WTX_RES (0x00F6) + +/* S-block interface reset request */ +#define ESESTATUS_RESET_REQ (0x00F7) + +/* S-block interface reset response */ +#define ESESTATUS_RESET_RES (0x00F8) + +/* S-block requesting a end of apdu transfer*/ +#define ESESTATUS_END_APDU_REQ (0x00F9) + +/* S-block acknowledging end of apdu transfer*/ +#define ESESTATUS_END_APDU_RES (0x00FA) + +/* + * Shutdown in progress, cannot handle the request at this time. + */ +#define ESESTATUS_SHUTDOWN (0x0091) + +/* + * Target is no more in RF field + */ +#define ESESTATUS_TARGET_LOST (0x0092) + +/* + * Request is rejected + */ +#define ESESTATUS_REJECTED (0x0093) + +/* + * Target is not connected + */ +#define ESESTATUS_TARGET_NOT_CONNECTED (0x0094) + +/* + * Invalid handle for the operation + */ +#define ESESTATUS_INVALID_HANDLE (0x0095) + +/* + * Process aborted + */ +#define ESESTATUS_ABORTED (0x0096) + +/* + * Requested command is not supported + */ +#define ESESTATUS_COMMAND_NOT_SUPPORTED (0x0097) + +/* + * Tag is not NDEF compilant + */ +#define ESESTATUS_NON_NDEF_COMPLIANT (0x0098) + +/* + * Not enough memory available to complete the requested operation + */ +#define ESESTATUS_NOT_ENOUGH_MEMORY (0x001F) + +/* + * Indicates incoming connection + */ +#define ESESTATUS_INCOMING_CONNECTION (0x0045) + +/* + * Indicates Connection was successful + */ +#define ESESTATUS_CONNECTION_SUCCESS (0x0046) + +/* + * Indicates Connection failed + */ +#define ESESTATUS_CONNECTION_FAILED (0x0047) + +#endif /* PHESESTATUS_H */ diff --git a/src/lib/t1oi2c/phEseTypes.h b/src/lib/t1oi2c/phEseTypes.h new file mode 100644 index 0000000..86934e9 --- /dev/null +++ b/src/lib/t1oi2c/phEseTypes.h @@ -0,0 +1,44 @@ +/* + * Copyright 2010-2014,2018-2019,2022 NXP + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef PHESETYPES_H +#define PHESETYPES_H +#include +#include + +typedef uint8_t utf8_t; /* UTF8 Character String */ +typedef uint8_t bool_t; /* boolean data type */ +typedef uint16_t ESESTATUS; /* Return values */ + +#define ENABLE_T1oI2C_LOGS 0 + +#if ENABLE_T1oI2C_LOGS +#define T_SMLOG_I(...) SMLOG_I(__VA_ARGS__) +#define T_SMLOG_E(...) SMLOG_E(__VA_ARGS__) +#define T_SMLOG_W(...) SMLOG_W(__VA_ARGS__) +#define T_SMLOG_D(...) SMLOG_D(__VA_ARGS__) +#define T_SMLOG_AU8_D(BUF, LEN) SMLOG_AU8_D(BUF, LEN) +#define T_SMLOG_MAU8_D(MSG, BUF, LEN) SMLOG_MAU8_D(MSG, BUF, LEN) +#else +#define T_SMLOG_I(...) +#define T_SMLOG_E(...) +#define T_SMLOG_W(...) +#define T_SMLOG_D(...) +#define T_SMLOG_AU8_D(BUF, LEN) +#define T_SMLOG_MAU8_D(MSG, BUF, LEN) +#endif //#if ENABLE_T1oI2C_LOGS + +#endif /* PHESETYPES_H */ diff --git a/src/lib/t1oi2c/phNxpEsePal_i2c.c b/src/lib/t1oi2c/phNxpEsePal_i2c.c new file mode 100644 index 0000000..90ce6a4 --- /dev/null +++ b/src/lib/t1oi2c/phNxpEsePal_i2c.c @@ -0,0 +1,251 @@ +/* + * Copyright 2010-2014,2018-2020,2022,2026 NXP + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include "lib/platform/arduino/sm_i2c.h" +#include "lib/platform/arduino/sm_timer.h" +#include "lib/platform/arduino/sm_port.h" + +#define MAX_RETRY_CNT 10 + +static int gBackoffDelay = 0; + +/******************************************************************************* +** +** Function phPalEse_i2c_back_off_delay_reset +** +** Description Back off delay is reset to 0 +** +** param[in] None +** +** Returns None +** +*******************************************************************************/ +static void phPalEse_i2c_back_off_delay_reset() +{ + T_SMLOG_D("phPalEse_i2c_back_off_delay_reset"); + gBackoffDelay = 0; +} + +/******************************************************************************* +** +** Function phPalEse_i2c_back_off_delay_wait +** +** Description Delay is incremented by 1 for every call +** +** param[in] None +** +** Returns None +** +*******************************************************************************/ +static void phPalEse_i2c_back_off_delay_wait() +{ + if (gBackoffDelay < 200) { + gBackoffDelay += 1; + } + T_SMLOG_D("phPalEse_i2c_back_off_delay_wait: %d", gBackoffDelay); + sm_sleep(gBackoffDelay); +} + +/******************************************************************************* +** +** Function phPalEse_i2c_is_retryable_error +** +** Description Check if the I2C error is retryable based on platform +** +** param[in] ret - I2C error code +** +** Returns 1 if error is retryable, 0 otherwise +** +*******************************************************************************/ +static int phPalEse_i2c_is_retryable_error(unsigned int ret) +{ + /* if platform returns different error codes, modify the check below.*/ +#ifdef T1OI2C_RETRY_ON_I2C_FAILED + if ((ret == I2C_FAILED) || (ret == I2C_NACK_ON_ADDRESS) || (ret == I2C_NACK_ON_DATA)) { + return 1; + } +#else + if ((ret == I2C_NACK_ON_ADDRESS) || (ret == I2C_NACK_ON_DATA)) { + return 1; + } +#endif + return 0; +} + +/******************************************************************************* +** +** Function phPalEse_i2c_close +** +** Description Closes PN547 device +** +** param[in] pDevHandle - device handle +** +** Returns None +** +*******************************************************************************/ +void phPalEse_i2c_close(void *pDevHandle) +{ +#ifdef Android + if (NULL != pDevHandle) { + close((intptr_t)pDevHandle); + } +#endif + axI2CTerm(pDevHandle, 0); + pDevHandle = NULL; + + return; +} + +/******************************************************************************* +** +** Function phPalEse_i2c_open_and_configure +** +** Description Open and configure pn547 device +** +** param[in] pConfig - hardware information +** +** Returns ESE status: +** ESESTATUS_SUCCESS - open_and_configure operation success +** ESESTATUS_INVALID_DEVICE - device open operation failure +** +*******************************************************************************/ +ESESTATUS phPalEse_i2c_open_and_configure(pphPalEse_Config_t pConfig) +{ + void *conn_ctx = NULL; + int retryCnt = 0; + unsigned int i2c_ret = 0; + + // Initializing Global variable gBackoffDelay + phPalEse_i2c_back_off_delay_reset(); + + T_SMLOG_D("%s Opening port", __FUNCTION__); + + /*Disable as interface reset happens on every session open*/ + //se05x_ic_reset(); + +retry: + i2c_ret = axI2CInit(&conn_ctx, (const char *)pConfig->pDevName); + if (i2c_ret != I2C_OK) { + T_SMLOG_E("%s Failed retry ", __FUNCTION__); + if (i2c_ret == I2C_BUSY) { + retryCnt++; + T_SMLOG_E("Retry open eSE driver, retry cnt : %d ", retryCnt); + if (retryCnt < MAX_RETRY_CNT) { + sm_sleep(ESE_POLL_DELAY_MS); + goto retry; + } + } + T_SMLOG_E("I2C init Failed: retval %x ", i2c_ret); + pConfig->pDevHandle = NULL; + return ESESTATUS_INVALID_DEVICE; + } + T_SMLOG_D("I2C driver Initialized :: fd = [%d] ", i2c_ret); + pConfig->pDevHandle = conn_ctx; + return ESESTATUS_SUCCESS; +} + +/******************************************************************************* +** +** Function phPalEse_i2c_read +** +** Description Reads requested number of bytes from pn547 device into given buffer +** +** param[in] pDevHandle - valid device handle +** param[in] pBuffer - buffer for read data +** param[in] nNbBytesToRead - number of bytes requested to be read +** +** Returns numRead - number of successfully read bytes +** -1 - read operation failure +** +*******************************************************************************/ +int phPalEse_i2c_read(void *pDevHandle, uint8_t *pBuffer, int nNbBytesToRead) +{ + unsigned int ret = 0; + int retryCount = 0; + int numRead = 0; + + T_SMLOG_D("%s Read Requested %d bytes ", __FUNCTION__, nNbBytesToRead); + while (numRead != nNbBytesToRead) { + ret = axI2CRead(pDevHandle, I2C_BUS_0, SMCOM_I2C_ADDRESS, pBuffer, nNbBytesToRead); + if (ret != I2C_OK) { + T_SMLOG_D("_i2c_read() error : %d ", ret); + if (phPalEse_i2c_is_retryable_error(ret)) { + /* Back-off delay wait with 1ms */ + phPalEse_i2c_back_off_delay_wait(); + if(retryCount < MAX_RETRY_COUNT) { + retryCount++; + T_SMLOG_D("_i2c_read() failed. Going to retry, counter:%d !", retryCount); + continue; + } + } + return -1; + } + else { + phPalEse_i2c_back_off_delay_reset(); + numRead = nNbBytesToRead; + break; + } + } + return numRead; +} + + +/******************************************************************************* +** +** Function phPalEse_i2c_write +** +** Description Writes requested number of bytes from given buffer into pn547 device +** +** param[in] pDevHandle - valid device handle +** param[in] pBuffer - buffer for read data +** param[in] nNbBytesToWrite - number of bytes requested to be written +** +** Returns numWrote - number of successfully written bytes +** -1 - write operation failure +** +*******************************************************************************/ +int phPalEse_i2c_write(void *pDevHandle, uint8_t *pBuffer, int nNbBytesToWrite) +{ + unsigned int ret = I2C_OK; + int retryCount = 0; + int numWrote = 0; + + pBuffer[0] = 0x5A; //Recovery if stack forgot to add NAD byte. + + do { + ret = axI2CWrite(pDevHandle, I2C_BUS_0, SMCOM_I2C_ADDRESS, pBuffer, nNbBytesToWrite); + if (ret != I2C_OK) { + T_SMLOG_D("_i2c_write() error : %d ", ret); + if (phPalEse_i2c_is_retryable_error(ret) && (retryCount < MAX_RETRY_COUNT)) { + /* Back-off delay wait with 1ms */ + phPalEse_i2c_back_off_delay_wait(); + retryCount++; + T_SMLOG_D("_i2c_write() failed. Going to retry, counter:%d !", retryCount); + continue; + } + return -1; + } + else { + phPalEse_i2c_back_off_delay_reset(); + numWrote = nNbBytesToWrite; + break; + } + } while (ret != I2C_OK); + + return numWrote; +} diff --git a/src/lib/t1oi2c/phNxpEsePal_i2c.h b/src/lib/t1oi2c/phNxpEsePal_i2c.h new file mode 100644 index 0000000..1a45e4e --- /dev/null +++ b/src/lib/t1oi2c/phNxpEsePal_i2c.h @@ -0,0 +1,104 @@ +/* + * Copyright 2010-2014,2018-2020,2022,2026 NXP + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * \addtogroup eSe_PAL_I2C + * \brief PAL I2C port implementation for linux + * @{ */ +#ifndef _PHNXPESE_PAL_I2C_H +#define _PHNXPESE_PAL_I2C_H + +/* Basic type definitions */ +#include + +/*! + * \brief ESE Poll timeout (min 1 miliseconds) + */ +#define ESE_POLL_DELAY_MS (1) + +/*! + * \brief ESE Poll timeout. + * As Max WTX timeout is 1sec, select ESE_NAD_POLLING_MAX count in such a way that WTX request from SE is not missed. + * + */ +#if defined(QN9090DK6) +#define ESE_NAD_POLLING_MAX (2 * 30) +#else +#define ESE_NAD_POLLING_MAX (500) +#endif + +/*! + * \brief Max retry count for Write + */ +#define MAX_RETRY_COUNT 8 + +/*! + * \brief ESE wakeup delay in case of write error retry + */ +#define WAKE_UP_DELAY_MS 5 //5 ms +/*! + * \brief ESE wakeup delay in case of write error retry + */ +#define NAD_POLLING_SCALER 1 +/*! + * \brief ESE wakeup delay in case of write error retry + */ +#define CHAINED_PKT_SCALER 1 +/*! + * \brief This function is used to set slave address of ESE + * + */ +// #define I2C_MASTER_SLAVE_ADDR_7BIT (0x90U >> 1) //slve bit address is 20U but driver do right shift so set to 40U +#define SMCOM_I2C_ADDRESS (0x90) + +// Enable t=1oi2c retry +#define T1OI2C_RETRY_ON_I2C_FAILED + +/*! + * \ingroup eSe_PAL_I2C + * + * \brief PAL Configuration exposed to upper layer. + */ +typedef struct phPalEse_Config +{ + int8_t *pDevName; + /*!< Port name connected to ESE + * + * Platform specific canonical device name to which ESE is connected. + * + * e.g. On Linux based systems this would be /dev/p73 + */ + + int8_t DeviceAddress; + /*!< I2C Address of SE connected + */ + + uint32_t dwBaudRate; + /*!< Communication speed between DH and ESE + * + * This is the baudrate of the bus for communication between DH and ESE + */ + + void *pDevHandle; + /*!< Device handle output */ +} phPalEse_Config_t, *pphPalEse_Config_t; /* pointer to phPalEse_Config_t */ + +void phPalEse_i2c_close(void *pDevHandle); +ESESTATUS phPalEse_i2c_open_and_configure(pphPalEse_Config_t pConfig); +int phPalEse_i2c_read(void *pDevHandle, uint8_t *pBuffer, int nNbBytesToRead); +int phPalEse_i2c_write(void *pDevHandle, uint8_t *pBuffer, int nNbBytesToWrite); +/** @} */ +#endif /* _PHNXPESE_PAL_I2C_H */ diff --git a/src/lib/t1oi2c/phNxpEseProto7816_3.c b/src/lib/t1oi2c/phNxpEseProto7816_3.c new file mode 100644 index 0000000..773845f --- /dev/null +++ b/src/lib/t1oi2c/phNxpEseProto7816_3.c @@ -0,0 +1,1782 @@ +/* + * Copyright 2012-2014,2018-2020,2022,2024 NXP + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include "lib/platform/arduino/sm_timer.h" +#include "lib/apdu/se05x_tlv.h" +#include "lib/platform/arduino/sm_port.h" +#include + +/** + * \addtogroup ISO7816-3_protocol_lib + * + * @{ */ + +phNxpEseProto7816_t phNxpEseProto7816_3_Var; + +/****************************************************************************** +\section Introduction Introduction + + * This module provide the 7816-3 protocol level implementation for ESE + * + ******************************************************************************/ +static bool_t phNxpEseProto7816_SendRawFrame(void *conn_ctx, uint32_t data_len, uint8_t *p_data); +static bool_t phNxpEseProto7816_GetRawFrame(void *conn_ctx, uint32_t *data_len, uint8_t **pp_data); +static uint16_t phNxpEseProto7816_ComputeCRC(unsigned char *p_buff, uint32_t offset, uint32_t length); +static bool_t phNxpEseProto7816_CheckCRC(uint32_t data_len, uint8_t *p_data); +static bool_t phNxpEseProto7816_SendSFrame(void *conn_ctx, sFrameInfo_t sFrameData); +static bool_t phNxpEseProto7816_SendIframe(void *conn_ctx, iFrameInfo_t iFrameData); +static bool_t phNxpEseProto7816_sendRframe(void *conn_ctx, rFrameTypes_t rFrameType); +static bool_t phNxpEseProto7816_SetFirstIframeContxt(void); +static bool_t phNxpEseProto7816_SetNextIframeContxt(void); +static bool_t phNxpEseProro7816_SaveRxframeData(uint8_t *p_data, uint32_t data_len); +static bool_t phNxpEseProto7816_ResetRecovery(void); +static bool_t phNxpEseProto7816_RecoverySteps(void); +static bool_t phNxpEseProto7816_DecodeFrame(uint8_t *p_data, uint32_t data_len); +static bool_t phNxpEseProto7816_ProcessResponse(void *conn_ctx); +static bool_t TransceiveProcess(void *conn_ctx); +static bool_t phNxpEseProto7816_RSync(void *conn_ctx); + +/****************************************************************************** + * Function phNxpEseProto7816_SendRawFrame + * + * Description This internal function is called send the data to ESE + * + * param[in] uint32_t: number of bytes to be written + * param[in] uint8_t : data buffer + * + * Returns On success return TRUE or else FALSE. + * + ******************************************************************************/ +static bool_t phNxpEseProto7816_SendRawFrame(void *conn_ctx, uint32_t data_len, uint8_t *p_data) +{ + ESESTATUS status = ESESTATUS_FAILED; + status = phNxpEse_WriteFrame(conn_ctx, data_len, p_data); + if (ESESTATUS_SUCCESS != status) { + T_SMLOG_E("%s Error phNxpEse_WriteFrame ", __FUNCTION__); + } + + return (status == ESESTATUS_SUCCESS) ? TRUE : FALSE; +} + +/****************************************************************************** + * Function phNxpEseProto7816_GetRawFrame + * + * Description This internal function is called read the data from the ESE + * + * param[out] uint32_t: number of bytes read + * param[out] uint8_t : Read data from ESE + * + * Returns On success return TRUE or else FALSE. + * + ******************************************************************************/ +static bool_t phNxpEseProto7816_GetRawFrame(void *conn_ctx, uint32_t *data_len, uint8_t **pp_data) +{ + bool_t bStatus = FALSE; + ESESTATUS status = ESESTATUS_FAILED; + + status = phNxpEse_read(conn_ctx, data_len, pp_data); + if (ESESTATUS_SUCCESS != status) { + T_SMLOG_E("%s phNxpEse_read failed , status : 0x%x ", __FUNCTION__, status); + } + else { + bStatus = TRUE; + } + return bStatus; +} + +/****************************************************************************** + * Function phNxpEseProto7816_ComputeCRC + * + * Description This internal function is called compute the CRC + * + * param[in] unsigned char: data buffer + * param[in] uint32_t : offset from which CRC to be calculated + * param[in] uint32_t : total length of frame + * + * Returns On success return TRUE or else FALSE. + * + ******************************************************************************/ +static uint16_t phNxpEseProto7816_ComputeCRC(unsigned char *p_buff, uint32_t offset, uint32_t length) +{ + uint16_t CAL_CRC = 0xFFFF, CRC1 = 0x0000; + uint32_t i = 0; + + ENSURE_OR_GO_EXIT(p_buff != NULL); + + for (i = offset; i < length; i++) { + CAL_CRC ^= p_buff[i]; + for (int bit = 8; bit > 0; --bit) { + if ((CAL_CRC & 0x0001) == 0x0001) { + CAL_CRC = (unsigned short)((CAL_CRC >> 1) ^ 0x8408); + } + else { + CAL_CRC >>= 1; + } + } + } + CAL_CRC ^= 0xFFFF; +#if defined(T1oI2C_UM11225) + CRC1 = ((CAL_CRC & 0xFF) << 8) | ((CAL_CRC >> 8) & 0xFF); +#elif defined(T1oI2C_GP1_0) + CRC1 = CAL_CRC; +#endif +exit: + return (uint16_t)CRC1; +} + +/****************************************************************************** + * Function phNxpEseProto7816_CheckCRC + * + * Description This internal function is called compute and compare the + * received CRC of the received data + * + * param[in] uint32_t : frame length + * param[in] uint8_t: data buffer + * + * Returns On success return TRUE or else FALSE. + * + ******************************************************************************/ +static bool_t phNxpEseProto7816_CheckCRC(uint32_t data_len, uint8_t *p_data) +{ + bool_t status = FALSE; + uint16_t calc_crc = 0; + uint16_t recv_crc = 0; + + ENSURE_OR_GO_EXIT(p_data != NULL); + ENSURE_OR_GO_EXIT(data_len < MAX_APDU_BUFFER); + ENSURE_OR_GO_EXIT(data_len >= 2); + + status = TRUE; + + recv_crc = p_data[data_len - 2] << 8 | p_data[data_len - 1]; //combine 2 byte CRC + + /* calculate the CRC after excluding Recieved CRC */ + /* CRC calculation includes NAD byte, so offset is set to 0 */ + calc_crc = phNxpEseProto7816_ComputeCRC(p_data, 0, (data_len - 2)); + T_SMLOG_D("Received CRC:0x%x Calculated CRC:0x%x ", recv_crc, calc_crc); + if (recv_crc != calc_crc) { + status = FALSE; + T_SMLOG_E("%s CRC failed ", __FUNCTION__); + } +exit: + return status; +} + +/****************************************************************************** + * Function getMaxSupportedSendIFrameSize + * + * Description This internal function is called to get the max supported + * I-frame size + * + * param[in] void + * + * Returns IFSC_SIZE_SEND + * + ******************************************************************************/ +uint8_t getMaxSupportedSendIFrameSize(void) +{ + return IFSC_SIZE_SEND; +} + +/****************************************************************************** + * Function phNxpEseProto7816_SendSFrame + * + * Description This internal function is called to send S-frame with all + * updated 7816-3 headers + * + * param[in] sFrameInfo_t: Info about S frame + * + * Returns On success return TRUE or else FALSE. + * + ******************************************************************************/ +static bool_t phNxpEseProto7816_SendSFrame(void *conn_ctx, sFrameInfo_t sFrameData) +{ + bool_t status = ESESTATUS_FAILED; + uint32_t frame_len = 0; + uint8_t p_framebuff[7] = {0}; + uint8_t pcb_byte = 0; + sFrameInfo_t sframeData = sFrameData; + uint16_t calc_crc = 0; + /* This update is helpful in-case a R-NACK is transmitted from the MW */ + phNxpEseProto7816_3_Var.lastSentNonErrorframeType = SFRAME; + switch (sframeData.sFrameType) { + case RESYNCH_REQ: + frame_len = (PH_PROTO_7816_HEADER_LEN + PH_PROTO_7816_CRC_LEN); + p_framebuff[PH_PROPTO_7816_LEN_UPPER_OFFSET] = 0; +#if defined(T1oI2C_GP1_0) + /* T =1 GP block format LEN field is of 2 byte*/ + p_framebuff[PH_PROPTO_7816_LEN_LOWER_OFFSET] = 0; +#endif + p_framebuff[PH_PROPTO_7816_INF_BYTE_OFFSET] = 0x00; + + pcb_byte |= PH_PROTO_7816_S_BLOCK_REQ; /* PCB */ + pcb_byte |= PH_PROTO_7816_S_RESYNCH; + break; +#if defined(T1oI2C_UM11225) + case INTF_RESET_REQ: + frame_len = (PH_PROTO_7816_HEADER_LEN + PH_PROTO_7816_CRC_LEN); + p_framebuff[PH_PROPTO_7816_LEN_UPPER_OFFSET] = 0; + p_framebuff[PH_PROPTO_7816_INF_BYTE_OFFSET] = 0x00; + + pcb_byte |= PH_PROTO_7816_S_BLOCK_REQ; /* PCB */ + pcb_byte |= PH_PROTO_7816_S_RESET; + break; + case PROP_END_APDU_REQ: + frame_len = (PH_PROTO_7816_HEADER_LEN + PH_PROTO_7816_CRC_LEN); + p_framebuff[PH_PROPTO_7816_LEN_UPPER_OFFSET] = 0; + p_framebuff[PH_PROPTO_7816_INF_BYTE_OFFSET] = 0x00; + + pcb_byte |= PH_PROTO_7816_S_BLOCK_REQ; /* PCB */ + pcb_byte |= PH_PROTO_7816_S_END_OF_APDU; + break; + case ATR_REQ: + frame_len = (PH_PROTO_7816_HEADER_LEN + PH_PROTO_7816_CRC_LEN); + p_framebuff[PH_PROPTO_7816_LEN_UPPER_OFFSET] = 0; + p_framebuff[PH_PROPTO_7816_INF_BYTE_OFFSET] = 0x00; + + pcb_byte |= PH_PROTO_7816_S_BLOCK_REQ; /* PCB */ + pcb_byte |= PH_PROTO_7816_S_GET_ATR; + break; +#endif + case DEEP_PWR_DOWN_REQ: + frame_len = (PH_PROTO_7816_HEADER_LEN + PH_PROTO_7816_CRC_LEN); + p_framebuff[PH_PROPTO_7816_LEN_UPPER_OFFSET] = 0; + p_framebuff[PH_PROPTO_7816_INF_BYTE_OFFSET] = 0x00; + + pcb_byte |= PH_PROTO_7816_S_BLOCK_REQ; /* PCB */ + pcb_byte |= PH_PROTO_7816_S_DEEP_PWR_DOWN; + break; + case WTX_RSP: + frame_len = (PH_PROTO_7816_HEADER_LEN + 1 + PH_PROTO_7816_CRC_LEN); +#if defined(T1oI2C_UM11225) + /* T =1 UM11225 SE050 block format LEN field is of 2 byte*/ + p_framebuff[PH_PROPTO_7816_LEN_UPPER_OFFSET] = 0x01; +#elif defined(T1oI2C_GP1_0) + /* T =1 GP block format LEN field is of 2 byte*/ + p_framebuff[PH_PROPTO_7816_LEN_UPPER_OFFSET] = 0x00; + p_framebuff[PH_PROPTO_7816_LEN_LOWER_OFFSET] = 0x01; +#endif + p_framebuff[PH_PROPTO_7816_INF_BYTE_OFFSET] = 0x01; + + pcb_byte |= PH_PROTO_7816_S_BLOCK_RSP; + pcb_byte |= PH_PROTO_7816_S_WTX; + break; +#if defined(T1oI2C_UM11225) + case CHIP_RESET_REQ: + frame_len = (PH_PROTO_7816_HEADER_LEN + PH_PROTO_7816_CRC_LEN); + p_framebuff[PH_PROPTO_7816_LEN_UPPER_OFFSET] = 0; + p_framebuff[PH_PROPTO_7816_INF_BYTE_OFFSET] = 0x00; + + pcb_byte |= PH_PROTO_7816_S_BLOCK_REQ; /* PCB */ + pcb_byte |= PH_PROTO_7816_S_CHIP_RST; + break; +#endif +#if defined(T1oI2C_GP1_0) + case SWR_REQ: + frame_len = (PH_PROTO_7816_HEADER_LEN + PH_PROTO_7816_CRC_LEN); + p_framebuff[PH_PROPTO_7816_LEN_UPPER_OFFSET] = 0; + p_framebuff[PH_PROPTO_7816_LEN_LOWER_OFFSET] = 0; + p_framebuff[PH_PROPTO_7816_INF_BYTE_OFFSET] = 0x00; + + pcb_byte |= PH_PROTO_7816_S_BLOCK_REQ; /* PCB */ + pcb_byte |= PH_PROTO_7816_S_SWR; + break; + case RELEASE_REQ: + frame_len = (PH_PROTO_7816_HEADER_LEN + PH_PROTO_7816_CRC_LEN); + p_framebuff[PH_PROPTO_7816_LEN_UPPER_OFFSET] = 0; + p_framebuff[PH_PROPTO_7816_LEN_LOWER_OFFSET] = 0; + p_framebuff[PH_PROPTO_7816_INF_BYTE_OFFSET] = 0x00; + + pcb_byte |= PH_PROTO_7816_S_BLOCK_REQ; /* PCB */ + pcb_byte |= PH_PROTO_7816_S_RELEASE; + break; + case CIP_REQ: + frame_len = (PH_PROTO_7816_HEADER_LEN + PH_PROTO_7816_CRC_LEN); + p_framebuff[PH_PROPTO_7816_LEN_UPPER_OFFSET] = 0; + p_framebuff[PH_PROPTO_7816_LEN_LOWER_OFFSET] = 0; + p_framebuff[PH_PROPTO_7816_INF_BYTE_OFFSET] = 0x00; + + pcb_byte |= PH_PROTO_7816_S_BLOCK_REQ; /* PCB */ + pcb_byte |= PH_PROTO_7816_S_GET_CIP; + break; + case COLD_RESET_REQ: + frame_len = (PH_PROTO_7816_HEADER_LEN + PH_PROTO_7816_CRC_LEN); + p_framebuff[PH_PROPTO_7816_LEN_UPPER_OFFSET] = 0; + p_framebuff[PH_PROPTO_7816_LEN_LOWER_OFFSET] = 0; + p_framebuff[PH_PROPTO_7816_INF_BYTE_OFFSET] = 0x00; + + pcb_byte |= PH_PROTO_7816_S_BLOCK_REQ; /* PCB */ + pcb_byte |= PH_PROTO_7816_S_COLD_RST; + break; +#endif + default: + T_SMLOG_E(" %s :Invalid S-block", __FUNCTION__); + return status; + } + + /* frame the packet */ + p_framebuff[PH_PROPTO_7816_NAD_OFFSET] = 0x5A; /* NAD Byte */ + p_framebuff[PH_PROPTO_7816_PCB_OFFSET] = pcb_byte; /* PCB */ + + calc_crc = phNxpEseProto7816_ComputeCRC(p_framebuff, 0, (frame_len - 2)); + p_framebuff[frame_len - 2] = (calc_crc >> 8) & 0xFF; + p_framebuff[frame_len - 1] = calc_crc & 0xFF; + T_SMLOG_D("S-Frame PCB: %x ", p_framebuff[PH_PROPTO_7816_PCB_OFFSET]); + status = phNxpEseProto7816_SendRawFrame(conn_ctx, frame_len, p_framebuff); + return status; +} + +/****************************************************************************** + * Function phNxpEseProto7816_sendRframe + * + * Description This internal function is called to send R-frame with all + * updated 7816-3 headers + * + * param[in] sFrameInfo_t: Info about R frame + * + * Returns On success return TRUE or else FALSE. + * + ******************************************************************************/ +static bool_t phNxpEseProto7816_sendRframe(void *conn_ctx, rFrameTypes_t rFrameType) +{ + bool_t status = FALSE; +#if defined(T1oI2C_UM11225) + uint8_t recv_ack[5] = {0x5A, 0x80, 0x00, 0x00, 0x00}; +#elif defined(T1oI2C_GP1_0) + uint8_t recv_ack[6] = {0x5A, 0x80, 0x00, 0x00, 0x00, 0x00}; +#endif + uint16_t calc_crc = 0; + iFrameInfo_t *pRx_lastRcvdIframeInfo = &phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.lastRcvdIframeInfo; + rFrameInfo_t *pNextTx_RframeInfo = &phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.RframeInfo; + if (RNACK == rFrameType) /* R-NACK */ + { + switch (pNextTx_RframeInfo->errCode) { + case PARITY_ERROR: + recv_ack[PH_PROPTO_7816_PCB_OFFSET] |= (0x01 & 0xFF); + break; + + case OTHER_ERROR: + recv_ack[PH_PROPTO_7816_PCB_OFFSET] |= (0x02 & 0xFF); + break; + + case SOF_MISSED_ERROR: + case UNDEFINED_ERROR: + recv_ack[PH_PROPTO_7816_PCB_OFFSET] |= (0x03 & 0xFF); + break; + + default: + break; + } + } + else /* R-ACK*/ + { + /* This update is helpful in-case a R-NACK is transmitted from the MW */ + phNxpEseProto7816_3_Var.lastSentNonErrorframeType = RFRAME; + } + + recv_ack[PH_PROPTO_7816_PCB_OFFSET] |= ((pRx_lastRcvdIframeInfo->seqNo ^ 1) << 4); + T_SMLOG_D("%s recv_ack[PH_PROPTO_7816_PCB_OFFSET]:0x%x ", __FUNCTION__, recv_ack[PH_PROPTO_7816_PCB_OFFSET]); + calc_crc = phNxpEseProto7816_ComputeCRC(recv_ack, 0x00, (sizeof(recv_ack) - 2)); + + recv_ack[(sizeof(recv_ack) - 2)] = (calc_crc >> 8) & 0xFF; + recv_ack[(sizeof(recv_ack) - 1)] = calc_crc & 0xFF; + status = phNxpEseProto7816_SendRawFrame(conn_ctx, sizeof(recv_ack), recv_ack); + return status; +} + +/****************************************************************************** + * Function phNxpEseProto7816_SendIframe + * + * Description This internal function is called to send I-frame with all + * updated 7816-3 headers + * + * param[in] sFrameInfo_t: Info about I frame + * + * Returns On success return TRUE or else FALSE. + * + ******************************************************************************/ +static bool_t phNxpEseProto7816_SendIframe(void *conn_ctx, iFrameInfo_t iFrameData) +{ + bool_t status = FALSE; + uint32_t frame_len = 0; + uint8_t p_framebuff[MAX_APDU_BUFFER]; + uint8_t pcb_byte = 0; + uint16_t calc_crc = 0; + iFrameInfo_t *pNextTx_IframeInfo = &phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.IframeInfo; + + if (0 == iFrameData.sendDataLen) { + T_SMLOG_E("%s Line: [%d] I frame Len is 0, INVALID ", __FUNCTION__, __LINE__); + return FALSE; + } + /* This update is helpful in-case a R-NACK is transmitted from the MW */ + phNxpEseProto7816_3_Var.lastSentNonErrorframeType = IFRAME; + ENSURE_OR_GO_EXIT(iFrameData.sendDataLen <= (UINT_MAX - (PH_PROTO_7816_HEADER_LEN + PH_PROTO_7816_CRC_LEN))) + frame_len = (iFrameData.sendDataLen + PH_PROTO_7816_HEADER_LEN + PH_PROTO_7816_CRC_LEN); + + /* frame the packet */ + p_framebuff[PH_PROPTO_7816_NAD_OFFSET] = SEND_PACKET_SOF; /* NAD Byte */ + + if (iFrameData.isChained) { + /* make B6 (M) bit high */ + pcb_byte |= PH_PROTO_7816_CHAINING; + } + + /* Update the send seq no */ + pcb_byte |= (pNextTx_IframeInfo->seqNo << 6); + + /* store the pcb byte */ + p_framebuff[PH_PROPTO_7816_PCB_OFFSET] = pcb_byte; +#if defined(T1oI2C_UM11225) + /* store I frame length */ + /* for T1oI2C_UM11225 LEN field is of 1 byte*/ + p_framebuff[PH_PROPTO_7816_LEN_UPPER_OFFSET] = iFrameData.sendDataLen; +#elif defined(T1oI2C_GP1_0) + /* store I frame length */ + /* for T1oI2C_GP1_0 LEN field is of 2 byte*/ + p_framebuff[PH_PROPTO_7816_LEN_UPPER_OFFSET] = (((uint16_t)iFrameData.sendDataLen) >> 8 & 0xff); + p_framebuff[PH_PROPTO_7816_LEN_LOWER_OFFSET] = (((uint16_t)iFrameData.sendDataLen) & 0xff); +#endif + /* store I frame */ + ENSURE_OR_GO_EXIT(iFrameData.sendDataLen <= (MAX_APDU_BUFFER - PH_PROPTO_7816_INF_BYTE_OFFSET)) + ENSURE_OR_GO_EXIT(frame_len - 1 < MAX_APDU_BUFFER) + + phNxpEse_memcpy(&(p_framebuff[PH_PROPTO_7816_INF_BYTE_OFFSET]), + iFrameData.p_data + iFrameData.dataOffset, + iFrameData.sendDataLen); + calc_crc = phNxpEseProto7816_ComputeCRC(p_framebuff, 0, (frame_len - 2)); + + p_framebuff[frame_len - 2] = (calc_crc >> 8) & 0xff; + p_framebuff[frame_len - 1] = calc_crc & 0xff; + status = phNxpEseProto7816_SendRawFrame(conn_ctx, frame_len, p_framebuff); + +exit: + return status; +} + +/****************************************************************************** + * Function phNxpEseProto7816_SetFirstIframeContxt + * + * Description This internal function is called to set the context for next I-frame. + * Not applicable for the first I-frame of the transceive + * + * param[in] void + * + * Returns Always return TRUE. + * + ******************************************************************************/ +static bool_t phNxpEseProto7816_SetFirstIframeContxt(void) +{ + phNxpEseRx_Cntx_t *pRx_EseCntx = &phNxpEseProto7816_3_Var.phNxpEseRx_Cntx; + iFrameInfo_t *pNextTx_IframeInfo = &phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.IframeInfo; + iFrameInfo_t *pLastTx_IframeInfo = &phNxpEseProto7816_3_Var.phNxpEseLastTx_Cntx.IframeInfo; + + pNextTx_IframeInfo->dataOffset = 0; + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.FrameType = IFRAME; + pNextTx_IframeInfo->seqNo = (uint8_t)(pLastTx_IframeInfo->seqNo ^ 1); + phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = SEND_IFRAME; + pRx_EseCntx->responseBytesRcvd = 0; + if (pNextTx_IframeInfo->totalDataLen > pNextTx_IframeInfo->maxDataLen) { + pNextTx_IframeInfo->isChained = TRUE; + pNextTx_IframeInfo->sendDataLen = pNextTx_IframeInfo->maxDataLen; + pNextTx_IframeInfo->totalDataLen = pNextTx_IframeInfo->totalDataLen - pNextTx_IframeInfo->maxDataLen; + } + else { + pNextTx_IframeInfo->sendDataLen = pNextTx_IframeInfo->totalDataLen; + pNextTx_IframeInfo->isChained = FALSE; + } + T_SMLOG_D("I-Frame Data Len: %d Seq. no:%d ", pNextTx_IframeInfo->sendDataLen, pNextTx_IframeInfo->seqNo); + return TRUE; +} + +/****************************************************************************** + * Function phNxpEseProto7816_SetNextIframeContxt + * + * Description This internal function is called to set the context for next I-frame. + * Not applicable for the first I-frame of the transceive + * + * param[in] void + * + * Returns Always return TRUE. + * + ******************************************************************************/ +static bool_t phNxpEseProto7816_SetNextIframeContxt(void) +{ + iFrameInfo_t *pNextTx_IframeInfo = &phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.IframeInfo; + iFrameInfo_t *pLastTx_IframeInfo = &phNxpEseProto7816_3_Var.phNxpEseLastTx_Cntx.IframeInfo; + + /* Expecting to reach here only after first of chained I-frame is sent and before the last chained is sent */ + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.FrameType = IFRAME; + phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = SEND_IFRAME; + + pNextTx_IframeInfo->seqNo = (uint8_t)(pLastTx_IframeInfo->seqNo ^ 1); + if ((UINT_MAX - pLastTx_IframeInfo->dataOffset) < pLastTx_IframeInfo->maxDataLen) { + return FALSE; + } + pNextTx_IframeInfo->dataOffset = pLastTx_IframeInfo->dataOffset + pLastTx_IframeInfo->maxDataLen; + pNextTx_IframeInfo->p_data = pLastTx_IframeInfo->p_data; + pNextTx_IframeInfo->maxDataLen = pLastTx_IframeInfo->maxDataLen; + + //if chained + if (pLastTx_IframeInfo->totalDataLen > pLastTx_IframeInfo->maxDataLen) { + T_SMLOG_D("%s Process Chained Frame ", __FUNCTION__); + pNextTx_IframeInfo->isChained = TRUE; + pNextTx_IframeInfo->sendDataLen = pLastTx_IframeInfo->maxDataLen; + pNextTx_IframeInfo->totalDataLen = pLastTx_IframeInfo->totalDataLen - pLastTx_IframeInfo->maxDataLen; + } + else { + pNextTx_IframeInfo->isChained = FALSE; + pNextTx_IframeInfo->sendDataLen = pLastTx_IframeInfo->totalDataLen; + } + T_SMLOG_D("I-Frame Data Len: %d ", pNextTx_IframeInfo->sendDataLen); + return TRUE; +} + +/****************************************************************************** + * Function phNxpEseProro7816_SaveRxframeData + * + * Description This internal function is called to save recv frame data + * + * param[in] uint8_t: data buffer + * param[in] uint32_t: buffer length + * + * Returns Always return TRUE. + * + ******************************************************************************/ +static bool_t phNxpEseProro7816_SaveRxframeData(uint8_t *p_data, uint32_t data_len) +{ + phNxpEseRx_Cntx_t *pRx_EseCntx = &phNxpEseProto7816_3_Var.phNxpEseRx_Cntx; + + if (p_data == NULL) { + return FALSE; + } + T_SMLOG_D("Data[0]=0x%x len=%ld Data[%ld]=0x%x Data[%ld]=0x%x", + p_data[0], + data_len, + data_len - 1, + p_data[data_len - 2], + data_len, + p_data[data_len - 1]); + if (pRx_EseCntx->pRsp != NULL) { + if (pRx_EseCntx->pRsp->p_data == NULL) { + return FALSE; + } + if (pRx_EseCntx->responseBytesRcvd > (UINT_MAX - data_len)) { + return FALSE; + } + if ((pRx_EseCntx->responseBytesRcvd + data_len) > pRx_EseCntx->pRsp->len) { + // LOG_W("Need '%ld' bytes. Got '%ld' to copy.", (size_t)(pRx_EseCntx->responseBytesRcvd + data_len), pRx_EseCntx->pRsp->len); + return FALSE; + } + phNxpEse_memcpy((pRx_EseCntx->pRsp->p_data + pRx_EseCntx->responseBytesRcvd), p_data, data_len); + pRx_EseCntx->responseBytesRcvd += data_len; + return TRUE; + } + else { + T_SMLOG_E("Unsolicited response"); + return FALSE; + } +} + +/****************************************************************************** + * Function phNxpEseProto7816_ResetRecovery + * + * Description This internal function is called to do reset the recovery pareameters + * + * param[in] void + * + * Returns Always return TRUE. + * + ******************************************************************************/ +static bool_t phNxpEseProto7816_ResetRecovery(void) +{ + phNxpEseProto7816_3_Var.recoveryCounter = 0; + return TRUE; +} + +/****************************************************************************** + * Function phNxpEseProto7816_RecoverySteps + * + * Description This internal function is called when 7816-3 stack failed to recover + * after PH_PROTO_7816_FRAME_RETRY_COUNT, and the interface has to be + * recovered + * + * param[in] void + * + * Returns Always return TRUE. + * + ******************************************************************************/ +static bool_t phNxpEseProto7816_RecoverySteps(void) +{ + sFrameInfo_t *pRx_lastRcvdSframeInfo = &phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.lastRcvdSframeInfo; + sFrameInfo_t *pNextTx_SframeInfo = &phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.SframeInfo; + + if (phNxpEseProto7816_3_Var.recoveryCounter <= PH_PROTO_7816_FRAME_RETRY_COUNT) { +#if defined(T1oI2C_UM11225) + pRx_lastRcvdSframeInfo->sFrameType = INTF_RESET_REQ; + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.FrameType = SFRAME; + pNextTx_SframeInfo->sFrameType = INTF_RESET_REQ; + phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = SEND_S_INTF_RST; +#elif defined(T1oI2C_GP1_0) + pRx_lastRcvdSframeInfo->sFrameType = SWR_REQ; + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.FrameType = SFRAME; + pNextTx_SframeInfo->sFrameType = SWR_REQ; + phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = SEND_S_SWR; +#endif + } + else { /* If recovery fails */ + phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = IDLE_STATE; + } + return TRUE; +} + +/****************************************************************************** + * Function phNxpEseProto7816_DecodeSFrameData + * + * Description This internal function is to decode S-frame payload. + * + * param[in] uint8_t; data buffer + * + * Returns void + * + ******************************************************************************/ +static void phNxpEseProto7816_DecodeSFrameData(uint8_t *p_data) +{ + uint8_t maxSframeLen = 0, frameOffset = 0; + + ENSURE_OR_GO_EXIT(p_data != NULL); +#if defined(T1oI2C_UM11225) + frameOffset = PH_PROPTO_7816_LEN_UPPER_OFFSET; +#elif defined(T1oI2C_GP1_0) + /* current GP implementation support max payload of 0x00FE, so considering lower offset */ + frameOffset = PH_PROPTO_7816_LEN_LOWER_OFFSET; +#endif + maxSframeLen = p_data[frameOffset] + frameOffset; /* to be in sync with offset which starts from index 0 */ + while (maxSframeLen > frameOffset) { + frameOffset += 1; /* To get the Type (TLV) */ + T_SMLOG_D("%s frameoffset=%d value=0x%x ", __FUNCTION__, frameOffset, p_data[frameOffset]); + frameOffset += p_data[frameOffset + 1]; /* Goto the end of current marker */ + } +exit: + return; +} + +/****************************************************************************** + * Function phNxpEseProto7816_DecodeFrame + * + * Description This internal function is used to + * 1. Identify the received frame + * 2. If the received frame is I-frame with expected sequence number, store it or else send R-NACK + 3. If the received frame is R-frame, + 3.1 R-ACK with expected seq. number: Send the next chained I-frame + 3.2 R-ACK with different sequence number: Sebd the R-Nack + 3.3 R-NACK: Re-send the last frame + 4. If the received frame is S-frame, send back the correct S-frame response. + * + * param[in] uint8_t : data buffer + * param[in] uint32_t : buffer length + * + * Returns On success return TRUE or else FALSE. + * + ******************************************************************************/ +static bool_t phNxpEseProto7816_DecodeFrame(uint8_t *p_data, uint32_t data_len) +{ + bool_t status = TRUE; + uint8_t pcb; + iFrameInfo_t *pRx_lastRcvdIframeInfo = &phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.lastRcvdIframeInfo; + rFrameInfo_t *pNextTx_RframeInfo = &phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.RframeInfo; + sFrameInfo_t *pNextTx_SframeInfo = &phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.SframeInfo; + iFrameInfo_t *pLastTx_IframeInfo = &phNxpEseProto7816_3_Var.phNxpEseLastTx_Cntx.IframeInfo; + sFrameInfo_t *pLastTx_SframeInfo = &phNxpEseProto7816_3_Var.phNxpEseLastTx_Cntx.SframeInfo; + rFrameInfo_t *pRx_lastRcvdRframeInfo = &phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.lastRcvdRframeInfo; + sFrameInfo_t *pRx_lastRcvdSframeInfo = &phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.lastRcvdSframeInfo; + + T_SMLOG_D("Retry Counter = %d ", phNxpEseProto7816_3_Var.recoveryCounter); + + ENSURE_OR_GO_EXIT(p_data != NULL); + ENSURE_OR_GO_EXIT(data_len < MAX_APDU_BUFFER); + ENSURE_OR_GO_EXIT(data_len >= PH_PROTO_7816_HEADER_LEN); + + pcb = p_data[PH_PROPTO_7816_PCB_OFFSET]; + if (data_len < PH_PROTO_7816_INF_FILED) { + return FALSE; + } + + if (!(pcb & 0x80)) /* I-FRAME decoded should come here */ + { + T_SMLOG_D("%s I-Frame Received ", __FUNCTION__); + phNxpEseProto7816_3_Var.wtx_counter = 0; + phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.lastRcvdFrameType = IFRAME; + if (pRx_lastRcvdIframeInfo->seqNo != ((pcb & 0x40) >> 6)) { + T_SMLOG_D("%s I-Frame lastRcvdIframeInfo.seqNo:0x%x ", __FUNCTION__, ((pcb & 0x40) >> 6)); + phNxpEseProto7816_ResetRecovery(); + pRx_lastRcvdIframeInfo->seqNo = 0x00; + pRx_lastRcvdIframeInfo->seqNo |= ((pcb & 0x40) >> 6); + + if (pcb & 0x20) { + pRx_lastRcvdIframeInfo->isChained = TRUE; + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.FrameType = RFRAME; + pNextTx_RframeInfo->errCode = NO_ERROR; + if (FALSE == phNxpEseProro7816_SaveRxframeData( + &p_data[PH_PROPTO_7816_INF_BYTE_OFFSET], data_len - PH_PROTO_7816_INF_FILED)) { + phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = IDLE_STATE; + T_SMLOG_E("phNxpEseProro7816_SaveRxframeData Failed"); + return FALSE; + } + phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = SEND_R_ACK; + } + else { + pRx_lastRcvdIframeInfo->isChained = FALSE; + phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = IDLE_STATE; + if (FALSE == phNxpEseProro7816_SaveRxframeData( + &p_data[PH_PROPTO_7816_INF_BYTE_OFFSET], data_len - PH_PROTO_7816_INF_FILED)) { + T_SMLOG_E("phNxpEseProro7816_SaveRxframeData Failed"); + return FALSE; + } + } + } + else { + sm_sleep(DELAY_ERROR_RECOVERY / 1000); + if (phNxpEseProto7816_3_Var.recoveryCounter < PH_PROTO_7816_FRAME_RETRY_COUNT) { + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.FrameType = RFRAME; + pNextTx_RframeInfo->errCode = OTHER_ERROR; + phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = SEND_R_NACK; + phNxpEseProto7816_3_Var.recoveryCounter++; + } + else { + phNxpEseProto7816_RecoverySteps(); + phNxpEseProto7816_3_Var.recoveryCounter++; + } + } + } + else if ((pcb & 0x80) && (!(0x40 & pcb))) /* R-FRAME decoded should come here */ + { + T_SMLOG_D("%s R-Frame Received", __FUNCTION__); + phNxpEseProto7816_3_Var.wtx_counter = 0; + phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.lastRcvdFrameType = RFRAME; + pRx_lastRcvdRframeInfo->seqNo = 0; // = 0; + pRx_lastRcvdRframeInfo->seqNo |= ((pcb & 0x10) >> 4); + + if ((!(pcb & 0x01)) && (!(pcb & 0x02))) { + pRx_lastRcvdRframeInfo->errCode = NO_ERROR; + phNxpEseProto7816_ResetRecovery(); + if (pRx_lastRcvdRframeInfo->seqNo != pLastTx_IframeInfo->seqNo) { + phNxpEseProto7816_SetNextIframeContxt(); + phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = SEND_IFRAME; + } + + } /* Error handling 1 : Parity error */ + else if (((pcb & 0x01) && (!(pcb & 0x02))) || + /* Error handling 2: Other indicated error */ + ((!(pcb & 0x01)) && (pcb & 0x02))) { + sm_sleep(DELAY_ERROR_RECOVERY / 1000); + if ((!(pcb & 0x01)) && (pcb & 0x02)) { + pRx_lastRcvdRframeInfo->errCode = OTHER_ERROR; + } + else { + pRx_lastRcvdRframeInfo->errCode = PARITY_ERROR; + } + if (phNxpEseProto7816_3_Var.recoveryCounter < PH_PROTO_7816_FRAME_RETRY_COUNT) { + if (phNxpEseProto7816_3_Var.phNxpEseLastTx_Cntx.FrameType == IFRAME) { + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx = phNxpEseProto7816_3_Var.phNxpEseLastTx_Cntx; + phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = SEND_IFRAME; + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.FrameType = IFRAME; + } + else if (phNxpEseProto7816_3_Var.phNxpEseLastTx_Cntx.FrameType == RFRAME) { + /* Usecase to reach the below case: + I-frame sent first, followed by R-NACK and we receive a R-NACK with + last sent I-frame sequence number*/ + if ((pRx_lastRcvdRframeInfo->seqNo == pLastTx_IframeInfo->seqNo) && + (phNxpEseProto7816_3_Var.lastSentNonErrorframeType == IFRAME)) { + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx = phNxpEseProto7816_3_Var.phNxpEseLastTx_Cntx; + phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = SEND_IFRAME; + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.FrameType = IFRAME; + } + /* Usecase to reach the below case: + R-frame sent first, followed by R-NACK and we receive a R-NACK with + next expected I-frame sequence number*/ + else if ((pRx_lastRcvdRframeInfo->seqNo != pLastTx_IframeInfo->seqNo) && + (phNxpEseProto7816_3_Var.lastSentNonErrorframeType == RFRAME)) { + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.FrameType = RFRAME; + pNextTx_RframeInfo->errCode = NO_ERROR; + phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = SEND_R_ACK; + } + /* Usecase to reach the below case: + I-frame sent first, followed by R-NACK and we receive a R-NACK with + next expected I-frame sequence number + all the other unexpected scenarios */ + else { + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.FrameType = RFRAME; + pNextTx_RframeInfo->errCode = OTHER_ERROR; + phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = SEND_R_NACK; + } + } + else if (phNxpEseProto7816_3_Var.phNxpEseLastTx_Cntx.FrameType == SFRAME) { + /* Copy the last S frame sent */ + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx = phNxpEseProto7816_3_Var.phNxpEseLastTx_Cntx; + } + phNxpEseProto7816_3_Var.recoveryCounter++; + } + else { + phNxpEseProto7816_RecoverySteps(); + phNxpEseProto7816_3_Var.recoveryCounter++; + } + //resend previously send I frame + } + /* Error handling 3 */ + else if ((pcb & 0x01) && (pcb & 0x02)) { + sm_sleep(DELAY_ERROR_RECOVERY / 1000); + if (phNxpEseProto7816_3_Var.recoveryCounter < PH_PROTO_7816_FRAME_RETRY_COUNT) { + pRx_lastRcvdRframeInfo->errCode = SOF_MISSED_ERROR; + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx = phNxpEseProto7816_3_Var.phNxpEseLastTx_Cntx; + phNxpEseProto7816_3_Var.recoveryCounter++; + } + else { + phNxpEseProto7816_RecoverySteps(); + phNxpEseProto7816_3_Var.recoveryCounter++; + } + } + } + else if ((0x80 & pcb) && (0x40 & pcb)) /* S-FRAME decoded should come here */ + { + T_SMLOG_D("%s S-Frame Received ", __FUNCTION__); + int32_t frameType = (int32_t)(pcb & 0x3F); /*discard upper 2 bits */ + phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.lastRcvdFrameType = SFRAME; + if (frameType != WTX_REQ) { + phNxpEseProto7816_3_Var.wtx_counter = 0; + } + switch (frameType) { + case RESYNCH_RSP: + pRx_lastRcvdSframeInfo->sFrameType = RESYNCH_RSP; + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.FrameType = UNKNOWN; + phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = IDLE_STATE; + break; + case IFSC_RES: + pRx_lastRcvdSframeInfo->sFrameType = IFSC_RES; + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.FrameType = UNKNOWN; + phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = IDLE_STATE; + break; + case ABORT_RES: + pRx_lastRcvdSframeInfo->sFrameType = ABORT_RES; + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.FrameType = UNKNOWN; + phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = IDLE_STATE; + break; + case WTX_REQ: + phNxpEseProto7816_3_Var.wtx_counter++; + T_SMLOG_D("%s Wtx_counter value - %lu ", __FUNCTION__, phNxpEseProto7816_3_Var.wtx_counter); + T_SMLOG_D( + "%s Wtx_counter wtx_counter_limit - %lu ", __FUNCTION__, phNxpEseProto7816_3_Var.wtx_counter_limit); + /* Previous sent frame is some S-frame but not WTX response S-frame */ + if (pLastTx_SframeInfo->sFrameType != WTX_RSP && + phNxpEseProto7816_3_Var.phNxpEseLastTx_Cntx.FrameType == + SFRAME) { /* Goto recovery if it keep coming here for more than recovery counter max. value */ + if (phNxpEseProto7816_3_Var.recoveryCounter < + PH_PROTO_7816_FRAME_RETRY_COUNT) { /* Re-transmitting the previous sent S-frame */ + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx = phNxpEseProto7816_3_Var.phNxpEseLastTx_Cntx; + phNxpEseProto7816_3_Var.recoveryCounter++; + } + else { + phNxpEseProto7816_RecoverySteps(); + phNxpEseProto7816_3_Var.recoveryCounter++; + } + } + else { /* Checking for WTX counter with max. allowed WTX count */ + if (phNxpEseProto7816_3_Var.wtx_counter == phNxpEseProto7816_3_Var.wtx_counter_limit) { +#if defined(T1oI2C_UM11225) + phNxpEseProto7816_3_Var.wtx_counter = 0; + pRx_lastRcvdSframeInfo->sFrameType = INTF_RESET_REQ; + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.FrameType = SFRAME; + pNextTx_SframeInfo->sFrameType = INTF_RESET_REQ; + phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = SEND_S_INTF_RST; + T_SMLOG_E("%s Interface Reset to eSE wtx count reached!!! ", __FUNCTION__); +#elif defined(T1oI2C_GP1_0) + phNxpEseProto7816_3_Var.wtx_counter = 0; + pRx_lastRcvdSframeInfo->sFrameType = SWR_REQ; + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.FrameType = SFRAME; + pNextTx_SframeInfo->sFrameType = SWR_REQ; + phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = SEND_S_SWR; + T_SMLOG_E("%s Software Reset to eSE wtx count reached!!! ", __FUNCTION__); +#endif + } + else { + sm_sleep(DELAY_ERROR_RECOVERY / 1000); + pRx_lastRcvdSframeInfo->sFrameType = WTX_REQ; + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.FrameType = SFRAME; + pNextTx_SframeInfo->sFrameType = WTX_RSP; + phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = SEND_S_WTX_RSP; + } + } + break; +#if defined(T1oI2C_UM11225) + case INTF_RESET_RSP: + if (p_data[PH_PROPTO_7816_FRAME_LENGTH_OFFSET] > 0) { + phNxpEseProto7816_DecodeSFrameData(p_data); + } + if (FALSE == phNxpEseProro7816_SaveRxframeData( + &p_data[PH_PROPTO_7816_INF_BYTE_OFFSET], data_len - PH_PROTO_7816_INF_FILED)) { + phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = IDLE_STATE; + T_SMLOG_E("phNxpEseProro7816_SaveRxframeData Failed"); + return FALSE; + } + if (phNxpEseProto7816_3_Var.recoveryCounter > PH_PROTO_7816_FRAME_RETRY_COUNT) { + /*Max recovery counter reached, send failure to APDU layer */ + T_SMLOG_E("%s Max retry count reached!!! ", __FUNCTION__); + phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = IDLE_STATE; + status = FALSE; + } + else { + phNxpEseProto7816_ResetProtoParams(); + pRx_lastRcvdSframeInfo->sFrameType = INTF_RESET_RSP; + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.FrameType = UNKNOWN; + phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = IDLE_STATE; + } + break; + case PROP_END_APDU_RSP: + pRx_lastRcvdSframeInfo->sFrameType = PROP_END_APDU_RSP; + if (p_data[PH_PROPTO_7816_FRAME_LENGTH_OFFSET] > 0) { + phNxpEseProto7816_DecodeSFrameData(p_data); + } + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.FrameType = UNKNOWN; + phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = IDLE_STATE; + break; + case ATR_RES: + pRx_lastRcvdSframeInfo->sFrameType = ATR_RES; + if (p_data[PH_PROPTO_7816_FRAME_LENGTH_OFFSET] > 0) { + phNxpEseProto7816_DecodeSFrameData(p_data); + } + if (FALSE == phNxpEseProro7816_SaveRxframeData( + &p_data[PH_PROPTO_7816_INF_BYTE_OFFSET], data_len - PH_PROTO_7816_INF_FILED)) { + phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = IDLE_STATE; + T_SMLOG_E("phNxpEseProro7816_SaveRxframeData Failed"); + return FALSE; + } + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.FrameType = UNKNOWN; + phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = IDLE_STATE; + break; + case CHIP_RESET_RES: + pRx_lastRcvdSframeInfo->sFrameType = CHIP_RESET_RES; + if (p_data[PH_PROPTO_7816_FRAME_LENGTH_OFFSET] > 0) { + phNxpEseProto7816_DecodeSFrameData(p_data); + } + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.FrameType = UNKNOWN; + phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = IDLE_STATE; + break; +#endif +#if defined(T1oI2C_GP1_0) + case SWR_RSP: + if (p_data[PH_PROPTO_7816_FRAME_LENGTH_OFFSET] > 0) { + phNxpEseProto7816_DecodeSFrameData(p_data); + } + if (phNxpEseProto7816_3_Var.recoveryCounter > PH_PROTO_7816_FRAME_RETRY_COUNT) { + /*Max recovery counter reached, send failure to APDU layer */ + T_SMLOG_E("%s Max retry count reached!!! ", __FUNCTION__); + phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = IDLE_STATE; + status = FALSE; + } + else { + phNxpEseProto7816_ResetProtoParams(); + pRx_lastRcvdSframeInfo->sFrameType = SWR_RSP; + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.FrameType = UNKNOWN; + phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = IDLE_STATE; + } + break; + case RELEASE_RES: + pRx_lastRcvdSframeInfo->sFrameType = RELEASE_RES; + if (p_data[PH_PROPTO_7816_FRAME_LENGTH_OFFSET] > 0) { + phNxpEseProto7816_DecodeSFrameData(p_data); + } + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.FrameType = UNKNOWN; + phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = IDLE_STATE; + break; + case CIP_RES: + pRx_lastRcvdSframeInfo->sFrameType = CIP_RES; + if (p_data[PH_PROPTO_7816_FRAME_LENGTH_OFFSET] > 0) { + phNxpEseProto7816_DecodeSFrameData(p_data); + } + if (FALSE == phNxpEseProro7816_SaveRxframeData( + &p_data[PH_PROPTO_7816_INF_BYTE_OFFSET], data_len - PH_PROTO_7816_INF_FILED)) { + phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = IDLE_STATE; + T_SMLOG_E("phNxpEseProro7816_SaveRxframeData Failed"); + return FALSE; + } + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.FrameType = UNKNOWN; + phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = IDLE_STATE; + break; + case COLD_RESET_RES: + pRx_lastRcvdSframeInfo->sFrameType = COLD_RESET_RES; + if (p_data[PH_PROPTO_7816_FRAME_LENGTH_OFFSET] > 0) { + phNxpEseProto7816_DecodeSFrameData(p_data); + } + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.FrameType = UNKNOWN; + phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = IDLE_STATE; + break; +#endif + case DEEP_PWR_DOWN_RES: + pRx_lastRcvdSframeInfo->sFrameType = DEEP_PWR_DOWN_RES; + if (p_data[PH_PROPTO_7816_FRAME_LENGTH_OFFSET] > 0) { + phNxpEseProto7816_DecodeSFrameData(p_data); + } + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.FrameType = UNKNOWN; + phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = IDLE_STATE; + break; + default: + T_SMLOG_E("%s Wrong S-Frame Received ", __FUNCTION__); + break; + } + } + else { + T_SMLOG_E("%s Wrong-Frame Received ", __FUNCTION__); + } +exit: + return status; +} + +/****************************************************************************** + * Function phNxpEseProto7816_ProcessResponse + * + * Description This internal function is used to + * 1. Check the CRC + * 2. Initiate decoding of received frame of data. + * + * param[in] void + * + * Returns On success return TRUE or else FALSE. + * + ******************************************************************************/ +static bool_t phNxpEseProto7816_ProcessResponse(void *conn_ctx) +{ + uint32_t data_len = 0; + uint8_t *p_data = NULL; + bool_t status = FALSE; + bool_t checkCrcPass = TRUE; + iFrameInfo_t *pRx_lastRcvdIframeInfo = &phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.lastRcvdIframeInfo; + rFrameInfo_t *pNextTx_RframeInfo = &phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.RframeInfo; + sFrameInfo_t *pLastTx_SframeInfo = &phNxpEseProto7816_3_Var.phNxpEseLastTx_Cntx.SframeInfo; + + status = phNxpEseProto7816_GetRawFrame(conn_ctx, &data_len, &p_data); + if (TRUE == status) { + /* Resetting the timeout counter */ + phNxpEseProto7816_3_Var.timeoutCounter = PH_PROTO_7816_VALUE_ZERO; + /* CRC check followed */ + checkCrcPass = phNxpEseProto7816_CheckCRC(data_len, p_data); + if (checkCrcPass == TRUE) { + /* Resetting the RNACK retry counter */ + phNxpEseProto7816_3_Var.rnack_retry_counter = PH_PROTO_7816_VALUE_ZERO; + status = phNxpEseProto7816_DecodeFrame(p_data, data_len); + } + else { + T_SMLOG_E("%s CRC Check failed ", __FUNCTION__); + if (phNxpEseProto7816_3_Var.rnack_retry_counter < phNxpEseProto7816_3_Var.rnack_retry_limit) { + phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.lastRcvdFrameType = INVALID; + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.FrameType = RFRAME; + pNextTx_RframeInfo->errCode = PARITY_ERROR; + pNextTx_RframeInfo->seqNo = (!pRx_lastRcvdIframeInfo->seqNo) << 4; + phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = SEND_R_NACK; + phNxpEseProto7816_3_Var.rnack_retry_counter++; + } + else { + phNxpEseProto7816_3_Var.rnack_retry_counter = PH_PROTO_7816_VALUE_ZERO; + /* Re-transmission failed completely, Going to exit */ + phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = IDLE_STATE; + phNxpEseProto7816_3_Var.timeoutCounter = PH_PROTO_7816_VALUE_ZERO; + status = FALSE; + } + } + } + else { + T_SMLOG_E("%s phNxpEseProto7816_GetRawFrame failed starting recovery", __FUNCTION__); + if ((SFRAME == phNxpEseProto7816_3_Var.phNxpEseLastTx_Cntx.FrameType) && + ((WTX_RSP == pLastTx_SframeInfo->sFrameType) || (RESYNCH_RSP == pLastTx_SframeInfo->sFrameType))) { + if (phNxpEseProto7816_3_Var.rnack_retry_counter < phNxpEseProto7816_3_Var.rnack_retry_limit) { + phNxpEse_clearReadBuffer(conn_ctx); + phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.lastRcvdFrameType = INVALID; + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.FrameType = RFRAME; + pNextTx_RframeInfo->errCode = OTHER_ERROR; + pNextTx_RframeInfo->seqNo = (!pRx_lastRcvdIframeInfo->seqNo) << 4; + phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = SEND_R_NACK; + phNxpEseProto7816_3_Var.rnack_retry_counter++; + } + else { + T_SMLOG_E("%s Recovery failed completely, Going to exit ", __FUNCTION__); + phNxpEseProto7816_3_Var.rnack_retry_counter = PH_PROTO_7816_VALUE_ZERO; + /* Recovery failed completely, Going to exit */ + phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = IDLE_STATE; + phNxpEseProto7816_3_Var.timeoutCounter = PH_PROTO_7816_VALUE_ZERO; + } + } + /*ISO7816-3 Rule 7.1 Implementation*/ + else if (IFRAME == phNxpEseProto7816_3_Var.phNxpEseLastTx_Cntx.FrameType) { + if (phNxpEseProto7816_3_Var.rnack_retry_counter < phNxpEseProto7816_3_Var.rnack_retry_limit) { + phNxpEse_clearReadBuffer(conn_ctx); + phNxpEseProto7816_3_Var.phNxpEseRx_Cntx.lastRcvdFrameType = INVALID; + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.FrameType = RFRAME; + pNextTx_RframeInfo->errCode = PARITY_ERROR; + pNextTx_RframeInfo->seqNo = (!pRx_lastRcvdIframeInfo->seqNo) << 4; + phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = SEND_R_NACK; + phNxpEseProto7816_3_Var.rnack_retry_counter++; + } + else { + T_SMLOG_E("%s Recovery failed completely, Going to exit ", __FUNCTION__); + phNxpEseProto7816_3_Var.rnack_retry_counter = PH_PROTO_7816_VALUE_ZERO; + /* Recovery failed completely, Going to exit */ + phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = IDLE_STATE; + phNxpEseProto7816_3_Var.timeoutCounter = PH_PROTO_7816_VALUE_ZERO; + } + } + else { + sm_sleep(DELAY_ERROR_RECOVERY / 1000); + /* re transmit the frame */ + if (phNxpEseProto7816_3_Var.timeoutCounter < PH_PROTO_7816_TIMEOUT_RETRY_COUNT) { + phNxpEseProto7816_3_Var.timeoutCounter++; + T_SMLOG_E("%s re-transmitting the previous frame ", __FUNCTION__); + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx = phNxpEseProto7816_3_Var.phNxpEseLastTx_Cntx; + } + else { + /* Recovery failed completely, Going to exit */ + T_SMLOG_E("%s Recovery failed completely, Going to exit ", __FUNCTION__); + phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = IDLE_STATE; + phNxpEseProto7816_3_Var.timeoutCounter = PH_PROTO_7816_VALUE_ZERO; + } + } + } + return status; +} + +/****************************************************************************** + * Function TransceiveProcess + * + * Description This internal function is used to + * 1. Send the raw data received from application after computing CRC + * 2. Receive the the response data from ESE, decode, process and + * store the data. + * + * param[in] void + * + * Returns On success return TRUE or else FALSE. + * + ******************************************************************************/ +static bool_t TransceiveProcess(void *conn_ctx) +{ + bool_t status = FALSE; + sFrameInfo_t sFrameInfo; + sFrameInfo.sFrameType = INVALID_REQ_RES; + + sFrameInfo.sFrameType = INVALID_REQ_RES; + + while (phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState != IDLE_STATE) { + T_SMLOG_D( + "%s nextTransceiveState %x ", __FUNCTION__, phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState); + switch (phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState) { + case SEND_IFRAME: + status = phNxpEseProto7816_SendIframe(conn_ctx, phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.IframeInfo); + break; + case SEND_R_ACK: + status = phNxpEseProto7816_sendRframe(conn_ctx, RACK); + break; + case SEND_R_NACK: + status = phNxpEseProto7816_sendRframe(conn_ctx, RNACK); + break; + case SEND_S_RSYNC: + sFrameInfo.sFrameType = RESYNCH_REQ; + status = phNxpEseProto7816_SendSFrame(conn_ctx, sFrameInfo); + break; + case SEND_S_WTX_RSP: + sFrameInfo.sFrameType = WTX_RSP; + status = phNxpEseProto7816_SendSFrame(conn_ctx, sFrameInfo); + break; + case SEND_DEEP_PWR_DOWN: + sFrameInfo.sFrameType = DEEP_PWR_DOWN_REQ; + status = phNxpEseProto7816_SendSFrame(conn_ctx, sFrameInfo); + break; +#if defined(T1oI2C_UM11225) + case SEND_S_CHIP_RST: + sFrameInfo.sFrameType = CHIP_RESET_REQ; + status = phNxpEseProto7816_SendSFrame(conn_ctx, sFrameInfo); + break; + case SEND_S_INTF_RST: + sFrameInfo.sFrameType = INTF_RESET_REQ; + status = phNxpEseProto7816_SendSFrame(conn_ctx, sFrameInfo); + break; + case SEND_S_EOS: + sFrameInfo.sFrameType = PROP_END_APDU_REQ; + status = phNxpEseProto7816_SendSFrame(conn_ctx, sFrameInfo); + break; + case SEND_S_ATR: + sFrameInfo.sFrameType = ATR_REQ; + status = phNxpEseProto7816_SendSFrame(conn_ctx, sFrameInfo); + break; +#elif defined(T1oI2C_GP1_0) + case SEND_S_CIP: + sFrameInfo.sFrameType = CIP_REQ; + status = phNxpEseProto7816_SendSFrame(conn_ctx, sFrameInfo); + break; + case SEND_S_SWR: + sFrameInfo.sFrameType = SWR_REQ; + status = phNxpEseProto7816_SendSFrame(conn_ctx, sFrameInfo); + break; + case SEND_S_RELEASE: + sFrameInfo.sFrameType = RELEASE_REQ; + status = phNxpEseProto7816_SendSFrame(conn_ctx, sFrameInfo); + break; + case SEND_S_COLD_RST: + sFrameInfo.sFrameType = COLD_RESET_REQ; + status = phNxpEseProto7816_SendSFrame(conn_ctx, sFrameInfo); + break; +#else +#error Either T1oI2C_UM11225 or T1oI2C_GP1_0 must be defined. +#endif + default: + phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = IDLE_STATE; + break; + } + if (TRUE == status) { + phNxpEseProto7816_3_Var.phNxpEseLastTx_Cntx = phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx; + status = phNxpEseProto7816_ProcessResponse(conn_ctx); + } + else { + T_SMLOG_E("%s Transceive send failed, going to recovery! ", __FUNCTION__); + phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = IDLE_STATE; + } + }; + return status; +} + +/****************************************************************************** + * Function phNxpEseProto7816_Transceive + * + * Description This function is used to + * 1. Send the raw data received from application after computing CRC + * 2. Receive the the response data from ESE, decode, process and + * store the data. + * 3. Get the final complete data and sent back to application + * + * param[in] phNxpEse_data: Command to ESE C-APDU + * param[out] phNxpEse_data: Response from ESE R-APDU + * + * Returns On success return TRUE or else FALSE. + * + ******************************************************************************/ +bool_t phNxpEseProto7816_Transceive(void *conn_ctx, phNxpEse_data *pCmd, phNxpEse_data *pRsp) +{ + bool_t status = FALSE; + phNxpEseRx_Cntx_t *pRx_EseCntx = &phNxpEseProto7816_3_Var.phNxpEseRx_Cntx; + iFrameInfo_t *pNextTx_IframeInfo = &phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.IframeInfo; + + T_SMLOG_D("Enter %s ", __FUNCTION__); + if ((NULL == pCmd) || (NULL == pRsp) || + (phNxpEseProto7816_3_Var.phNxpEseProto7816_CurrentState != PH_NXP_ESE_PROTO_7816_IDLE)) + return status; + /* Updating the transceive information to the protocol stack */ + phNxpEseProto7816_3_Var.phNxpEseProto7816_CurrentState = PH_NXP_ESE_PROTO_7816_TRANSCEIVE; + pNextTx_IframeInfo->p_data = pCmd->p_data; + pNextTx_IframeInfo->totalDataLen = pCmd->len; + pRx_EseCntx->pRsp = pRsp; + T_SMLOG_D("Transceive data ptr 0x%p len:%d ", pCmd->p_data, pCmd->len); + phNxpEseProto7816_SetFirstIframeContxt(); + status = TransceiveProcess(conn_ctx); + if (FALSE == status) { + /* ESE hard reset to be done */ + T_SMLOG_E("%s Transceive failed, hard reset to proceed ", __FUNCTION__); + } + if (pRx_EseCntx->responseBytesRcvd > UINT32_MAX) { + return FALSE; + } + pRsp->len = pRx_EseCntx->responseBytesRcvd; + phNxpEseProto7816_3_Var.phNxpEseProto7816_CurrentState = PH_NXP_ESE_PROTO_7816_IDLE; + return status; +} + +/****************************************************************************** + * Function phNxpEseProto7816_RSync + * + * Description This function is used to send the RSync command + * + * param[in] void + * + * Returns On success return TRUE or else FALSE. + * + ******************************************************************************/ +static bool_t phNxpEseProto7816_RSync(void *conn_ctx) +{ + bool_t status = FALSE; + sFrameInfo_t *pNextTx_SframeInfo = &phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.SframeInfo; + + phNxpEseProto7816_3_Var.phNxpEseProto7816_CurrentState = PH_NXP_ESE_PROTO_7816_TRANSCEIVE; + /* send the end of session s-frame */ + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.FrameType = SFRAME; + pNextTx_SframeInfo->sFrameType = RESYNCH_REQ; + phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = SEND_S_RSYNC; + status = TransceiveProcess(conn_ctx); + phNxpEseProto7816_3_Var.phNxpEseProto7816_CurrentState = PH_NXP_ESE_PROTO_7816_IDLE; + return status; +} + +/****************************************************************************** + * Function phNxpEseProto7816_ResetProtoParams + * + * Description This function is used to reset the 7816 protocol stack instance + * + * param[in] void + * + * Returns Always return TRUE. + * + ******************************************************************************/ +bool_t phNxpEseProto7816_ResetProtoParams(void) +{ + unsigned long int tmpWTXCountlimit = PH_PROTO_7816_VALUE_ZERO; + unsigned long int tmpRNACKCountlimit = PH_PROTO_7816_VALUE_ZERO; + phNxpEseRx_Cntx_t *pRx_EseCntx = &phNxpEseProto7816_3_Var.phNxpEseRx_Cntx; + iFrameInfo_t *pNextTx_IframeInfo = &phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.IframeInfo; + iFrameInfo_t *pLastTx_IframeInfo = &phNxpEseProto7816_3_Var.phNxpEseLastTx_Cntx.IframeInfo; + + tmpWTXCountlimit = phNxpEseProto7816_3_Var.wtx_counter_limit; + tmpRNACKCountlimit = phNxpEseProto7816_3_Var.rnack_retry_limit; + phNxpEse_memset(&phNxpEseProto7816_3_Var, PH_PROTO_7816_VALUE_ZERO, sizeof(phNxpEseProto7816_t)); + phNxpEseProto7816_3_Var.wtx_counter_limit = tmpWTXCountlimit; + phNxpEseProto7816_3_Var.rnack_retry_limit = tmpRNACKCountlimit; + phNxpEseProto7816_3_Var.phNxpEseProto7816_CurrentState = PH_NXP_ESE_PROTO_7816_IDLE; + phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = IDLE_STATE; + pRx_EseCntx->lastRcvdFrameType = INVALID; + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.FrameType = INVALID; + pNextTx_IframeInfo->maxDataLen = IFSC_SIZE_SEND; + pNextTx_IframeInfo->p_data = NULL; + phNxpEseProto7816_3_Var.phNxpEseLastTx_Cntx.FrameType = INVALID; + pLastTx_IframeInfo->maxDataLen = IFSC_SIZE_SEND; + pLastTx_IframeInfo->p_data = NULL; + /* Initialized with sequence number of the last I-frame sent */ + pNextTx_IframeInfo->seqNo = PH_PROTO_7816_VALUE_ONE; + /* Initialized with sequence number of the last I-frame received */ + pRx_EseCntx->lastRcvdIframeInfo.seqNo = PH_PROTO_7816_VALUE_ONE; + /* Initialized with sequence number of the last I-frame received */ + pLastTx_IframeInfo->seqNo = PH_PROTO_7816_VALUE_ONE; + phNxpEseProto7816_3_Var.recoveryCounter = PH_PROTO_7816_VALUE_ZERO; + phNxpEseProto7816_3_Var.timeoutCounter = PH_PROTO_7816_VALUE_ZERO; + phNxpEseProto7816_3_Var.wtx_counter = PH_PROTO_7816_VALUE_ZERO; + /* This update is helpful in-case a R-NACK is transmitted from the MW */ + phNxpEseProto7816_3_Var.lastSentNonErrorframeType = UNKNOWN; + phNxpEseProto7816_3_Var.rnack_retry_counter = PH_PROTO_7816_VALUE_ZERO; + pRx_EseCntx->pRsp = NULL; + return TRUE; +} + +/****************************************************************************** + * Function phNxpEseProto7816_Reset + * + * Description This function is used to reset the 7816 protocol stack instance + * + * param[in] void + * + * Returns On success return TRUE or else FALSE. + * + ******************************************************************************/ +bool_t phNxpEseProto7816_Reset(void) +{ + bool_t status = FALSE; + /* Resetting host protocol instance */ + status = phNxpEseProto7816_ResetProtoParams(); + /* Resynchronising ESE protocol instance */ + //status = phNxpEseProto7816_RSync(); + return status; +} + +/****************************************************************************** + * Function phNxpEseProto7816_Open + * + * Description This function is used to open the 7816 protocol stack instance + * + * param[in] phNxpEseProto7816InitParam_t: ESE communication mode + * param[out] phNxpEse_data: ATR Response from ESE + * + * Returns On success return TRUE or else FALSE. + * + ******************************************************************************/ +bool_t phNxpEseProto7816_Open(void *conn_ctx, phNxpEseProto7816InitParam_t initParam, phNxpEse_data *AtrRsp) +{ + bool_t status = FALSE; + phNxpEseRx_Cntx_t *pRx_EseCntx = &phNxpEseProto7816_3_Var.phNxpEseRx_Cntx; + status = phNxpEseProto7816_ResetProtoParams(); + T_SMLOG_D("%s: First open completed", __FUNCTION__); + /* Update WTX max. limit */ + phNxpEseProto7816_3_Var.wtx_counter_limit = initParam.wtx_counter_limit; + phNxpEseProto7816_3_Var.rnack_retry_limit = initParam.rnack_retry_limit; + /*Intialise the buffers before hand so that we are able to receive data + if RSync goes to recovery handling*/ + pRx_EseCntx->pRsp = AtrRsp; + pRx_EseCntx->pRsp->len = AtrRsp->len; + pRx_EseCntx->responseBytesRcvd = 0; + if (initParam.interfaceReset) /* Do interface reset */ + { + /*After power ON , initialization state takes 5ms after which slave enters active + state where slave can exchange data with the master */ + sm_sleep(WAKE_UP_DELAY_MS); + phNxpEse_waitForWTX(conn_ctx); + phNxpEse_clearReadBuffer(conn_ctx); +#if defined(T1oI2C_UM11225) + /* Interface Reset respond with ATR*/ + status = phNxpEseProto7816_RSync(conn_ctx); + if (status == TRUE) { + status = phNxpEseProto7816_GetAtr(conn_ctx, AtrRsp); + } + +#elif defined(T1oI2C_GP1_0) + /* For GP soft reset does not respond with CIP so master should send CIP req. seperatly */ + status = phNxpEseProto7816_RSync(conn_ctx); + if (status == TRUE) { + status = phNxpEseProto7816_GetCip(conn_ctx, AtrRsp); + } +#endif + } + else /* Do R-Sync */ + { + status = phNxpEseProto7816_RSync(conn_ctx); + } + AtrRsp->len = pRx_EseCntx->responseBytesRcvd; + return status; +} + +/****************************************************************************** + * Function phNxpEseProto7816_Close + * + * Description This function is used to close the 7816 protocol stack instance + * + * param[in] void + * + * Returns On success return TRUE or else FALSE. + * + ******************************************************************************/ +bool_t phNxpEseProto7816_Close(void *conn_ctx) +{ + sFrameInfo_t *pNextTx_SframeInfo = &phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.SframeInfo; + bool_t status = FALSE; + /*Explicitly Initilising to NULL as the Application layer does not intend to receive a response*/ + phNxpEseRx_Cntx_t *pRx_EseCntx = &phNxpEseProto7816_3_Var.phNxpEseRx_Cntx; + pRx_EseCntx->pRsp = NULL; + + if (phNxpEseProto7816_3_Var.phNxpEseProto7816_CurrentState != PH_NXP_ESE_PROTO_7816_IDLE) { + return status; + } + phNxpEseProto7816_3_Var.phNxpEseProto7816_CurrentState = PH_NXP_ESE_PROTO_7816_DEINIT; + phNxpEseProto7816_3_Var.recoveryCounter = 0; + phNxpEseProto7816_3_Var.wtx_counter = 0; +#if defined(T1oI2C_UM11225) + /* send the end of session s-frame */ + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.FrameType = SFRAME; + pNextTx_SframeInfo->sFrameType = PROP_END_APDU_REQ; + phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = SEND_S_EOS; +#elif defined(T1oI2C_GP1_0) + /* send the release request s-frame */ + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.FrameType = SFRAME; + pNextTx_SframeInfo->sFrameType = RELEASE_REQ; + phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = SEND_S_RELEASE; +#endif + status = TransceiveProcess(conn_ctx); + if (FALSE == status) { + /* reset all the structures */ + T_SMLOG_E("%s TransceiveProcess failed ", __FUNCTION__); + } + phNxpEseProto7816_3_Var.phNxpEseProto7816_CurrentState = PH_NXP_ESE_PROTO_7816_IDLE; + return status; +} + +#if defined(T1oI2C_UM11225) +/****************************************************************************** + * Function phNxpEseProto7816_IntfReset + * + * Description This function is used to reset just the current interface + and get the ATR response on successful reset + * + * param[in] phNxpEse_data: ATR response from ESE + * + * Returns On success return TRUE or else FALSE. + * + ******************************************************************************/ +bool_t phNxpEseProto7816_IntfReset(void *conn_ctx, phNxpEse_data *AtrRsp) +{ + bool_t status = FALSE; + sFrameInfo_t *pNextTx_SframeInfo = &phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.SframeInfo; + phNxpEseRx_Cntx_t *pRx_EseCntx = &phNxpEseProto7816_3_Var.phNxpEseRx_Cntx; + + ENSURE_OR_GO_EXIT(AtrRsp != NULL); + phNxpEseProto7816_3_Var.phNxpEseProto7816_CurrentState = PH_NXP_ESE_PROTO_7816_TRANSCEIVE; + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.FrameType = SFRAME; + pNextTx_SframeInfo->sFrameType = INTF_RESET_REQ; + phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = SEND_S_INTF_RST; + pRx_EseCntx->pRsp = AtrRsp; + pRx_EseCntx->pRsp->len = AtrRsp->len; + pRx_EseCntx->responseBytesRcvd = 0; + phNxpEse_clearReadBuffer(conn_ctx); + status = TransceiveProcess(conn_ctx); + AtrRsp->len = pRx_EseCntx->responseBytesRcvd; + if (FALSE == status) { + /* reset all the structures */ + T_SMLOG_E("%s TransceiveProcess failed ", __FUNCTION__); + } + + phNxpEseProto7816_3_Var.phNxpEseProto7816_CurrentState = PH_NXP_ESE_PROTO_7816_IDLE; +exit: + return status; +} + +/****************************************************************************** + * Function phNxpEseProto7816_ChipReset + * + * Description This function is used to reset just the current interface + * + * param[in] void + * + * Returns On success return TRUE or else FALSE. + * + ******************************************************************************/ +bool_t phNxpEseProto7816_ChipReset(void *conn_ctx) +{ + bool_t status = FALSE; + sFrameInfo_t *pNextTx_SframeInfo = &phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.SframeInfo; + phNxpEseRx_Cntx_t *pRx_EseCntx = &phNxpEseProto7816_3_Var.phNxpEseRx_Cntx; + + phNxpEseProto7816_3_Var.phNxpEseProto7816_CurrentState = PH_NXP_ESE_PROTO_7816_TRANSCEIVE; + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.FrameType = SFRAME; + pNextTx_SframeInfo->sFrameType = CHIP_RESET_REQ; + phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = SEND_S_CHIP_RST; + pRx_EseCntx->pRsp = NULL; + status = TransceiveProcess(conn_ctx); + if (FALSE == status) { + /* reset all the structures */ + T_SMLOG_E("%s TransceiveProcess failed ", __FUNCTION__); + } + phNxpEseProto7816_3_Var.phNxpEseProto7816_CurrentState = PH_NXP_ESE_PROTO_7816_IDLE; + return status; +} +#endif + +#if defined(T1oI2C_GP1_0) +/****************************************************************************** + * Function phNxpEseProto7816_SoftReset + * + * Description This function is used only for T1oI2C GP to reset just the current interface + * + * param[in] void + * + * Returns On success return TRUE or else FALSE. + * + ******************************************************************************/ +bool_t phNxpEseProto7816_SoftReset(void *conn_ctx) +{ + bool_t status = FALSE; + sFrameInfo_t *pNextTx_SframeInfo = &phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.SframeInfo; + phNxpEseRx_Cntx_t *pRx_EseCntx = &phNxpEseProto7816_3_Var.phNxpEseRx_Cntx; + + phNxpEseProto7816_3_Var.phNxpEseProto7816_CurrentState = PH_NXP_ESE_PROTO_7816_TRANSCEIVE; + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.FrameType = SFRAME; + pNextTx_SframeInfo->sFrameType = SWR_REQ; + phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = SEND_S_SWR; + pRx_EseCntx->pRsp = NULL; + phNxpEse_clearReadBuffer(conn_ctx); + status = TransceiveProcess(conn_ctx); + if (FALSE == status) { + /* reset all the structures */ + T_SMLOG_E("%s TransceiveProcess failed ", __FUNCTION__); + } + + phNxpEseProto7816_3_Var.phNxpEseProto7816_CurrentState = PH_NXP_ESE_PROTO_7816_IDLE; + return status; +} + +/****************************************************************************** + * Function phNxpEseProto7816_ColdReset + * + * Description This function is used to reset just the current interface + * + * param[in] void + * + * Returns On success return TRUE or else FALSE. + * + ******************************************************************************/ +bool_t phNxpEseProto7816_ColdReset(void *conn_ctx) +{ + bool_t status = FALSE; + sFrameInfo_t *pNextTx_SframeInfo = &phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.SframeInfo; + phNxpEseRx_Cntx_t *pRx_EseCntx = &phNxpEseProto7816_3_Var.phNxpEseRx_Cntx; + + phNxpEseProto7816_3_Var.phNxpEseProto7816_CurrentState = PH_NXP_ESE_PROTO_7816_TRANSCEIVE; + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.FrameType = SFRAME; + pNextTx_SframeInfo->sFrameType = COLD_RESET_REQ; + phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = SEND_S_COLD_RST; + pRx_EseCntx->pRsp = NULL; + status = TransceiveProcess(conn_ctx); + if (FALSE == status) { + /* reset all the structures */ + T_SMLOG_E("%s TransceiveProcess failed ", __FUNCTION__); + } + phNxpEseProto7816_3_Var.phNxpEseProto7816_CurrentState = PH_NXP_ESE_PROTO_7816_IDLE; + return status; +} +#endif +/****************************************************************************** + * Function phNxpEseProto7816_SetIfscSize + * + * Description This function is used to set the max T=1 data send size + * + * param[in] uint16_t IFSC_Size + * + * Returns Always return TRUE (1). + * + ******************************************************************************/ +bool_t phNxpEseProto7816_SetIfscSize(uint16_t IFSC_Size) +{ + iFrameInfo_t *pNextTx_IframeInfo = &phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.IframeInfo; + pNextTx_IframeInfo->maxDataLen = IFSC_Size; + return TRUE; +} + +/****************************************************************************** + * Function phNxpEseProto7816_WTXRsp + * + * Description This function is used to send WTX response + * + * param[in] void* conn_ctx + * + * Returns On success return TRUE or else FALSE. + * + ******************************************************************************/ +bool_t phNxpEseProto7816_WTXRsp(void *conn_ctx) +{ + sFrameInfo_t sFrameInfo; + sFrameInfo.sFrameType = WTX_RSP; + T_SMLOG_D(" %s - Sending WTX Response", __FUNCTION__); + return phNxpEseProto7816_SendSFrame(conn_ctx, sFrameInfo); +} + +/****************************************************************************** + * Function phNxpEseProto7816_SendRSync + * + * Description This function is used to send Rsync + * + * param[in] void* conn_ctx + * + * Returns On success return TRUE or else FALSE. + * + ******************************************************************************/ +bool_t phNxpEseProto7816_SendRSync(void *conn_ctx) +{ + sFrameInfo_t sFrameInfo; + sFrameInfo.sFrameType = RESYNCH_REQ; + T_SMLOG_D(" %s - Sending Rsync", __FUNCTION__); + return phNxpEseProto7816_SendSFrame(conn_ctx, sFrameInfo); +} + +#if defined(T1oI2C_UM11225) +/****************************************************************************** + * Function phNxpEseProto7816_GetAtr + * + * Description This function is used to reset just the current interface + * + * param[in] phNxpEse_data : ATR response from ESE + * + * Returns On success return TRUE or else FALSE. + * + ******************************************************************************/ +bool_t phNxpEseProto7816_GetAtr(void *conn_ctx, phNxpEse_data *pRsp) +{ + bool_t status = FALSE; + sFrameInfo_t *pNextTx_SframeInfo = &phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.SframeInfo; + phNxpEseRx_Cntx_t *pRx_EseCntx = &phNxpEseProto7816_3_Var.phNxpEseRx_Cntx; + + ENSURE_OR_GO_EXIT(pRsp != NULL); + phNxpEseProto7816_3_Var.phNxpEseProto7816_CurrentState = PH_NXP_ESE_PROTO_7816_TRANSCEIVE; + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.FrameType = SFRAME; + pNextTx_SframeInfo->sFrameType = ATR_REQ; + phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = SEND_S_ATR; + pRx_EseCntx->pRsp = pRsp; + pRx_EseCntx->pRsp->len = pRsp->len; + pRx_EseCntx->responseBytesRcvd = 0; + status = TransceiveProcess(conn_ctx); + pRsp->len = pRx_EseCntx->responseBytesRcvd; + if (FALSE == status) { + /* reset all the structures */ + T_SMLOG_E("%s TransceiveProcess failed ", __FUNCTION__); + } + phNxpEseProto7816_3_Var.phNxpEseProto7816_CurrentState = PH_NXP_ESE_PROTO_7816_IDLE; +exit: + return status; +} +#endif + +#if defined(T1oI2C_GP1_0) +/****************************************************************************** + * Function phNxpEseProto7816_GetCip + * + * Description This function is used only by T1oI2c GP to get CIP response + * + * param[in] phNxpEse_data : CIP response from ESE + * + * Returns On success return TRUE or else FALSE. + * + ******************************************************************************/ +bool_t phNxpEseProto7816_GetCip(void *conn_ctx, phNxpEse_data *pRsp) +{ + bool_t status = FALSE; + phNxpEseRx_Cntx_t *pRx_EseCntx = &phNxpEseProto7816_3_Var.phNxpEseRx_Cntx; + sFrameInfo_t *pNextTx_SframeInfo = &phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.SframeInfo; + + ENSURE_OR_GO_EXIT(pRsp != NULL); + phNxpEseProto7816_3_Var.phNxpEseProto7816_CurrentState = PH_NXP_ESE_PROTO_7816_TRANSCEIVE; + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.FrameType = SFRAME; + pNextTx_SframeInfo->sFrameType = CIP_REQ; + phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = SEND_S_CIP; + pRx_EseCntx->pRsp = pRsp; + pRx_EseCntx->pRsp->len = pRsp->len; + pRx_EseCntx->responseBytesRcvd = 0; + status = TransceiveProcess(conn_ctx); + pRsp->len = pRx_EseCntx->responseBytesRcvd; + if (FALSE == status) { + /* reset all the structures */ + T_SMLOG_E("%s TransceiveProcess failed ", __FUNCTION__); + } + + phNxpEseProto7816_3_Var.phNxpEseProto7816_CurrentState = PH_NXP_ESE_PROTO_7816_IDLE; +exit: + return status; +} +#endif + +/****************************************************************************** + * Function phNxpEseProto7816_Deep_Pwr_Down + * + * Description This function is used to send deep power down command + * + * param[in] void + * + * Returns On success return TRUE or else FALSE. + * + ******************************************************************************/ +bool_t phNxpEseProto7816_Deep_Pwr_Down(void *conn_ctx) +{ + bool_t status = FALSE; + sFrameInfo_t *pNextTx_SframeInfo = &phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.SframeInfo; + + phNxpEseProto7816_3_Var.phNxpEseProto7816_CurrentState = PH_NXP_ESE_PROTO_7816_TRANSCEIVE; + /* send the end of session s-frame */ + phNxpEseProto7816_3_Var.phNxpEseNextTx_Cntx.FrameType = SFRAME; + pNextTx_SframeInfo->sFrameType = DEEP_PWR_DOWN_REQ; + phNxpEseProto7816_3_Var.phNxpEseProto7816_nextTransceiveState = SEND_DEEP_PWR_DOWN; + status = TransceiveProcess(conn_ctx); + phNxpEseProto7816_3_Var.phNxpEseProto7816_CurrentState = PH_NXP_ESE_PROTO_7816_IDLE; + return status; +} + +/** @} */ diff --git a/src/lib/t1oi2c/phNxpEseProto7816_3.h b/src/lib/t1oi2c/phNxpEseProto7816_3.h new file mode 100644 index 0000000..dc8170c --- /dev/null +++ b/src/lib/t1oi2c/phNxpEseProto7816_3.h @@ -0,0 +1,437 @@ +/* + * Copyright 2010-2014,2018-2020,2022,2024 NXP + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef _PHNXPESEPROTO7816_3_H_ +#define _PHNXPESEPROTO7816_3_H_ +#include + +/** + * \addtogroup ISO7816-3_protocol_lib + * \brief 7816-3 PROTOCOL STACK + * @{ */ + +/********************* Definitions and structures *****************************/ + +/*! + * \brief S-Frame types used in 7816-3 protocol stack + */ +typedef enum sFrameTypes +{ + RESYNCH_REQ = 0x00, /*!< Re-synchronisation request between host and ESE */ + RESYNCH_RSP = 0x20, /*!< Re-synchronisation response between host and ESE */ + IFSC_REQ = 0x01, /*!< IFSC size request */ + IFSC_RES = 0x21, /*!< IFSC size response */ + ABORT_REQ = 0x02, /*!< Abort request */ + ABORT_RES = 0x22, /*!< Abort response */ + WTX_REQ = 0x03, /*!< WTX request */ + WTX_RSP = 0x23, /*!< WTX response */ +#if defined(T1oI2C_UM11225) + INTF_RESET_REQ = 0x0F, /*!< Interface reset request */ + INTF_RESET_RSP = 0x2F, /*!< Interface reset response */ + PROP_END_APDU_REQ = 0x05, /*!< Proprietary Enf of APDU request */ + PROP_END_APDU_RSP = 0x25, /*!< Proprietary Enf of APDU response */ + CHIP_RESET_REQ = 0x06, /*chip reset request*/ + CHIP_RESET_RES = 0x26, /*chip reset response*/ + ATR_REQ = 0x07, /* get ATR request*/ + ATR_RES = 0x27, /*get ATR response*/ +#elif defined(T1oI2C_GP1_0) + SWR_REQ = 0x0F, /*!< Software reset request */ + SWR_RSP = 0x2F, /*!< Software reset response */ + COLD_RESET_REQ = 0x1E, /*cold reset request*/ + COLD_RESET_RES = 0x3E, /*cold reset response*/ + RELEASE_REQ = 0x06, /* Release request*/ + RELEASE_RES = 0x26, /* Release response*/ + CIP_REQ = 0x04, /*!< Get CIP request */ + CIP_RES = 0x24, /*!< Get CIP response */ +#endif + DEEP_PWR_DOWN_REQ = 0x1F, /*deep power down*/ + DEEP_PWR_DOWN_RES = 0x3F, /*deep power down*/ + INVALID_REQ_RES /*!< Invalid request */ +} sFrameTypes_t; + +/*! + * \brief R-Frame types used in 7816-3 protocol stack + */ +typedef enum rFrameTypes +{ + RACK = 0x01, /*!< R-frame Acknowledgement frame indicator */ + RNACK = 0x02 /*!< R-frame Negative-Acknowledgement frame indicator */ +} rFrameTypes_t; + +/*! + * \brief R-Frame error types used 7816-3 protocol stack + */ +typedef enum rFrameErrorTypes +{ + NO_ERROR, /*!< R-frame received with success */ + PARITY_ERROR, /*!< R-frame received with parity error */ + OTHER_ERROR, /*!< R-frame received with Other error */ + SOF_MISSED_ERROR, /*!< R-frame received with frame missing error */ + UNDEFINED_ERROR /*!< R-frame received with some undefined error */ +} rFrameErrorTypes_t; + +/*! + * \brief Frame types used in 7816-3 protocol stack + */ +typedef enum phNxpEseProto7816_FrameTypes +{ + IFRAME, /*!< Frame type: I-frame */ + SFRAME, /*!< Frame type: S-frame */ + RFRAME, /*!< Frame type: R-frame */ + INVALID, /*!< Frame type: Invalid */ + UNKNOWN /*!< Frame type: Unknown */ +} phNxpEseProto7816_FrameTypes_t; + +/*! + * \brief 7816-3 protocol stack states + */ +typedef enum phNxpEseProto7816_State +{ + PH_NXP_ESE_PROTO_7816_IDLE, /*!< 7816-3 protocol state: IDLE */ + PH_NXP_ESE_PROTO_7816_TRANSCEIVE, /*!< 7816-3 protocol state: TRANSCEIVE going on */ + PH_NXP_ESE_PROTO_7816_DEINIT /*!< 7816-3 protocol state: DeInit going on */ +} phNxpEseProto7816_State_t; + +/*! + * \brief 7816-3 protocol transceive states + */ +typedef enum phNxpEseProto7816_TransceiveStates +{ + IDLE_STATE, /*!< 7816-3 protocol transceive state: IDLE */ + SEND_IFRAME, /*!< 7816-3 protocol transceive state: I-frame to be sent */ + SEND_R_NACK, /*!< 7816-3 protocol transceive state: R-NACK frame to be sent */ + SEND_R_ACK, /*!< 7816-3 protocol transceive state: R-ACK frame to be sent */ + SEND_S_RSYNC, /*!< 7816-3 protocol transceive state: S-frame re-synchronisation command to be sent */ +#if defined(T1oI2C_UM11225) + SEND_S_INTF_RST, /*!< 7816-3 protocol transceive state: S-frame interface reset command to be sent */ + SEND_S_EOS, /*!< 7816-3 protocol transceive state: S-frame end of session command to be sent */ + SEND_S_ATR, /*!< 7816-3 protocol transceive state: S-frame ATR command to be sent */ + SEND_S_CHIP_RST, /*!< 7816-3 protocol transceive state: S-frame chip reset command to be sent */ +#elif defined(T1oI2C_GP1_0) + SEND_S_SWR, /*!< 7816-3 protocol transceive state: S-frame Software reset command to be sent */ + SEND_S_RELEASE, /*!< 7816-3 protocol transceive state: S-frame RELEASE command to be sent */ + SEND_S_CIP, /*!< 7816-3 protocol transceive state: S-frame CIP command to be sent */ + SEND_S_COLD_RST, /*!< 7816-3 protocol transceive state: S-frame cold reset command to be sent */ +#endif + SEND_S_WTX_REQ, /*!< 7816-3 protocol transceive state: S-frame WTX command to be sent */ + SEND_S_WTX_RSP, /*!< 7816-3 protocol transceive state: S-frame WTX response to be sent */ + SEND_DEEP_PWR_DOWN, /*!< Deep power down */ +} phNxpEseProto7816_TransceiveStates_t; + +/*! + * \brief I-frame information structure for ISO 7816-3 + * + * This structure holds the information of I-frame used for sending + * and receiving the frame packet. + * + */ +typedef struct iFrameInfo +{ + bool_t isChained; /*!< I-frame: Indicates if more frames to follow in the same data packet or not */ + uint8_t *p_data; /*!< I-frame: Actual data (Information field (INF)) */ + uint8_t seqNo; /*!< I-frame: Sequence number of the I-frame */ + uint32_t maxDataLen; /*!< I-frame: Maximum data length to be allowed in a single I-frame */ + uint32_t dataOffset; /*!< I-frame: Offset to the actual data(INF) for the current frame of the packet */ + uint32_t + totalDataLen; /*!< I-frame: Total data left in the packet, used to set the chained flag/calculating offset */ + uint32_t sendDataLen; /*!< I-frame: the length of the I-frame actual data */ +} iFrameInfo_t; + +/*! + * \brief S-frame information structure for ISO 7816-3 + * + * This structure holds the information of S-frame used for sending + * and receiving the frame packet. + * + */ +typedef struct sFrameInfo +{ + sFrameTypes_t sFrameType; /*!< S-frame: Type of S-frame cmd/rsp */ +} sFrameInfo_t; + +/*! + * \brief R-frame information structure for ISO 7816-3 + * + * This structure holds the information of R-frame used for sending + * and receiving the frame packet. + * + */ +typedef struct rFrameInfo +{ + uint8_t seqNo; /*!< R-frame: Sequence number of the expected I-frame */ + rFrameErrorTypes_t errCode; /*!< R-frame: Error type */ +} rFrameInfo_t; + +/*! + * \brief Next/Last Tx information structure holding transceive data + * + * This structure holds the information of the next/last sent + * I-frame/R-frame/S-frame depending on the frame type + * + */ +typedef struct phNxpEseProto7816_NextTx_Info +{ + //union { + iFrameInfo_t + IframeInfo; /*!< Information of the I-frame to be send next or the last sent I-frame depending on the frame type */ + rFrameInfo_t + RframeInfo; /*!< Information of the R-frame to be send next or the last sent R-frame depending on the frame type */ + sFrameInfo_t + SframeInfo; /*!< Information of the S-frame to be send next or the last sent S-frame depending on the frame type */ + //} f; + phNxpEseProto7816_FrameTypes_t FrameType; /*!< Frame (I/R/S frames) type to be sent next */ +} phNxpEseProto7816_NextTx_Info_t; + +/*! + * \brief Last sent Tx ransceive data + * + * This structure holds the information of the last sent + * I-frame/R-frame/S-frame + * + */ +typedef phNxpEseProto7816_NextTx_Info_t phNxpEseProto7816_LastTx_Info_t; + +/*! + * \brief Last Rx information structure holding transceive data + * + * This structure holds the information of the next/last sent + * I-frame/R-frame/S-frame + * + */ +typedef struct phNxpEseRx_Cntx +{ + iFrameInfo_t lastRcvdIframeInfo; /*!< I-frame: Last received frame */ + rFrameInfo_t lastRcvdRframeInfo; /*!< R-frame: Last received frame */ + sFrameInfo_t lastRcvdSframeInfo; /*!< S-frame: Last received frame */ + phNxpEseProto7816_FrameTypes_t lastRcvdFrameType; /*!< Last received frame type */ + phNxpEse_data *pRsp; + size_t responseBytesRcvd; +} phNxpEseRx_Cntx_t; + +/*! + * \brief 7816-3 protocol stack context structure + * + * This structure holds the complete information of the + * 7816-3 protocol stack context + * + */ +typedef struct phNxpEseProto7816 +{ + phNxpEseProto7816_LastTx_Info_t phNxpEseLastTx_Cntx; /*!< Last transmitted frame information */ + phNxpEseProto7816_NextTx_Info_t phNxpEseNextTx_Cntx; /*!< Next frame to be transmitted */ + phNxpEseRx_Cntx_t phNxpEseRx_Cntx; /*!< Last received frame information */ + phNxpEseProto7816_TransceiveStates_t + phNxpEseProto7816_nextTransceiveState; /*!< Next Transceive state. It determines the next + action to be done from host */ + phNxpEseProto7816_State_t phNxpEseProto7816_CurrentState; /*!< Current protocol stack state */ + uint8_t + recoveryCounter; /*!< Keeps track of number of error recovery done. Stack exits after it reaches max. count */ + unsigned long int wtx_counter_limit; /*!< Max. WTX counter limit */ + unsigned long int wtx_counter; /*!< WTX count tracker */ + uint8_t timeoutCounter; /*!< Keeps track of number of timeout happened. Stack exits after it reaches max. count */ + phNxpEseProto7816_FrameTypes_t + lastSentNonErrorframeType; /*!< Copy of the last sent non-error frame type: R-ACK, S-frame, I-frame */ + unsigned long int rnack_retry_limit; + unsigned long int rnack_retry_counter; +} phNxpEseProto7816_t; + +/*! + * \brief 7816-3 protocol stack init params + * + * This structure holds the parameters to be passed to open 7816-3 protocl stack instance + * + */ +typedef struct phNxpEseProto7816InitParam +{ + unsigned long int wtx_counter_limit; /*!< WTX count limit */ + bool_t interfaceReset; /*!< INTF reset required or not>*/ + unsigned long int rnack_retry_limit; +} phNxpEseProto7816InitParam_t; + +/*! + * \brief 7816_3 protocol stack instance + */ +//phNxpEseProto7816_t phNxpEseProto7816_3_Var; + +/*! + * \brief Max. size of the frame that can be sent + */ +#define IFSC_SIZE_SEND 254 +/*! + * \brief Delay to be used before sending the next frame, after error reported by ESE + */ +#define DELAY_ERROR_RECOVERY 3500 +/*! + * \brief 7816-3 protocol frame header length + */ +#if defined(T1oI2C_UM11225) +#define PH_PROTO_7816_HEADER_LEN 0x03 // LEN field is 1 byte +#elif defined(T1oI2C_GP1_0) +#define PH_PROTO_7816_HEADER_LEN 0x04 // LEN field is 2 byte +#endif +/*! + * \brief 7816-3 protocol frame CRC length + */ +#define PH_PROTO_7816_CRC_LEN 0x02 +/*! + * \brief 7816-3 Chaining flag bit for masking + */ +#define PH_PROTO_7816_CHAINING 0x20 +/*! + * \brief 7816-3 frame length offset + */ +#define PH_PROPTO_7816_FRAME_LENGTH_OFFSET 0x02 +/*! + * \brief 7816-3 S-block request command mask + */ +#define PH_PROTO_7816_S_BLOCK_REQ 0xC0 +/*! + * \brief 7816-3 S-block response mask + */ +#define PH_PROTO_7816_S_BLOCK_RSP 0xE0 +/*! + * \brief 7816-3 S-block reset command mask + */ +#define PH_PROTO_7816_S_RESET 0x0F +/*! + * \brief 7816-3 S-block End of APDU cmd mask + */ +#define PH_PROTO_7816_S_END_OF_APDU 0x05 +/*! + * \brief 7816-3 S-block WTX mask + */ +#define PH_PROTO_7816_S_WTX 0x03 +/*! + * \brief 7816-3 S-block re-sync mask + */ +#define PH_PROTO_7816_S_RESYNCH 0x00 +/*! + * \brief 7816-3 protocol max. error retry counter + */ +#define PH_PROTO_7816_FRAME_RETRY_COUNT 10 +/*! + * \brief 7816-3 protocol max. WTX default count + */ +#define PH_PROTO_WTX_DEFAULT_COUNT 500 +/*! + * \brief 7816-3 protocol max. timeout retry count + */ +#define PH_PROTO_7816_TIMEOUT_RETRY_COUNT 1 +/*! + * \brief 7816-3 to represent magic number zero + */ +#define PH_PROTO_7816_VALUE_ZERO 0x00 +/*! + * \brief 7816-3 to represent magic number one + */ +#define PH_PROTO_7816_VALUE_ONE 0x01 +/*! + * \brief 7816-3 for max retry for CRC error + */ +#define MAX_RNACK_RETRY_LIMIT 0x02 +/*! + * \brief 7816-3 S-block chip reset mask + */ +#if defined(T1oI2C_UM11225) +#define PH_PROTO_7816_S_CHIP_RST 0x06 +#elif defined(T1oI2C_GP1_0) +#define PH_PROTO_7816_S_COLD_RST 0x1E +#endif +/*! + * \brief 7816-3 S-block get atr mask + */ +#define PH_PROTO_7816_S_GET_ATR 0x07 +/*! + * \brief 7816-3 S-block deep power down + */ +#define PH_PROTO_7816_S_DEEP_PWR_DOWN 0x1F +/*! + * \brief 7816-3 S-block software reset mask + */ +#define PH_PROTO_7816_S_SWR 0x0F +/*! + * \brief 7816-3 S-block release cmd mask + */ +#define PH_PROTO_7816_S_RELEASE 0x06 +/*! + * \brief 7816-3 S-block get CIP cmd mask + */ +#define PH_PROTO_7816_S_GET_CIP 0x04 + +/* T=1 protocol Block format for T1oI2C UM11225_SE050 + ___________________________________________________________________________________________________ +| Prologue Filed (Mandatory) | Information Field (Optional)| Epilogue Filed (Mandatory) | +|________________________________________|_____________________________|____________________________| +|NAD(1 byte) | PCB(1 byte) | LEN(1 byte) | INF(LEN bytes) | CRC(2 bytes) | | +|____________|_____________|_____________|_____________________________|____________________________| | +*/ + +/* T=1 protocol Block format for T1oI2C GP + ___________________________________________________________________________________________________ +| Prologue Filed (Mandatory) | Information Field (Optional)| Epilogue Filed (Mandatory) | +|________________________________________|_____________________________|____________________________| +|NAD(1 byte) | PCB(1 byte) | LEN(2 byte) | INF(LEN bytes) | CRC(2 bytes) | | +|____________|_____________|_____________|_____________________________|____________________________| | +*/ + +#define PH_PROPTO_7816_NAD_OFFSET 0 +#define PH_PROPTO_7816_PCB_OFFSET 1 +#define PH_PROPTO_7816_LEN_UPPER_OFFSET 2 +#define PH_PROPTO_7816_LEN_LOWER_OFFSET 3 /* for GP lower byte will be a part of T=1 protocol frame*/ +#define PH_PROPTO_7816_INF_BYTE_OFFSET (PH_PROTO_7816_HEADER_LEN) + +/*! + * \brief Start of frame marker + * \ communication Direction NAD value + * \ SE host to SE 0x5A + * \ SE to SE host 0xA5 + * \ eUICC host to Euicc 0x4B + * \ eUICC to eUICC host 0xB4 + */ +#define SEND_PACKET_SOF 0x5A +/*! + * \Retrieve Information Filed from 7816-3 T=1 protocol frame + * NAD -1 byte + * PCB -1 byte + * LEN -(1 or 3 bytes for UM11225_SE050) & (2 bytes for GP) + * CRC16 -2 bytes + */ +#define PH_PROTO_7816_INF_FILED (PH_PROTO_7816_HEADER_LEN + PH_PROTO_7816_CRC_LEN) +/* + * APIs exposed from the 7816-3 protocol layer + */ + +#if defined(T1oI2C_UM11225) +bool_t phNxpEseProto7816_IntfReset(void *conn_ctx, phNxpEse_data *AtrRsp); +bool_t phNxpEseProto7816_GetAtr(void *conn_ctx, phNxpEse_data *pRsp); +bool_t phNxpEseProto7816_ChipReset(void *conn_ctx); +#endif +bool_t phNxpEseProto7816_Close(void *conn_ctx); +bool_t phNxpEseProto7816_Open(void *conn_ctx, phNxpEseProto7816InitParam_t initParam, phNxpEse_data *AtrRsp); +bool_t phNxpEseProto7816_Transceive(void *conn_ctx, phNxpEse_data *pCmd, phNxpEse_data *pRsp); +bool_t phNxpEseProto7816_Reset(void); +bool_t phNxpEseProto7816_SetIfscSize(uint16_t IFSC_Size); +bool_t phNxpEseProto7816_ResetProtoParams(void); +#if defined(T1oI2C_GP1_0) +bool_t phNxpEseProto7816_SoftReset(void *conn_ctx); +bool_t phNxpEseProto7816_GetCip(void *conn_ctx, phNxpEse_data *pRsp); +bool_t phNxpEseProto7816_ColdReset(void *conn_ctx); +#endif +uint8_t getMaxSupportedSendIFrameSize(void); +bool_t phNxpEseProto7816_WTXRsp(void *conn_ctx); +bool_t phNxpEseProto7816_SendRSync(void *conn_ctx); +bool_t phNxpEseProto7816_Deep_Pwr_Down(void *conn_ctx); +/** @} */ +#endif /* _PHNXPESEPROTO7816_3_H_ */ diff --git a/src/lib/t1oi2c/phNxpEse_Api.c b/src/lib/t1oi2c/phNxpEse_Api.c new file mode 100644 index 0000000..2fe17ac --- /dev/null +++ b/src/lib/t1oi2c/phNxpEse_Api.c @@ -0,0 +1,828 @@ +/* + * Copyright 2012-2014,2018-2020,2022,2024,2026 NXP + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include +#include +#include "lib/platform/arduino/sm_timer.h" +#include "lib/apdu/se05x_tlv.h" +#include "lib/platform/arduino/sm_port.h" +#include + +#define RECIEVE_PACKET_SOF 0xA5 +#define CHAINED_PACKET_WITHSEQN 0x60 +#define CHAINED_PACKET_WITHOUTSEQN 0x20 +#define WTX_REQ_ID 0xC3 +static int phNxpEse_readPacket(void *conn_ctx, void *pDevHandle, uint8_t *pBuffer, int nNbBytesToRead); +static int poll_sof_chained_delay = 0; + +/* Duration for which session open should wait for previous transaction to complete */ +#define T1OI2C_WAIT_FOR_PREV_TXN 40 + +/*********************** Global Variables *************************************/ + +/* ESE Context structure */ +phNxpEse_Context_t gnxpese_ctxt; + +/****************************************************************************** + * Function phNxpEse_init + * + * Description This function is called by smCom during the + * initialization of the ESE. It initializes protocol stack instance variable + * + * param[in] connection context + * param[in] phNxpEse_initParams: ESE communication mode + * param[out] phNxpEse_data: ATR Response from ESE + * + * Returns This function return ESESTATUS_SUCCES (0) in case of success + * In case of failure returns other failure value. + * + ******************************************************************************/ +ESESTATUS phNxpEse_init(void *conn_ctx, phNxpEse_initParams initParams, phNxpEse_data *AtrRsp) +{ + ESESTATUS wConfigStatus = ESESTATUS_SUCCESS; + phNxpEse_Context_t *nxpese_ctxt = (conn_ctx == NULL) ? &gnxpese_ctxt : (phNxpEse_Context_t *)conn_ctx; + bool_t status = FALSE; + phNxpEseProto7816InitParam_t protoInitParam; + phNxpEse_memset(&protoInitParam, 0x00, sizeof(phNxpEseProto7816InitParam_t)); + protoInitParam.rnack_retry_limit = MAX_RNACK_RETRY_LIMIT; + protoInitParam.wtx_counter_limit = PH_PROTO_WTX_DEFAULT_COUNT; + + if (ESE_MODE_NORMAL == initParams.initMode) /* TZ/Normal wired mode should come here*/ + { + protoInitParam.interfaceReset = TRUE; + } + else if (ESE_MODE_RESUME == initParams.initMode) { + /* To skip GetAtr command */ + protoInitParam.interfaceReset = FALSE; + } + else { + protoInitParam.interfaceReset = FALSE; + /*RFU*/ + } + + /* T=1 Protocol layer open */ + status = phNxpEseProto7816_Open((void *)nxpese_ctxt, protoInitParam, AtrRsp); + if (FALSE == status) { + wConfigStatus = ESESTATUS_FAILED; + T_SMLOG_E("phNxpEseProto7816_Open failed "); + } + return wConfigStatus; +} + +/****************************************************************************** + * Function phNxpEse_open + * + * Description This function is called by smCom during the + * initialization of the ESE. It opens the physical connection + * with ESE and initializes the protocol stack + * + * param[in] Pointer to connection context + * param[in] phNxpEse_initParams: ESE communication mode + * + * Returns This function return ESESTATUS_SUCCES (0) in case of success + * In case of failure returns other failure value. + * + ******************************************************************************/ +ESESTATUS phNxpEse_open(void **conn_ctx, phNxpEse_initParams initParams, const char *pConnString) +{ + phPalEse_Config_t tPalConfig; + phNxpEse_Context_t *pnxpese_ctxt = NULL; + ESESTATUS wConfigStatus = ESESTATUS_SUCCESS; + + pnxpese_ctxt = &gnxpese_ctxt; + phNxpEse_memset(pnxpese_ctxt, 0, sizeof(phNxpEse_Context_t)); + if (conn_ctx != NULL) { + *conn_ctx = pnxpese_ctxt; + } + + /*When I2C channel is already opened return status as FAILED*/ + if (pnxpese_ctxt->EseLibStatus != ESE_STATUS_CLOSE) { + T_SMLOG_E(" Session already opened"); + return ESESTATUS_BUSY; + } + + phNxpEse_memset(pnxpese_ctxt, 0x00, sizeof(phNxpEse_Context_t)); + phNxpEse_memset(&tPalConfig, 0x00, sizeof(tPalConfig)); + + tPalConfig.pDevName = (int8_t *)pConnString; //"/dev/p73"; /*RFU*/ + /* Initialize PAL layer */ + wConfigStatus = phPalEse_i2c_open_and_configure(&tPalConfig); + if (wConfigStatus != ESESTATUS_SUCCESS) { + T_SMLOG_E("phPalEse_Init Failed"); + goto clean_and_return; + } + /* Copying device handle to ESE Lib context*/ + pnxpese_ctxt->pDevHandle = tPalConfig.pDevHandle; + /* STATUS_OPEN */ + pnxpese_ctxt->EseLibStatus = ESE_STATUS_OPEN; + phNxpEse_memcpy(&pnxpese_ctxt->initParams, &initParams, sizeof(phNxpEse_initParams)); + return wConfigStatus; + +clean_and_return: + if (NULL != pnxpese_ctxt->pDevHandle) { + phPalEse_i2c_close(pnxpese_ctxt->pDevHandle); + phNxpEse_memset(pnxpese_ctxt, 0x00, sizeof(phNxpEse_Context_t)); + } + pnxpese_ctxt->EseLibStatus = ESE_STATUS_CLOSE; + return ESESTATUS_FAILED; +} + +/****************************************************************************** + * Function phNxpEse_Transceive + * + * Description This function validate ESE state & C-APDU data before sending + * it to 7816 protocol + * + * param[in] connection context + * param[in] phNxpEse_data: Command to ESE C-APDU + * param[out] phNxpEse_data: Response from ESE R-APDU + * + * Returns On Success ESESTATUS_SUCCESS else proper error code + * + ******************************************************************************/ +ESESTATUS phNxpEse_Transceive(void *conn_ctx, phNxpEse_data *pCmd, phNxpEse_data *pRsp) +{ + ESESTATUS status = ESESTATUS_FAILED; + bool_t bStatus = FALSE; + phNxpEse_Context_t *nxpese_ctxt = (conn_ctx == NULL) ? &gnxpese_ctxt : (phNxpEse_Context_t *)conn_ctx; + + if ((NULL == pCmd) || (NULL == pRsp)) { + return ESESTATUS_INVALID_PARAMETER; + } + + if ((pCmd->len == 0) || pCmd->p_data == NULL) { + T_SMLOG_E(" phNxpEse_Transceive - Invalid Parameter no data"); + return ESESTATUS_INVALID_PARAMETER; + } + else if ((ESE_STATUS_CLOSE == nxpese_ctxt->EseLibStatus)) { + T_SMLOG_E(" %s ESE Not Initialized ", __FUNCTION__); + return ESESTATUS_NOT_INITIALISED; + } + else if ((ESE_STATUS_BUSY == nxpese_ctxt->EseLibStatus)) { + T_SMLOG_E(" %s ESE - BUSY ", __FUNCTION__); + return ESESTATUS_BUSY; + } + else { + nxpese_ctxt->EseLibStatus = ESE_STATUS_BUSY; + bStatus = phNxpEseProto7816_Transceive((void *)nxpese_ctxt, pCmd, pRsp); + if (TRUE == bStatus) { + status = ESESTATUS_SUCCESS; + } + else { + status = ESESTATUS_FAILED; + } + + if (ESESTATUS_SUCCESS != status) { + T_SMLOG_E(" %s phNxpEseProto7816_Transceive- Failed ", __FUNCTION__); + } + if (nxpese_ctxt->EseLibStatus != ESE_STATUS_CLOSE) { + nxpese_ctxt->EseLibStatus = ESE_STATUS_IDLE; + } + + T_SMLOG_D(" %s Exit status 0x%x ", __FUNCTION__, status); + return status; + } +} + +/****************************************************************************** + * Function phNxpEse_reset + * + * Description This function reset the ESE interface and free all + * + * param[in] connection context + * + * Returns It returns ESESTATUS_SUCCESS (0) if the operation is successful else + * ESESTATUS_FAILED(1) + ******************************************************************************/ +ESESTATUS phNxpEse_reset(void *conn_ctx) +{ + ESESTATUS status = ESESTATUS_FAILED; + phNxpEse_Context_t *nxpese_ctxt = (conn_ctx == NULL) ? &gnxpese_ctxt : (phNxpEse_Context_t *)conn_ctx; + //bool_t bStatus = phNxpEseProto7816_IntfReset(&AtrRsp); + status = phNxpEse_chipReset((void *)nxpese_ctxt); + if (status != ESESTATUS_SUCCESS) { + T_SMLOG_E("phNxpEse_reset Failed"); + } + return status; +} + +/****************************************************************************** + * Function phNxpEse_EndOfApdu + * + * Description This function is used to send S-frame to indicate END_OF_APDU + * + * param[in] connection context + * + * Returns It returns ESESTATUS_SUCCESS (0) if the operation is successful else + * ESESTATUS_FAILED(1) + * + ******************************************************************************/ +ESESTATUS phNxpEse_EndOfApdu(void *conn_ctx) +{ + ESESTATUS status = ESESTATUS_SUCCESS; + phNxpEse_Context_t *nxpese_ctxt = (conn_ctx == NULL) ? &gnxpese_ctxt : (phNxpEse_Context_t *)conn_ctx; + bool_t bStatus = phNxpEseProto7816_Close((void *)nxpese_ctxt); + if (!bStatus) { + status = ESESTATUS_FAILED; + } + return status; +} + +/****************************************************************************** + * Function phNxpEse_chipReset + * + * Description This function is used to reset the ESE. + * + * param[in] connection context + * + * Returns On Success ESESTATUS_SUCCESS (0) else ESESTATUS_FAILED (1). + * + ******************************************************************************/ +ESESTATUS phNxpEse_chipReset(void *conn_ctx) +{ + ESESTATUS status = ESESTATUS_SUCCESS; + bool_t bStatus = FALSE; + phNxpEse_Context_t *nxpese_ctxt = (conn_ctx == NULL) ? &gnxpese_ctxt : (phNxpEse_Context_t *)conn_ctx; + bStatus = phNxpEseProto7816_Reset(); + if (!bStatus) { + status = ESESTATUS_FAILED; + T_SMLOG_E("phNxpEseProto7816_Reset Failed"); + } +#if defined(T1oI2C_UM11225) + bStatus = phNxpEseProto7816_ChipReset((void *)nxpese_ctxt); +#elif defined(T1oI2C_GP1_0) + bStatus = phNxpEseProto7816_ColdReset((void *)nxpese_ctxt); +#endif + if (bStatus != TRUE) { + T_SMLOG_E("phNxpEse_chipReset Failed"); + } + return status; +} + +/****************************************************************************** + * Function phNxpEse_deInit + * + * Description This function de-initializes all the ESE protocol params + * + * param[in] connection context + * + * Returns On Success ESESTATUS_SUCCESS (0) else ESESTATUS_FAILED (1). + * + ******************************************************************************/ +ESESTATUS phNxpEse_deInit(void *conn_ctx) +{ + ESESTATUS status = ESESTATUS_SUCCESS; + //bool_t bStatus = FALSE; + phNxpEse_Context_t *nxpese_ctxt = (conn_ctx == NULL) ? &gnxpese_ctxt : (phNxpEse_Context_t *)conn_ctx; + /*bStatus = phNxpEseProto7816_ResetProtoParams(); + if(!bStatus) + { + status = ESESTATUS_FAILED; + }*/ + phPalEse_i2c_close(nxpese_ctxt->pDevHandle); + phNxpEse_memset(nxpese_ctxt, 0x00, sizeof(*nxpese_ctxt)); + //status= phNxpEse_close(); + return status; +} + +/****************************************************************************** + * Function phNxpEse_close + * + * Description This function close the ESE interface and free all + * resources. + * + * param[in] connection context + * + * Returns On Success ESESTATUS_SUCCESS else proper error code. + * + ******************************************************************************/ +ESESTATUS phNxpEse_close(void *conn_ctx) +{ + ESESTATUS status = ESESTATUS_SUCCESS; + phNxpEse_Context_t *nxpese_ctxt = (conn_ctx == NULL) ? &gnxpese_ctxt : (phNxpEse_Context_t *)conn_ctx; + + if ((ESE_STATUS_CLOSE == nxpese_ctxt->EseLibStatus)) { + T_SMLOG_E(" %s ESE Not Initialized previously ", __FUNCTION__); + return ESESTATUS_NOT_INITIALISED; + } + + phPalEse_i2c_close(nxpese_ctxt->pDevHandle); + phNxpEse_memset(nxpese_ctxt, 0x00, sizeof(*nxpese_ctxt)); + T_SMLOG_D("phNxpEse_close - ESE Context deinit completed"); + /* Return success always */ + return status; +} + +/****************************************************************************** + * Function phNxpEse_waitWTX + * + * Description This function read out any wtx requests received from the previous + * session and send wtx response. + * Additionally read any response at end of WTX and ignore it. + * Just to make sure that if host was not able to finish previous operation, + * the response of that must not cause an error in current session. + * + * param[in] void*: connection context + * + * Returns void + * + ******************************************************************************/ +void phNxpEse_waitForWTX(void *conn_ctx) +{ + int ret = -1; + int loopcnt = 0; + //int wtx_cnt = 0; + //uint8_t readBuf[MAX_APDU_BUFFER] = {0}; + phNxpEse_Context_t *nxpese_ctxt = (conn_ctx == NULL) ? &gnxpese_ctxt : (phNxpEse_Context_t *)conn_ctx; + + T_SMLOG_D("%s Enter ..", __FUNCTION__); + + /* Send Rsync - To check if there is a pending operation (by checking for WTX) */ + if (!phNxpEseProto7816_SendRSync(conn_ctx)) { + T_SMLOG_E(" %s - Error in phNxpEseProto7816_SendRSync ", __FUNCTION__); + return; + } + + //ret = phPalEse_i2c_read(nxpese_ctxt->pDevHandle, readBuf, MAX_APDU_BUFFER); + ret = phPalEse_i2c_read(nxpese_ctxt->pDevHandle, nxpese_ctxt->p_read_buff, MAX_APDU_BUFFER); + + if (ret < 0) { + return; + } + else { + //if (readBuf[0] == RECIEVE_PACKET_SOF && readBuf[1] == WTX_REQ_ID) + if (nxpese_ctxt->p_read_buff[0] == RECIEVE_PACKET_SOF && nxpese_ctxt->p_read_buff[1] == WTX_REQ_ID) { + /** 0xC3 corresponds to WTX request. Send WTX response. */ + T_SMLOG_D(" %s - Received WTX Request", __FUNCTION__); + if (!phNxpEseProto7816_WTXRsp(conn_ctx)) { + T_SMLOG_E(" %s - Error in phNxpEseProto7816_WTXRsp ", __FUNCTION__); + return; + } + T_SMLOG_D("Wait till previous transaction is complete"); + } + else { + T_SMLOG_D("No WTX request received. Continue with session open"); + return; + } + } + + while (loopcnt < T1OI2C_WAIT_FOR_PREV_TXN) { + sm_sleep(1000); /* WTX is expected every 1 sec */ + //ret = phPalEse_i2c_read(nxpese_ctxt->pDevHandle, readBuf, MAX_APDU_BUFFER); + ret = phPalEse_i2c_read(nxpese_ctxt->pDevHandle, nxpese_ctxt->p_read_buff, MAX_APDU_BUFFER); + if (ret < 0) { + T_SMLOG_E(" %s - Error in phPalEse_i2c_read ", __FUNCTION__); + } + else { + T_SMLOG_MAU8_D("Previous RAW Rx < ", nxpese_ctxt->p_read_buff, ret); + //if (readBuf[0] == RECIEVE_PACKET_SOF && readBuf[1] == WTX_REQ_ID) + if (nxpese_ctxt->p_read_buff[0] == RECIEVE_PACKET_SOF && nxpese_ctxt->p_read_buff[1] == WTX_REQ_ID) { + /** 0xC3 corresponds to WTX request. Send WTX response. */ + T_SMLOG_D(" %s - Received WTX Request", __FUNCTION__); + //LOG_I("WTX REQ received (CNT = %d).. Send WTX Resp \n", ++wtx_cnt); + if (!phNxpEseProto7816_WTXRsp(conn_ctx)) { + T_SMLOG_E(" %s - Error in phNxpEseProto7816_WTXRsp ", __FUNCTION__); + return; + } + } + else { + T_SMLOG_D("Ignoring response other than WTX Request. Continue with session open"); + return; + } + } + loopcnt++; + } + T_SMLOG_W("Last operation took more time than expected"); + T_SMLOG_W("Either increase waiting time (T1OI2C_WAIT_FOR_PREV_TXN) or do a physical reset of IC"); + return; +} + +/****************************************************************************** + * Function phNxpEse_clearReadBuffer + * + * Description This function read out complete data from SE FIFO read buffer + * interface (e.g. I2C) using the driver interface. + * Just to make sure that if host is unable to read complete data + * during previous transaction + * + * param[in] void*: connection context + * + * Returns void + * + ******************************************************************************/ +void phNxpEse_clearReadBuffer(void *conn_ctx) +{ + int ret = -1; + //uint8_t readBuf[MAX_APDU_BUFFER]; + phNxpEse_Context_t *nxpese_ctxt = (conn_ctx == NULL) ? &gnxpese_ctxt : (phNxpEse_Context_t *)conn_ctx; + + T_SMLOG_D("%s Enter ..", __FUNCTION__); + + ret = phPalEse_i2c_read(nxpese_ctxt->pDevHandle, nxpese_ctxt->p_read_buff, MAX_APDU_BUFFER); + if (ret < 0) { + /* Do nothing as nothing to read*/ + } + else { + T_SMLOG_W("Previous transaction buffer is now cleard"); + T_SMLOG_MAU8_D("RAW Rx<", nxpese_ctxt->p_read_buff, ret); + } + return; +} + +/****************************************************************************** + * Function phNxpEse_read + * + * Description This function read the data from ESE through physical + * interface (e.g. I2C) using the driver interface. + * + * param[in] void*: connection context + * param[out] uint32_t: number of bytes read + * param[out] uint8_t : Read data from ESE + * + * Returns It returns ESESTATUS_SUCCESS (0) if read successful else + * ESESTATUS_FAILED(1) + * + ******************************************************************************/ +ESESTATUS phNxpEse_read(void *conn_ctx, uint32_t *data_len, uint8_t **pp_data) +{ + ESESTATUS status = ESESTATUS_FAILED; + int ret = -1; + phNxpEse_Context_t *nxpese_ctxt = (conn_ctx == NULL) ? &gnxpese_ctxt : (phNxpEse_Context_t *)conn_ctx; + + T_SMLOG_D("%s Enter ..", __FUNCTION__); + + ENSURE_OR_GO_EXIT(data_len != NULL); + ENSURE_OR_GO_EXIT(pp_data != NULL); + + ret = phNxpEse_readPacket((void *)nxpese_ctxt, nxpese_ctxt->pDevHandle, nxpese_ctxt->p_read_buff, MAX_APDU_BUFFER); + if (ret < 0) { + T_SMLOG_E("PAL Read status error status = %x", status); + status = ESESTATUS_FAILED; + } + else { + T_SMLOG_MAU8_D("RAW Rx<", nxpese_ctxt->p_read_buff, ret); + *data_len = ret; + *pp_data = nxpese_ctxt->p_read_buff; + status = ESESTATUS_SUCCESS; + } +exit: + return status; +} + +/****************************************************************************** + * Function phNxpEse_readPacket + * + * Description This function Reads requested number of bytes from + * ESE device into given buffer. + * + * param[in] void*: connection context + * param[in] void: ESE Context + * param[in] uint8_t: pointer to read buffer + * param[in] int : MAX bytes to read + * + * Returns ret - number of successfully read bytes + * -1 - read operation failure + * + ******************************************************************************/ +static int phNxpEse_readPacket(void *conn_ctx, void *pDevHandle, uint8_t *pBuffer, int nNbBytesToRead) +{ + int ret = -1; + int sof_counter = 0; /* one read may take 1 ms*/ + int total_count = 0, numBytesToRead = 0, headerIndex = 0; + phNxpEse_Context_t *nxpese_ctxt = (conn_ctx == NULL) ? &gnxpese_ctxt : (phNxpEse_Context_t *)conn_ctx; + + ENSURE_OR_GO_EXIT(pBuffer != NULL); + memset(pBuffer, 0, nNbBytesToRead); + do { + sof_counter++; + ret = -1; + ret = phPalEse_i2c_read(pDevHandle, pBuffer, 2); /*read NAD PCB byte first*/ + if (ret < 0) { + /*Polling for read on i2c, hence Debug log*/ + T_SMLOG_D("_i2c_read() ret : %X", ret); + } + + if (pBuffer[0] == RECIEVE_PACKET_SOF) { + /* Read the HEADR of Two bytes*/ + T_SMLOG_D("%s Read HDR", __FUNCTION__); + pBuffer[0] = RECIEVE_PACKET_SOF; +#if defined(T1oI2C_UM11225) + numBytesToRead = 1; +#elif defined(T1oI2C_GP1_0) + numBytesToRead = 2; +#endif + headerIndex = 1; + break; + } + + if (pBuffer[1] == RECIEVE_PACKET_SOF) { + /* Read the HEADR of Two bytes*/ + T_SMLOG_D("%s Read HDR", __FUNCTION__); + pBuffer[0] = RECIEVE_PACKET_SOF; +#if defined(T1oI2C_UM11225) + numBytesToRead = 2; +#elif defined(T1oI2C_GP1_0) + numBytesToRead = 3; +#endif + headerIndex = 0; + break; + } + + /*if host writes invalid frame and host and SE are out of sync*/ + if ((pBuffer[0] == 0x00) && ((pBuffer[1] == 0x82) || (pBuffer[1] == 0x92))) { + T_SMLOG_W("%s Recieved NAD byte 0x%x ", __FUNCTION__, pBuffer[0]); + T_SMLOG_W("%s NAD error, clearing the read buffer ", __FUNCTION__); + /*retry to get all data*/ +#if defined(T1oI2C_UM11225) + numBytesToRead = 1; +#elif defined(T1oI2C_GP1_0) + numBytesToRead = 2; +#endif + headerIndex = 1; + ret = phPalEse_i2c_read(pDevHandle, &pBuffer[1 + headerIndex], numBytesToRead); +#if defined(T1oI2C_UM11225) + total_count = 3; + nNbBytesToRead = pBuffer[2]; +#elif defined(T1oI2C_GP1_0) + total_count = 4; + nNbBytesToRead = (pBuffer[2] << 8 & 0xFF) | (pBuffer[3] & 0xFF); +#endif + /* Read the Complete data + two byte CRC*/ + ret = phPalEse_i2c_read( + pDevHandle, &pBuffer[PH_PROTO_7816_HEADER_LEN], (nNbBytesToRead + PH_PROTO_7816_CRC_LEN)); + if (ret < 0) { + T_SMLOG_D("_i2c_read() ret : %X", ret); + ret = -1; + } + else { + ret = (total_count + (nNbBytesToRead + PH_PROTO_7816_CRC_LEN)); + } + break; + } + + /*If it is Chained packet wait for 1 ms*/ + if (poll_sof_chained_delay == 1) { + T_SMLOG_D("%s Chained Pkt, delay read %dms", __FUNCTION__, ESE_POLL_DELAY_MS * CHAINED_PKT_SCALER); + } + else { + T_SMLOG_D("%s Normal Pkt, delay read %dms", __FUNCTION__, ESE_POLL_DELAY_MS * NAD_POLLING_SCALER); + } + } while ((sof_counter < ESE_NAD_POLLING_MAX) && (nxpese_ctxt->EseLibStatus != ESE_STATUS_CLOSE)); + + if ((pBuffer[0] == RECIEVE_PACKET_SOF) && (ret > 0)) { + T_SMLOG_D("%s SOF FOUND", __FUNCTION__); + /* Read the HEADR of one/Two bytes based on how two bytes read A5 PCB or 00 A5*/ + ret = phPalEse_i2c_read(pDevHandle, &pBuffer[1 + headerIndex], numBytesToRead); + if (ret < 0) { + T_SMLOG_D("_i2c_read() ret: %X", ret); + } + if ((pBuffer[1] == CHAINED_PACKET_WITHOUTSEQN) || (pBuffer[1] == CHAINED_PACKET_WITHSEQN)) { + poll_sof_chained_delay = 1; + T_SMLOG_D("poll_sof_chained_delay value is %d ", poll_sof_chained_delay); + } + else { + poll_sof_chained_delay = 0; + T_SMLOG_D("poll_sof_chained_delay value is %d ", poll_sof_chained_delay); + } +#if defined(T1oI2C_UM11225) + total_count = 3; + nNbBytesToRead = pBuffer[2]; +#elif defined(T1oI2C_GP1_0) + total_count = 4; + nNbBytesToRead = (pBuffer[2] << 8 & 0xFF00) | (pBuffer[3] & 0xFF); +#endif + /* Read the Complete data + two byte CRC*/ + ret = + phPalEse_i2c_read(pDevHandle, &pBuffer[PH_PROTO_7816_HEADER_LEN], (nNbBytesToRead + PH_PROTO_7816_CRC_LEN)); + if (ret < 0) { + T_SMLOG_D("_i2c_read() ret : %X", ret); + ret = -1; + } + else { + ret = (total_count + (nNbBytesToRead + PH_PROTO_7816_CRC_LEN)); + } + } + else { + ret = -1; + } +exit: + return ret; +} +/****************************************************************************** + * Function phNxpEse_WriteFrame + * + * Description This function writes the data to ESE. + * It waits till write callback provide the result of write + * process. + * + * param[in] void*: connection context + * param[in] uint32_t: number of bytes to be written + * param[in] uint8_t : data buffer + * + * Returns It returns ESESTATUS_SUCCESS (0) if write successful else + * ESESTATUS_FAILED(1) + * + ******************************************************************************/ +ESESTATUS phNxpEse_WriteFrame(void *conn_ctx, uint32_t data_len, const uint8_t *p_data) +{ + ESESTATUS status = ESESTATUS_INVALID_PARAMETER; + int32_t dwNoBytesWrRd = 0; + phNxpEse_Context_t *nxpese_ctxt = (conn_ctx == NULL) ? &gnxpese_ctxt : (phNxpEse_Context_t *)conn_ctx; + + /* Create local copy of cmd_data */ + T_SMLOG_D("%s Enter ..", __FUNCTION__); + + if (data_len > MAX_APDU_BUFFER) { + return ESESTATUS_FAILED; + } + + //phNxpEse_memcpy(nxpese_ctxt->p_cmd_data, p_data, data_len); + //nxpese_ctxt->cmd_len = data_len; + + if (nxpese_ctxt->EseLibStatus != ESE_STATUS_CLOSE) { + dwNoBytesWrRd = phPalEse_i2c_write(nxpese_ctxt->pDevHandle, + /*nxpese_ctxt->p_cmd_data*/ (uint8_t *)p_data, + /*nxpese_ctxt->cmd_len*/ data_len); + if (-1 == dwNoBytesWrRd) { + T_SMLOG_E(" - Error in I2C Write....."); + status = ESESTATUS_FAILED; + } + else if (-2 == dwNoBytesWrRd) { + status = ESESTATUS_INVALID_STATE; + } + else { + status = ESESTATUS_SUCCESS; + //T_SMLOG_MAU8_D("RAW Tx>", nxpese_ctxt->p_cmd_data, nxpese_ctxt->cmd_len); + T_SMLOG_MAU8_D("RAW Tx>", p_data, data_len); + } + } + else + status = ESESTATUS_INVALID_STATE; + return status; +} + +/****************************************************************************** + * Function phNxpEse_setIfsc + * + * Description This function sets the IFSC size to 240/254 support JCOP OS Update. + * + * param[in] uint16_t IFSC_Size + * + * Returns Always return ESESTATUS_SUCCESS (0). + * + ******************************************************************************/ +ESESTATUS phNxpEse_setIfsc(uint16_t IFSC_Size) +{ + /*SET the IFSC size to 240 bytes*/ + phNxpEseProto7816_SetIfscSize(IFSC_Size); + return ESESTATUS_SUCCESS; +} + +/****************************************************************************** + * Function phNxpEse_memset + * + * Description This function updates destination buffer with val + * data in len size + * + * param[in] buff - Array to be udpated + * param[in] val - value to be updated + * param[in] len - length of array to be updated + * + * Returns Always return ESESTATUS_SUCCESS (0). + * + ******************************************************************************/ +void *phNxpEse_memset(void *buff, int val, size_t len) +{ + return memset(buff, val, len); +} + +/****************************************************************************** + * Function phNxpEse_memcpy + * + * Description This function copies source buffer to destination buffer + * data in len size + * + * param[in] dest - Destination array to be updated + * param[in] src - Source array to be updated + * param[in] len - length of array to be updated + * + * Returns Return pointer to allocated memory location. + * + ******************************************************************************/ +void *phNxpEse_memcpy(void *dest, const void *src, size_t len) +{ + return memcpy(dest, src, len); +} + +/****************************************************************************** + * Function phNxpEse_Memalloc + * + * Description This function allocation memory + * + * param[in] uint32_t size + * + * Returns Return pointer to allocated memory or NULL. + * + ******************************************************************************/ +void *phNxpEse_memalloc(uint32_t size) +{ + return sm_malloc(size); +} + +/****************************************************************************** + * Function phNxpEse_free + * + * Description This function de-allocation memory + * + * param[in] ptr - Address pointer to previous allocation + * + * Returns void. + * + ******************************************************************************/ +void phNxpEse_free(void *ptr) +{ + ENSURE_OR_GO_EXIT(ptr != NULL); + sm_free(ptr); +exit: + return; +} + +#if defined(T1oI2C_UM11225) +/****************************************************************************** + * Function phNxpEse_getAtr + * + * Description This function get ATR from ESE. + * + * param[out] phNxpEse_data: Response from ESE + * + * Returns On Success ESESTATUS_SUCCESS else ESESTATUS_FAILED. + * + ******************************************************************************/ +ESESTATUS phNxpEse_getAtr(void *conn_ctx, phNxpEse_data *pRsp) +{ + bool_t status = FALSE; + status = phNxpEseProto7816_GetAtr(conn_ctx, pRsp); + if (status == FALSE) { + T_SMLOG_E("%s Get ATR Failed ", __FUNCTION__); + return ESESTATUS_FAILED; + } + return ESESTATUS_SUCCESS; +} +#endif + +#if defined(T1oI2C_GP1_0) +/****************************************************************************** + * Function phNxpEse_getCip + * + * Description This function get CIP from ESE. + * + * param[out] phNxpEse_data: Response from ESE + * + * Returns On Success ESESTATUS_SUCCESS else ESESTATUS_FAILED. + * + ******************************************************************************/ +ESESTATUS phNxpEse_getCip(void *conn_ctx, phNxpEse_data *pRsp) +{ + bool_t status = FALSE; + status = phNxpEseProto7816_GetCip(conn_ctx, pRsp); + if (status == FALSE) { + T_SMLOG_E("%s Get CIP Failed ", __FUNCTION__); + return ESESTATUS_FAILED; + } + return ESESTATUS_SUCCESS; +} +#endif + +/****************************************************************************** + * Function phNxpEse_deepPwrDown + * + * Description This function is used to send deep power down command + * + * param[out] + * + * Returns On Success ESESTATUS_SUCCESS else ESESTATUS_FAILED. + * + ******************************************************************************/ +ESESTATUS phNxpEse_deepPwrDown(void *conn_ctx) +{ + bool_t status = FALSE; + status = phNxpEseProto7816_Deep_Pwr_Down(conn_ctx); + if (status == FALSE) { + T_SMLOG_E("%s Deep Pwr Down Failed ", __FUNCTION__); + return ESESTATUS_FAILED; + } + return ESESTATUS_SUCCESS; +} diff --git a/src/lib/t1oi2c/phNxpEse_Api.h b/src/lib/t1oi2c/phNxpEse_Api.h new file mode 100644 index 0000000..e4f8be1 --- /dev/null +++ b/src/lib/t1oi2c/phNxpEse_Api.h @@ -0,0 +1,72 @@ +/* + * Copyright 2024 NXP + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * + * \brief ESE Lib layer interface to application + * @{ */ + +#ifndef _PHNXPESE_API_H_ +#define _PHNXPESE_API_H_ + +#include "lib/t1oi2c/phEseStatus.h" + +typedef enum +{ + ESE_MODE_NORMAL = 0, /*!< All wired transaction other OSU */ + ESE_MODE_OSU, /*!< Jcop Os update mode */ + ESE_MODE_RESUME /*!< Session Resume mode */ +} phNxpEse_initMode; + +/** + * + * \brief Ese data buffer + * + */ +typedef struct phNxpEse_data +{ + uint32_t len; /*!< length of the buffer */ + uint8_t *p_data; /*!< pointer to a buffer */ +} phNxpEse_data; + +/** + * + * \brief Ese library init parameters to be set while calling phNxpEse_init + * + */ +typedef struct phNxpEse_initParams +{ + phNxpEse_initMode initMode; /*!< Ese communication mode */ +} phNxpEse_initParams; + +ESESTATUS phNxpEse_init(void *conn_ctx, phNxpEse_initParams initParams, phNxpEse_data *AtrRsp); +ESESTATUS phNxpEse_open(void **conn_ctx, phNxpEse_initParams initParams, const char *pConnString); +ESESTATUS phNxpEse_Transceive(void *conn_ctx, phNxpEse_data *pCmd, phNxpEse_data *pRsp); +ESESTATUS phNxpEse_deInit(void *conn_ctx); +ESESTATUS phNxpEse_close(void *conn_ctx); +ESESTATUS phNxpEse_reset(void *conn_ctx); +ESESTATUS phNxpEse_chipReset(void *conn_ctx); +ESESTATUS phNxpEse_setIfsc(uint16_t IFSC_Size); +ESESTATUS phNxpEse_EndOfApdu(void *conn_ctx); +void *phNxpEse_memset(void *buff, int val, size_t len); +void *phNxpEse_memcpy(void *dest, const void *src, size_t len); +void *phNxpEse_memalloc(uint32_t size); +void phNxpEse_free(void *ptr); +ESESTATUS phNxpEse_getAtr(void *conn_ctx, phNxpEse_data *pRsp); +ESESTATUS phNxpEse_getCip(void *conn_ctx, phNxpEse_data *pRsp); +ESESTATUS phNxpEse_deepPwrDown(void *conn_ctx); +/** @} */ +#endif /* _PHNXPESE_API_H_ */ diff --git a/src/lib/t1oi2c/phNxpEse_Internal.h b/src/lib/t1oi2c/phNxpEse_Internal.h new file mode 100644 index 0000000..ce03c49 --- /dev/null +++ b/src/lib/t1oi2c/phNxpEse_Internal.h @@ -0,0 +1,56 @@ +/* + * Copyright 2024 NXP + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef _PHNXPESE_INTERNAL_H_ +#define _PHNXPESE_INTERNAL_H_ + +#include +#include +#include "lib/platform/arduino/sm_i2c.h" + +#ifdef T1oI2C_UM1225_SE050 +/* MW version 02.13.00 onwards */ +#error Do not define T1oI2C_UM1225_SE050, define T1oI2C_UM11225 instead. +#endif + +/********************* Definitions and structures *****************************/ + +typedef enum +{ + ESE_STATUS_CLOSE = 0x00, + ESE_STATUS_BUSY, + ESE_STATUS_RECOVERY, + ESE_STATUS_IDLE, + ESE_STATUS_OPEN, +} phNxpEse_LibStatus; + +/* I2C Control structure */ +typedef struct phNxpEse_Context +{ + phNxpEse_LibStatus EseLibStatus; /* Indicate if Ese Lib is open or closed */ + void *pDevHandle; + + uint8_t p_read_buff[MAX_APDU_BUFFER]; + //uint16_t cmd_len; + //uint8_t p_cmd_data[MAX_APDU_BUFFER]; + phNxpEse_initParams initParams; +} phNxpEse_Context_t; + +ESESTATUS phNxpEse_WriteFrame(void *conn_ctx, uint32_t data_len, const uint8_t *p_data); +ESESTATUS phNxpEse_read(void *conn_ctx, uint32_t *data_len, uint8_t **pp_data); +void phNxpEse_clearReadBuffer(void *conn_ctx); +void phNxpEse_waitForWTX(void *conn_ctx); + +#endif /* _PHNXPESE_INTERNAL_H_ */ From 9cc1c8360cc41871bdc49bd19180876441a300f6 Mon Sep 17 00:00:00 2001 From: Andrea Gilardoni Date: Mon, 30 Mar 2026 16:10:49 +0200 Subject: [PATCH 3/8] Adding additional SE05X apis Including some apis for se05X, that are missing from nxp plugandtrust nano-package, but being used in SE05X library in arduinoCore-renesas --- src/lib/apdu/se05x_APDU_apis.h | 509 +++++++++++++++++++++++++++++++++ src/lib/apdu/se05x_APDU_impl.c | 370 ++++++++++++++++++++++++ src/lib/apdu/se05x_tlv.h | 3 + src/lib/apdu/se05x_types.h | 132 ++++++++- 4 files changed, 1010 insertions(+), 4 deletions(-) diff --git a/src/lib/apdu/se05x_APDU_apis.h b/src/lib/apdu/se05x_APDU_apis.h index edc4a9b..cdfa62b 100644 --- a/src/lib/apdu/se05x_APDU_apis.h +++ b/src/lib/apdu/se05x_APDU_apis.h @@ -820,6 +820,488 @@ smStatus_t Se05x_API_WriteSymmKey(pSe05xSession_t session_ctx, */ smStatus_t Se05x_API_DeleteSecureObject(pSe05xSession_t session_ctx, uint32_t objectID); +/** Se05x_API_GetRandom + * + * Gets random data from the SE05X . + * + * + * # Command to Applet + * + * @rst + * +-------+------------+-----------------------------+ + * | Field | Value | Description | + * +=======+============+=============================+ + * | CLA | 0x80 | | + * +-------+------------+-----------------------------+ + * | INS | INS_MGMT | See :cpp:type:`SE05x_INS_t` | + * +-------+------------+-----------------------------+ + * | P1 | P1_DEFAULT | See :cpp:type:`SE05x_P1_t` | + * +-------+------------+-----------------------------+ + * | P2 | P2_RANDOM | See :cpp:type:`SE05x_P2_t` | + * +-------+------------+-----------------------------+ + * | Lc | #(Payload) | | + * +-------+------------+-----------------------------+ + * | | TLV[TAG_1] | 2-byte requested size. | + * +-------+------------+-----------------------------+ + * | Le | 0x00 | Expecting random data | + * +-------+------------+-----------------------------+ + * @endrst + * + * # R-APDU Body + * + * @rst + * +------------+--------------+ + * | Value | Description | + * +============+==============+ + * | TLV[TAG_1] | Random data. | + * +------------+--------------+ + * @endrst + * + * # R-APDU Trailer + * + * @rst + * +-------------+--------------------------------+ + * | SW | Description | + * +=============+================================+ + * | SW_NO_ERROR | Data is returned successfully. | + * +-------------+--------------------------------+ + * @endrst + * + * + * + * @param[in] session_ctx The session context + * @param[in] size The size + * @param randomData The random data + * @param prandomDataLen The prandom data length + * + * @return The sm status. + */ +smStatus_t Se05x_API_GetRandom(pSe05xSession_t session_ctx, uint16_t size, uint8_t *randomData, size_t *prandomDataLen); + +/** Se05x_API_DigestInit + * + * Open a digest operation. The state of the digest operation is kept in the + * Crypto Object until the Crypto Object is finalized or deleted. + * + * + * # Command to Applet + * + * @rst + * +-------+------------+---------------------------------+ + * | Field | Value | Description | + * +=======+============+=================================+ + * | CLA | 0x80 | | + * +-------+------------+---------------------------------+ + * | INS | INS_CRYPTO | See :cpp:type:`SE05x_INS_t` | + * +-------+------------+---------------------------------+ + * | P1 | P1_DEFAULT | See :cpp:type:`SE05x_P1_t` | + * +-------+------------+---------------------------------+ + * | P2 | P2_INIT | See :cpp:type:`SE05x_P2_t` | + * +-------+------------+---------------------------------+ + * | Lc | #(Payload) | | + * +-------+------------+---------------------------------+ + * | | TLV[TAG_2] | 2-byte Crypto Object identifier | + * +-------+------------+---------------------------------+ + * @endrst + * + * # R-APDU Body + * + * NA + * + * # R-APDU Trailer + * + * @rst + * +-------------+--------------------------------------+ + * | SW | Description | + * +=============+======================================+ + * | SW_NO_ERROR | The command is handled successfully. | + * +-------------+--------------------------------------+ + * @endrst + * + * + * + * @param[in] session_ctx Session Context [0:kSE05x_pSession] + * @param[in] cryptoObjectID cryptoObjectID [1:kSE05x_TAG_2] + */ +smStatus_t Se05x_API_DigestInit(pSe05xSession_t session_ctx, SE05x_CryptoObjectID_t cryptoObjectID); + +/** Se05x_API_DigestUpdate + * + * + * # Command to Applet + * + * @rst + * +-------+------------+---------------------------------+ + * | Field | Value | Description | + * +=======+============+=================================+ + * | CLA | 0x80 | | + * +-------+------------+---------------------------------+ + * | INS | INS_CRYPTO | See :cpp:type:`SE05x_INS_t` | + * +-------+------------+---------------------------------+ + * | P1 | P1_DEFAULT | See :cpp:type:`SE05x_P1_t` | + * +-------+------------+---------------------------------+ + * | P2 | P2_UPDATE | See :cpp:type:`SE05x_P2_t` | + * +-------+------------+---------------------------------+ + * | Lc | #(Payload) | | + * +-------+------------+---------------------------------+ + * | | TLV[TAG_2] | 2-byte Crypto Object identifier | + * +-------+------------+---------------------------------+ + * | | TLV[TAG_3] | Data to be hashed. | + * +-------+------------+---------------------------------+ + * | Le | | | + * +-------+------------+---------------------------------+ + * @endrst + * + * # R-APDU Body + * + * NA + * + * # R-APDU Trailer + * + * @rst + * +-------------+--------------------------------------+ + * | SW | Description | + * +=============+======================================+ + * | SW_NO_ERROR | The command is handled successfully. | + * +-------------+--------------------------------------+ + * @endrst + * + * + * + * @param[in] session_ctx Session Context [0:kSE05x_pSession] + * @param[in] cryptoObjectID cryptoObjectID [1:kSE05x_TAG_2] + * @param[in] inputData inputData [2:kSE05x_TAG_3] + * @param[in] inputDataLen Length of inputData + */ +smStatus_t Se05x_API_DigestUpdate( + pSe05xSession_t session_ctx, SE05x_CryptoObjectID_t cryptoObjectID, const uint8_t *inputData, size_t inputDataLen); + +/** Se05x_API_DigestFinal + * + * + * # Command to Applet + * + * @rst + * +-------+------------+------------------------------------+ + * | Field | Value | Description | + * +=======+============+====================================+ + * | CLA | 0x80 | | + * +-------+------------+------------------------------------+ + * | INS | INS_CRYPTO | See :cpp:type:`SE05x_INS_t` | + * +-------+------------+------------------------------------+ + * | P1 | P1_DEFAULT | See :cpp:type:`SE05x_P1_t` | + * +-------+------------+------------------------------------+ + * | P2 | P2_FINAL | See :cpp:type:`SE05x_P2_t` | + * +-------+------------+------------------------------------+ + * | Lc | #(Payload) | | + * +-------+------------+------------------------------------+ + * | | TLV[TAG_2] | 2-byte Crypto Object identifier | + * +-------+------------+------------------------------------+ + * | | TLV[TAG_3] | Data to be encrypted or decrypted. | + * +-------+------------+------------------------------------+ + * | Le | 0x00 | Expecting TLV with hash value. | + * +-------+------------+------------------------------------+ + * @endrst + * + * # R-APDU Body + * + * @rst + * +------------+-------------+ + * | Value | Description | + * +============+=============+ + * | TLV[TAG_1] | CMAC value | + * +------------+-------------+ + * @endrst + * + * # R-APDU Trailer + * + * @rst + * +-------------+-----------------------------------+ + * | SW | Description | + * +=============+===================================+ + * | SW_NO_ERROR | The hash is created successfully. | + * +-------------+-----------------------------------+ + * @endrst + * + * + * + * @param[in] session_ctx Session Context [0:kSE05x_pSession] + * @param[in] cryptoObjectID cryptoObjectID [1:kSE05x_TAG_2] + * @param[in] inputData inputData [2:kSE05x_TAG_3] + * @param[in] inputDataLen Length of inputData + * @param[out] cmacValue [0:kSE05x_TAG_1] + * @param[in,out] pcmacValueLen Length for cmacValue + */ +smStatus_t Se05x_API_DigestFinal(pSe05xSession_t session_ctx, + SE05x_CryptoObjectID_t cryptoObjectID, + const uint8_t *inputData, + size_t inputDataLen, + uint8_t *cmacValue, + size_t *pcmacValueLen); + +/** Se05x_API_DigestOneShot + * + * Performs a hash operation in one shot (without context). + * + * + * # Command to Applet + * + * @rst + * +-------+------------+-------------------------------------------+ + * | Field | Value | Description | + * +=======+============+===========================================+ + * | CLA | 0x80 | | + * +-------+------------+-------------------------------------------+ + * | INS | INS_CRYPTO | See :cpp:type:`SE05x_INS_t` | + * +-------+------------+-------------------------------------------+ + * | P1 | P1_DEFAULT | See :cpp:type:`SE05x_P1_t` | + * +-------+------------+-------------------------------------------+ + * | P2 | P2_ONESHOT | See :cpp:type:`SE05x_P2_t` | + * +-------+------------+-------------------------------------------+ + * | Lc | #(Payload) | | + * +-------+------------+-------------------------------------------+ + * | | TLV[TAG_1] | 1-byte DigestMode (except DIGEST_NO_HASH) | + * +-------+------------+-------------------------------------------+ + * | | TLV[TAG_2] | Data to hash. | + * +-------+------------+-------------------------------------------+ + * | Le | 0x00 | TLV expecting hash value | + * +-------+------------+-------------------------------------------+ + * @endrst + * + * # R-APDU Body + * + * @rst + * +------------+-------------+ + * | Value | Description | + * +============+=============+ + * | TLV[TAG_1] | Hash value. | + * +------------+-------------+ + * @endrst + * + * # R-APDU Trailer + * + * @rst + * +-------------+-----------------------------------+ + * | SW | Description | + * +=============+===================================+ + * | SW_NO_ERROR | The hash is created successfully. | + * +-------------+-----------------------------------+ + * @endrst + * + * + * + * @param[in] session_ctx Session Context [0:kSE05x_pSession] + * @param[in] digestMode digestMode [1:kSE05x_TAG_1] + * @param[in] inputData inputData [2:kSE05x_TAG_2] + * @param[in] inputDataLen Length of inputData + * @param[out] hashValue [0:kSE05x_TAG_1] + * @param[in,out] phashValueLen Length for hashValue + */ +smStatus_t Se05x_API_DigestOneShot(pSe05xSession_t session_ctx, + uint8_t digestMode, + const uint8_t *inputData, + size_t inputDataLen, + uint8_t *hashValue, + size_t *phashValueLen); + + +/** Se05x_API_MACOneShot_G + * + * Generate. See @ref Se05x_API_MACOneShot_V for Verfiication. + * + * Performs a MAC operation in one shot (without keeping state). + * + * The 4-byte identifier of the key must refer to an AESKey, DESKey or HMACKey. + * + * # Command to Applet + * + * @rst + * +---------+------------------------+---------------------------------------------+ + * | Field | Value | Description | + * +=========+========================+=============================================+ + * | CLA | 0x80 | | + * +---------+------------------------+---------------------------------------------+ + * | INS | INS_CRYPTO | :cpp:type:`SE05x_INS_t` | + * +---------+------------------------+---------------------------------------------+ + * | P1 | P1_MAC | See :cpp:type:`SE05x_P1_t` | + * +---------+------------------------+---------------------------------------------+ + * | P2 | P2_GENERATE_ONESHOT or | See :cpp:type:`SE05x_P2_t` | + * | | P2_VALIDATE_ONESHOT | | + * +---------+------------------------+---------------------------------------------+ + * | Lc | #(Payload) | | + * +---------+------------------------+---------------------------------------------+ + * | Payload | TLV[TAG_1] | 4-byte identifier of the key object. | + * +---------+------------------------+---------------------------------------------+ + * | | TLV[TAG_2] | 1-byte :cpp:type:`MACAlgoRef` | + * +---------+------------------------+---------------------------------------------+ + * | | TLV[TAG_3] | Byte array containing data to be taken as | + * | | | input to MAC. | + * +---------+------------------------+---------------------------------------------+ + * | | TLV[TAG_5] | MAC to verify (when P2=P2_VALIDATE_ONESHOT) | + * +---------+------------------------+---------------------------------------------+ + * | Le | 0x00 | Expecting MAC or Result. | + * +---------+------------------------+---------------------------------------------+ + * @endrst + * + * # R-APDU Body + * + * @rst + * +------------+---------------------------------------+ + * | Value | Description | + * +============+=======================================+ + * | TLV[TAG_1] | MAC value (P2=P2_GENERATE_ONESHOT) or | + * | | :cpp:type:`SE05x_Result_t` (when | + * | | p2=P2_VALIDATE_ONESHOT). | + * +------------+---------------------------------------+ + * @endrst + * + * # R-APDU Trailer + * + * @rst + * +-------------+--------------------------------------+ + * | SW | Description | + * +=============+======================================+ + * | SW_NO_ERROR | The command is handled successfully. | + * +-------------+--------------------------------------+ + * @endrst + * + * @param[in] session_ctx Session Context [0:kSE05x_pSession] + * @param[in] objectID objectID [1:kSE05x_TAG_1] + * @param[in] macOperation macOperation [2:kSE05x_TAG_2] + * @param[in] inputData inputData [3:kSE05x_TAG_3] + * @param[in] inputDataLen Length of inputData + * @param[out] macValue [0:kSE05x_TAG_1] + * @param[in,out] pmacValueLen Length for macValue + */ +smStatus_t Se05x_API_MACOneShot_G(pSe05xSession_t session_ctx, + uint32_t objectID, + uint8_t macOperation, + const uint8_t *inputData, + size_t inputDataLen, + uint8_t *macValue, + size_t *pmacValueLen); + + +/** Se05x_API_CreateCryptoObject + * + * Creates a Crypto Object on the SE05X . Once the Crypto Object is created, it + * is bound to the user who created the Crypto Object. + * + * A CryptoObject is a 2-byte value consisting of a CryptoContext in MSB and one + * of the following in LSB: + * + * * DigestMode in case CryptoContext = CC_DIGEST + * + * * CipherMode in case CryptoContext = CC_CIPHER + * + * * MACAlgo in case CryptoContext = CC_SIGNATURE + * + * * AEADMode in case CryptoContext = CC_AEAD + * + * # Command to Applet + * + * @rst + * +---------+---------------+-------------------------------------------+ + * | Field | Value | Description | + * +=========+===============+===========================================+ + * | CLA | 0x80 | | + * +---------+---------------+-------------------------------------------+ + * | INS | INS_WRITE | See :cpp:type:`SE05x_INS_t` | + * +---------+---------------+-------------------------------------------+ + * | P1 | P1_CRYPTO_OBJ | See :cpp:type:`SE05x_P1_t` | + * +---------+---------------+-------------------------------------------+ + * | P2 | P2_DEFAULT | See :cpp:type:`SE05x_P2_t` | + * +---------+---------------+-------------------------------------------+ + * | Lc | #(Payload) | Payload length | + * +---------+---------------+-------------------------------------------+ + * | Payload | TLV[TAG_1] | 2-byte Crypto Object identifier | + * +---------+---------------+-------------------------------------------+ + * | | TLV[TAG_2] | 1-byte :cpp:type:`SE05x_CryptoObject_t` | + * +---------+---------------+-------------------------------------------+ + * | | TLV[TAG_3] | 1-byte Crypto Object subtype, either from | + * | | | :cpp:type:`DigestModeRef`, CipherMode, | + * | | | MACAlgo (depending on TAG_2) or AEADMode. | + * +---------+---------------+-------------------------------------------+ + * @endrst + * + * # R-APDU Body + * + * NA + * + * # R-APDU Trailer + * + * @rst + * +-------------+----------------------------------------------+ + * | SW | Description | + * +=============+==============================================+ + * | SW_NO_ERROR | The file is created or updated successfully. | + * +-------------+----------------------------------------------+ + * @endrst + * + * + * + * @param[in] session_ctx Session Context [0:kSE05x_pSession] + * @param[in] cryptoObjectID cryptoObjectID [1:kSE05x_TAG_1] + * @param[in] cryptoContext cryptoContext [2:kSE05x_TAG_2] + * + * @param[in] subtype 1-byte Crypto Object subtype, either from + * DigestMode, CipherMode or MACAlgo (depending on + * TAG_2). [3:kSE05x_TAG_3] + */ +smStatus_t Se05x_API_CreateCryptoObject(pSe05xSession_t session_ctx, + SE05x_CryptoObjectID_t cryptoObjectID, + SE05x_CryptoContext_t cryptoContext, + SE05x_CryptoModeSubType_t subtype); + +/** Se05x_API_DeleteCryptoObject + * + * Deletes a Crypto Object on the SE05X . + * + * Note: when a Crypto Object is deleted, the memory (as mentioned in ) is de- + * allocated, but the transient memory is only freed when de-selecting the + * applet! + * + * # Command to Applet + * + * @rst + * +---------+------------------+---------------------------------+ + * | Field | Value | Description | + * +=========+==================+=================================+ + * | CLA | 0x80 | | + * +---------+------------------+---------------------------------+ + * | INS | INS_MGMT | See :cpp:type:`SE05x_INS_t` | + * +---------+------------------+---------------------------------+ + * | P1 | P1_CRYPTO_OBJ | See :cpp:type:`SE05x_P1_t` | + * +---------+------------------+---------------------------------+ + * | P2 | P2_DELETE_OBJECT | See :cpp:type:`SE05x_P2_t` | + * +---------+------------------+---------------------------------+ + * | Lc | #(Payload) | Payload length | + * +---------+------------------+---------------------------------+ + * | Payload | TLV[TAG_1] | 2-byte Crypto Object identifier | + * +---------+------------------+---------------------------------+ + * @endrst + * + * # R-APDU Body + * + * NA + * + * # R-APDU Trailer + * + * @rst + * +-------------+----------------------------------------------+ + * | SW | Description | + * +=============+==============================================+ + * | SW_NO_ERROR | The file is created or updated successfully. | + * +-------------+----------------------------------------------+ + * @endrst + * + * + * + * @param[in] session_ctx Session Context [0:kSE05x_pSession] + * @param[in] cryptoObjectID cryptoObjectID [1:kSE05x_TAG_1] + */ +smStatus_t Se05x_API_DeleteCryptoObject(pSe05xSession_t session_ctx, SE05x_CryptoObjectID_t cryptoObjectID); + /** Se05x_API_CreateSession * * Creates a session on SE05X . @@ -951,6 +1433,33 @@ smStatus_t Se05x_API_ReadIDList(pSe05xSession_t session_ctx, uint8_t *idlist, size_t *pidlistLen); + /** Se05x_API_DeleteAll_Iterative + * + * Go through each object and delete it individually. + * + * This API does not use the Applet API @ref Se05x_API_DeleteAll. It + * does not delete ALL objects and purposefully skips few objects. + * + * Instead, this API uses @ref Se05x_API_ReadIDList and @ref + * Se05x_API_ReadCryptoObjectList to first fetch list of objects to host, and + * **selectitvely** deletes. + * + * For e.g. It does not kill objects from: + * - The range SE05X_OBJID_SE05X_APPLET_RES_START to + * SE05X_OBJID_SE05X_APPLET_RES_END. This range is used by applet. + * - The range EX_SSS_OBJID_DEMO_AUTH_START to EX_SSS_OBJID_DEMO_AUTH_END, + * which is used by middleware DEMOS for authentication. + * - And others. + * + * Kindly see the Implementation of is API Se05x_API_DeleteAll_Iterative to see + * the list of ranges that are skipped. + * + * @param[in] session_ctx Session Context + * + * @return The status of API. + */ +smStatus_t Se05x_API_DeleteAll_Iterative(pSe05xSession_t session_ctx); + /** Se05x_API_ReadSize * * ReadSize diff --git a/src/lib/apdu/se05x_APDU_impl.c b/src/lib/apdu/se05x_APDU_impl.c index 8e5b026..65cb6ef 100644 --- a/src/lib/apdu/se05x_APDU_impl.c +++ b/src/lib/apdu/se05x_APDU_impl.c @@ -729,6 +729,318 @@ smStatus_t Se05x_API_DeleteSecureObject(pSe05xSession_t session_ctx, uint32_t ob return retStatus; } +/* API added from PlugNTrust full library*/ + +smStatus_t Se05x_API_GetRandom(pSe05xSession_t session_ctx, uint16_t size, uint8_t *randomData, size_t *prandomDataLen) +{ + smStatus_t retStatus = SM_NOT_OK; + tlvHeader_t hdr = {{kSE05x_CLA, kSE05x_INS_MGMT, kSE05x_P1_DEFAULT, kSE05x_P2_RANDOM}}; + size_t cmdbufLen = 0; + uint8_t *pCmdbuf = NULL; + int tlvRet = 0; + uint8_t *pRspbuf = NULL; + size_t rspbufLen = 0; + + ENSURE_OR_GO_CLEANUP(session_ctx != NULL); + + SMLOG_D("APDU - Se05x_API_GetRandom [] \n"); + + pCmdbuf = &session_ctx->apdu_buffer[0]; + pRspbuf = &session_ctx->apdu_buffer[0]; + rspbufLen = sizeof(session_ctx->apdu_buffer); + + tlvRet = TLVSET_U16("size", &pCmdbuf, &cmdbufLen, kSE05x_TAG_1, size); + if (0 != tlvRet) { + goto cleanup; + } + retStatus = DoAPDUTxRx(session_ctx, &hdr, session_ctx->apdu_buffer, cmdbufLen, pRspbuf, &rspbufLen, 0); + if (retStatus == SM_OK) { + retStatus = SM_NOT_OK; + size_t rspIndex = 0; + tlvRet = tlvGet_u8buf(pRspbuf, &rspIndex, rspbufLen, kSE05x_TAG_1, randomData, prandomDataLen); /* */ + if (0 != tlvRet) { + goto cleanup; + } + if ((rspIndex + 2) == rspbufLen) { + retStatus = (smStatus_t)((pRspbuf[rspIndex] << 8) | (pRspbuf[rspIndex + 1])); + } + } + +cleanup: + return retStatus; +} + + +smStatus_t Se05x_API_DigestInit(pSe05xSession_t session_ctx, SE05x_CryptoObjectID_t cryptoObjectID) +{ + smStatus_t retStatus = SM_NOT_OK; + tlvHeader_t hdr = {{kSE05x_CLA, kSE05x_INS_CRYPTO, kSE05x_P1_DEFAULT, kSE05x_P2_INIT}}; + size_t cmdbufLen = 0; + uint8_t *pCmdbuf = NULL; + int tlvRet = 0; + + ENSURE_OR_GO_CLEANUP(session_ctx != NULL); + + SMLOG_D("APDU - Se05x_API_DigestInit [] \n"); + + pCmdbuf = &session_ctx->apdu_buffer[0]; + + tlvRet = TLVSET_U16("cryptoObjectID", &pCmdbuf, &cmdbufLen, kSE05x_TAG_2, cryptoObjectID); + if (0 != tlvRet) { + goto cleanup; + } + retStatus = DoAPDUTx(session_ctx, &hdr, session_ctx->apdu_buffer, cmdbufLen, 0); + +cleanup: + return retStatus; +} + +smStatus_t Se05x_API_DigestUpdate( + pSe05xSession_t session_ctx, SE05x_CryptoObjectID_t cryptoObjectID, const uint8_t *inputData, size_t inputDataLen) +{ + smStatus_t retStatus = SM_NOT_OK; + tlvHeader_t hdr = {{kSE05x_CLA, kSE05x_INS_CRYPTO, kSE05x_P1_DEFAULT, kSE05x_P2_UPDATE}}; + size_t cmdbufLen = 0; + uint8_t *pCmdbuf = NULL; + int tlvRet = 0; + + ENSURE_OR_GO_CLEANUP(session_ctx != NULL); + + SMLOG_D("APDU - Se05x_API_DigestUpdate [] \n"); + + pCmdbuf = &session_ctx->apdu_buffer[0]; + + tlvRet = TLVSET_U16("cryptoObjectID", &pCmdbuf, &cmdbufLen, kSE05x_TAG_2, cryptoObjectID); + if (0 != tlvRet) { + SMLOG_D("cryptoObjectID err \n"); + goto cleanup; + } + tlvRet = TLVSET_u8bufOptional("inputData", &pCmdbuf, &cmdbufLen, kSE05x_TAG_3, inputData, inputDataLen); + if (0 != tlvRet) { + goto cleanup; + } + retStatus = DoAPDUTx(session_ctx, &hdr, session_ctx->apdu_buffer, cmdbufLen, 0); + +cleanup: + return retStatus; +} + +smStatus_t Se05x_API_DigestFinal(pSe05xSession_t session_ctx, + SE05x_CryptoObjectID_t cryptoObjectID, + const uint8_t *inputData, + size_t inputDataLen, + uint8_t *cmacValue, + size_t *pcmacValueLen) +{ + smStatus_t retStatus = SM_NOT_OK; + tlvHeader_t hdr = {{kSE05x_CLA, kSE05x_INS_CRYPTO, kSE05x_P1_DEFAULT, kSE05x_P2_FINAL}}; + size_t cmdbufLen = 0; + uint8_t *pCmdbuf = NULL; + int tlvRet = 0; + uint8_t *pRspbuf = NULL; + size_t rspbufLen = 0; + + ENSURE_OR_GO_CLEANUP(session_ctx != NULL); + + SMLOG_D("APDU - Se05x_API_DigestFinal [] \n"); + + pCmdbuf = &session_ctx->apdu_buffer[0]; + pRspbuf = &session_ctx->apdu_buffer[0]; + rspbufLen = sizeof(session_ctx->apdu_buffer); + + tlvRet = TLVSET_U16("cryptoObjectID", &pCmdbuf, &cmdbufLen, kSE05x_TAG_2, cryptoObjectID); + if (0 != tlvRet) { + goto cleanup; + } + tlvRet = TLVSET_u8buf("inputData", &pCmdbuf, &cmdbufLen, kSE05x_TAG_3, inputData, inputDataLen); + if (0 != tlvRet) { + goto cleanup; + } + retStatus = DoAPDUTxRx(session_ctx, &hdr, session_ctx->apdu_buffer, cmdbufLen, pRspbuf, &rspbufLen, 0); + if (retStatus == SM_OK) { + retStatus = SM_NOT_OK; + size_t rspIndex = 0; + tlvRet = tlvGet_u8buf(pRspbuf, &rspIndex, rspbufLen, kSE05x_TAG_1, cmacValue, pcmacValueLen); /* */ + if (0 != tlvRet) { + goto cleanup; + } + if ((rspIndex + 2) == rspbufLen) { + retStatus = (smStatus_t)((pRspbuf[rspIndex] << 8) | (pRspbuf[rspIndex + 1])); + } + } + +cleanup: + return retStatus; +} + +smStatus_t Se05x_API_DigestOneShot(pSe05xSession_t session_ctx, + uint8_t digestMode, + const uint8_t *inputData, + size_t inputDataLen, + uint8_t *hashValue, + size_t *phashValueLen) +{ + smStatus_t retStatus = SM_NOT_OK; + tlvHeader_t hdr = {{kSE05x_CLA, kSE05x_INS_CRYPTO, kSE05x_P1_DEFAULT, kSE05x_P2_ONESHOT}}; + size_t cmdbufLen = 0; + uint8_t *pCmdbuf = NULL; + int tlvRet = 0; + uint8_t *pRspbuf = NULL; + size_t rspbufLen = 0; + + ENSURE_OR_GO_CLEANUP(session_ctx != NULL); + + SMLOG_D("APDU - Se05x_API_DigestOneShot [] \n"); + + pCmdbuf = &session_ctx->apdu_buffer[0]; + pRspbuf = &session_ctx->apdu_buffer[0]; + rspbufLen = sizeof(session_ctx->apdu_buffer); + + tlvRet = TLVSET_U8("digestMode", &pCmdbuf, &cmdbufLen, kSE05x_TAG_1, digestMode); + if (0 != tlvRet) { + goto cleanup; + } + tlvRet = TLVSET_u8bufOptional("inputData", &pCmdbuf, &cmdbufLen, kSE05x_TAG_2, inputData, inputDataLen); + if (0 != tlvRet) { + goto cleanup; + } + retStatus = DoAPDUTxRx(session_ctx, &hdr, session_ctx->apdu_buffer, cmdbufLen, pRspbuf, &rspbufLen, 0); + if (retStatus == SM_OK) { + retStatus = SM_NOT_OK; + size_t rspIndex = 0; + tlvRet = tlvGet_u8buf(pRspbuf, &rspIndex, rspbufLen, kSE05x_TAG_1, hashValue, phashValueLen); /* */ + if (0 != tlvRet) { + goto cleanup; + } + if ((rspIndex + 2) == rspbufLen) { + retStatus = (smStatus_t)((pRspbuf[rspIndex] << 8) | (pRspbuf[rspIndex + 1])); + } + } + +cleanup: + return retStatus; +} + + +smStatus_t Se05x_API_MACOneShot_G(pSe05xSession_t session_ctx, + uint32_t objectID, + uint8_t macOperation, + const uint8_t *inputData, + size_t inputDataLen, + uint8_t *macValue, + size_t *pmacValueLen) +{ + smStatus_t retStatus = SM_NOT_OK; + tlvHeader_t hdr = {{kSE05x_CLA, kSE05x_INS_CRYPTO, kSE05x_P1_MAC, kSE05x_P2_GENERATE_ONESHOT}}; + size_t cmdbufLen = 0; + uint8_t *pCmdbuf = NULL; + int tlvRet = 0; + uint8_t *pRspbuf = NULL; + size_t rspbufLen = 0; + + ENSURE_OR_GO_CLEANUP(session_ctx != NULL); + + SMLOG_D("APDU - Se05x_API_MACOneShot_G [] \n"); + + pCmdbuf = &session_ctx->apdu_buffer[0]; + pRspbuf = &session_ctx->apdu_buffer[0]; + rspbufLen = sizeof(session_ctx->apdu_buffer); + + tlvRet = TLVSET_U32("objectID", &pCmdbuf, &cmdbufLen, kSE05x_TAG_1, objectID); + if (0 != tlvRet) { + goto cleanup; + } + tlvRet = TLVSET_U8("macOperation", &pCmdbuf, &cmdbufLen, kSE05x_TAG_2, macOperation); + if (0 != tlvRet) { + goto cleanup; + } + tlvRet = TLVSET_u8bufOptional("inputData", &pCmdbuf, &cmdbufLen, kSE05x_TAG_3, inputData, inputDataLen); + if (0 != tlvRet) { + goto cleanup; + } + retStatus = DoAPDUTxRx(session_ctx, &hdr, session_ctx->apdu_buffer, cmdbufLen, pRspbuf, &rspbufLen, 0); + + if (retStatus == SM_OK) { + retStatus = SM_NOT_OK; + size_t rspIndex = 0; + tlvRet = tlvGet_u8buf(pRspbuf, &rspIndex, rspbufLen, kSE05x_TAG_1, macValue, pmacValueLen); + if (0 != tlvRet) { + goto cleanup; + } + if ((rspIndex + 2) == rspbufLen) { + retStatus = (smStatus_t)((pRspbuf[rspIndex] << 8) | (pRspbuf[rspIndex + 1])); + } + } + +cleanup: + return retStatus; +} + + +smStatus_t Se05x_API_CreateCryptoObject(pSe05xSession_t session_ctx, + SE05x_CryptoObjectID_t cryptoObjectID, + SE05x_CryptoContext_t cryptoContext, + SE05x_CryptoModeSubType_t subtype) +{ + smStatus_t retStatus = SM_NOT_OK; + tlvHeader_t hdr = {{kSE05x_CLA, kSE05x_INS_WRITE, kSE05x_P1_CRYPTO_OBJ, kSE05x_P2_DEFAULT}}; + size_t cmdbufLen = 0; + uint8_t *pCmdbuf = NULL; + int tlvRet = 0; + + ENSURE_OR_GO_CLEANUP(session_ctx != NULL); + + SMLOG_D("APDU - Se05x_API_CreateCryptoObject [] \n"); + + pCmdbuf = &session_ctx->apdu_buffer[0]; + + tlvRet = TLVSET_U16("cryptoObjectID", &pCmdbuf, &cmdbufLen, kSE05x_TAG_1, cryptoObjectID); + if (0 != tlvRet) { + goto cleanup; + } + tlvRet = TLVSET_U8("cryptoContext", &pCmdbuf, &cmdbufLen, kSE05x_TAG_2, cryptoContext); + if (0 != tlvRet) { + goto cleanup; + } + tlvRet = TLVSET_CryptoModeSubType( + "1-byte Crypto Object subtype, either from DigestMode, CipherMode or MACAlgo (depending on TAG_2).", + &pCmdbuf, + &cmdbufLen, + kSE05x_TAG_3, + subtype); + if (0 != tlvRet) { + goto cleanup; + } + retStatus = DoAPDUTx(session_ctx, &hdr, session_ctx->apdu_buffer, cmdbufLen, 0); + +cleanup: + return retStatus; +} + +smStatus_t Se05x_API_DeleteCryptoObject(pSe05xSession_t session_ctx, SE05x_CryptoObjectID_t cryptoObjectID) +{ + smStatus_t retStatus = SM_NOT_OK; + tlvHeader_t hdr = {{kSE05x_CLA, kSE05x_INS_MGMT, kSE05x_P1_CRYPTO_OBJ, kSE05x_P2_DELETE_OBJECT}}; + size_t cmdbufLen = 0; + uint8_t *pCmdbuf = NULL; + int tlvRet = 0; + + ENSURE_OR_GO_CLEANUP(session_ctx != NULL); + + SMLOG_D("APDU - Se05x_API_DeleteCryptoObject [] \n"); + + pCmdbuf = &session_ctx->apdu_buffer[0]; + + tlvRet = TLVSET_U16("cryptoObjectID", &pCmdbuf, &cmdbufLen, kSE05x_TAG_1, cryptoObjectID); + if (0 != tlvRet) { + goto cleanup; + } + retStatus = DoAPDUTx(session_ctx, &hdr, session_ctx->apdu_buffer, cmdbufLen, 0); + +cleanup: + return retStatus; +} + smStatus_t Se05x_API_CreateSession( pSe05xSession_t session_ctx, uint32_t authObjectID, uint8_t *sessionId, size_t *psessionIdLen) { @@ -1206,3 +1518,61 @@ smStatus_t Se05x_API_PBKDF2_extended(pSe05xSession_t session_ctx, cleanup: return retStatus; } + +smStatus_t Se05x_API_DeleteAll_Iterative(pSe05xSession_t session_ctx) +{ + uint8_t pmore = kSE05x_MoreIndicator_NA; + uint8_t list[1024]; + size_t listlen = sizeof(list); + size_t i; + smStatus_t retStatus = SM_NOT_OK; + uint16_t outputOffset = 0; + do { + retStatus = Se05x_API_ReadIDList(session_ctx, outputOffset, 0xFF, &pmore, list, &listlen); + if (retStatus != SM_OK) { + return retStatus; + } + outputOffset = (uint16_t)listlen; + for (i = 0; i < listlen; i += 4) { + uint32_t id = 0 | (list[i + 0] << (3 * 8)) | (list[i + 1] << (2 * 8)) | (list[i + 2] << (1 * 8)) | + (list[i + 3] << (0 * 8)); + if (SE05X_OBJID_SE05X_APPLET_RES_START == SE05X_OBJID_SE05X_APPLET_RES_MASK(id)) { + SMLOG_D("Not erasing ObjId=0x%08X (Reserved)", id); + /* In Reserved space */ + } + else if (EX_SSS_OBJID_DEMO_AUTH_START == EX_SSS_OBJID_DEMO_AUTH_MASK(id)) { + SMLOG_D("Not erasing ObjId=0x%08X (Demo Auth)", id); + /* Not reasing default authentication object */ + } + else if (EX_SSS_OBJID_IOT_HUB_A_START == EX_SSS_OBJID_IOT_HUB_A_MASK(id)) { + SMLOG_D("Not erasing ObjId=0x%08X (IoT Hub)", id); + /* Not reasing IoT Hub object */ + } + else if (!SE05X_OBJID_TP_MASK(id) && id) { + SMLOG_D("Not erasing Trust Provisioned objects"); + } + else { + retStatus = Se05x_API_DeleteSecureObject(session_ctx, id); + if (retStatus != SM_OK) { + SMLOG_W("Error in erasing ObjId=0x%08X (Others)", id); + } + } + } + } while (pmore == kSE05x_MoreIndicator_MORE); +#if SSSFTR_SE05X_CREATE_DELETE_CRYPTOOBJ + retStatus = Se05x_API_ReadCryptoObjectList(session_ctx, list, &listlen); + if (retStatus != SM_OK) { + goto cleanup; + } + for (i = 0; i < listlen; i += 4) { + uint16_t cryptoObjectId = list[i + 1] | (list[i + 0] << 8); + SE05x_CryptoObjectID_t ecryptoObjectId = (SE05x_CryptoObjectID_t)cryptoObjectId; + retStatus = Se05x_API_DeleteCryptoObject(session_ctx, ecryptoObjectId); + if (retStatus != SM_OK) { + LOG_W("Error in erasing CryptoObject=%04X", cryptoObjectId); + } + } +cleanup: +#endif + return retStatus; +} diff --git a/src/lib/apdu/se05x_tlv.h b/src/lib/apdu/se05x_tlv.h index f9909db..ec5d619 100644 --- a/src/lib/apdu/se05x_tlv.h +++ b/src/lib/apdu/se05x_tlv.h @@ -105,4 +105,7 @@ smStatus_t DoAPDUTxRx(pSe05xSession_t session_ctx, #define TLVSET_ECCurveParam TLVSET_U8 #define TLVSET_AttestationAlgo TLVSET_U8 +#define TLVSET_CryptoModeSubType(DESCRIPTION, PBUF, PBUFLEN, TAG, VALUE) \ + TLVSET_U8(DESCRIPTION, PBUF, PBUFLEN, TAG, ((VALUE).union_8bit)) + #endif // #ifndef SE05X_TLV_H_INC diff --git a/src/lib/apdu/se05x_types.h b/src/lib/apdu/se05x_types.h index 446a7da..dc50723 100644 --- a/src/lib/apdu/se05x_types.h +++ b/src/lib/apdu/se05x_types.h @@ -40,6 +40,10 @@ #define EX_SSS_OBJID_IOT_HUB_A_START 0xF0000000u #define EX_SSS_OBJID_IOT_HUB_A_MASK(X) (0xF0000000u & (X)) +#define EX_SSS_OBJID_DEMO_AUTH_START 0x7DA00000u +#define EX_SSS_OBJID_DEMO_AUTH_MASK(X) (0xFFFF0000u & (X)) +#define SE05X_OBJID_TP_MASK(X) (0xFFFFFFFC & (X)) + /** When we want to read with attestation */ #define kSE05x_INS_READ_With_Attestation (kSE05x_INS_READ | kSE05x_INS_ATTEST) @@ -193,6 +197,7 @@ typedef enum kSE05x_P1_SIGNATURE = 0x0C, kSE05x_P1_MAC = 0x0D, kSE05x_P1_CIPHER = 0x0E, + kSE05x_P1_CRYPTO_OBJ = 0x10, } SE05x_P1_t; /** Values for P2 in ISO7816 APDU */ @@ -205,6 +210,11 @@ typedef enum kSE05x_P2_SIZE = 0x07, kSE05x_P2_SIGN = 0x09, kSE05x_P2_VERIFY = 0x0A, + kSE05x_P2_INIT = 0x0B, + kSE05x_P2_UPDATE = 0x0C, + kSE05x_P2_FINAL = 0x0D, + kSE05x_P2_ONESHOT = 0x0E, + kSE05x_P2_DH = 0x0F, kSE05x_P2_SESSION_CREATE = 0x1B, kSE05x_P2_SESSION_CLOSE = 0x1C, kSE05x_P2_VERSION = 0x20, @@ -214,13 +224,14 @@ typedef enum kSE05x_P2_DELETE_OBJECT = 0x28, kSE05x_P2_SESSION_UserID = 0x2C, kSE05x_P2_PBKDF = 0x2E, - kSE05x_P2_DH = 0x0F, + kSE05x_P2_ID = 0x36, kSE05x_P2_ENCRYPT_ONESHOT = 0x37, kSE05x_P2_DECRYPT_ONESHOT = 0x38, - kSE05x_P2_SCP = 0x52, - kSE05x_P2_ONESHOT = 0x0E, - kSE05x_P2_ID = 0x36, kSE05x_P2_PARAM = 0x40, + kSE05x_P2_GENERATE_ONESHOT = 0x45, + kSE05x_P2_VALIDATE_ONESHOT = 0x46, + kSE05x_P2_RANDOM = 0x49, + kSE05x_P2_SCP = 0x52, } SE05x_P2_t; /** ECC Curve Identifiers */ @@ -526,4 +537,117 @@ typedef enum kSE05x_MACAlgo_DES_CMAC8 = 0x7A, } SE05x_MACAlgo_t; + +/** Crypto object identifiers Added for handling digests */ +typedef enum +{ + /** Invalid */ + kSE05x_CryptoObject_NA = 0, + kSE05x_CryptoObject_DIGEST_SHA, + kSE05x_CryptoObject_DIGEST_SHA224, + kSE05x_CryptoObject_DIGEST_SHA256, + kSE05x_CryptoObject_DIGEST_SHA384, + kSE05x_CryptoObject_DIGEST_SHA512, + kSE05x_CryptoObject_DES_CBC_NOPAD, + kSE05x_CryptoObject_DES_CBC_ISO9797_M1, + kSE05x_CryptoObject_DES_CBC_ISO9797_M2, + kSE05x_CryptoObject_DES_CBC_PKCS5, + kSE05x_CryptoObject_DES_ECB_NOPAD, + kSE05x_CryptoObject_DES_ECB_ISO9797_M1, + kSE05x_CryptoObject_DES_ECB_ISO9797_M2, + kSE05x_CryptoObject_DES_ECB_PKCS5, + kSE05x_CryptoObject_AES_ECB_NOPAD, + kSE05x_CryptoObject_AES_CBC_NOPAD, + kSE05x_CryptoObject_AES_CBC_ISO9797_M1, + kSE05x_CryptoObject_AES_CBC_ISO9797_M2, + kSE05x_CryptoObject_AES_CBC_PKCS5, + kSE05x_CryptoObject_AES_CTR, + kSE05x_CryptoObject_AES_CTR_INT_IV, + kSE05x_CryptoObject_HMAC_SHA1, + kSE05x_CryptoObject_HMAC_SHA256, + kSE05x_CryptoObject_HMAC_SHA384, + kSE05x_CryptoObject_HMAC_SHA512, + kSE05x_CryptoObject_CMAC_128, + kSE05x_CryptoObject_AES_GCM, + kSE05x_CryptoObject_AES_GCM_INT_IV, + kSE05x_CryptoObject_AES_CCM, + kSE05x_CryptoObject_AES_CCM_INT_IV, + kSE05x_CryptoObject_PAKE_TYPE_A, + kSE05x_CryptoObject_PAKE_TYPE_B, + kSE05x_CryptoObject_End, +} SE05x_CryptoObjectID_t; + +/** Hashing/Digest algorithms */ +typedef enum +{ + /** Invalid */ + kSE05x_DigestMode_NA = 0, + kSE05x_DigestMode_NO_HASH = 0x00, + kSE05x_DigestMode_SHA = 0x01, + /** Not supported */ + kSE05x_DigestMode_SHA224 = 0x07, + kSE05x_DigestMode_SHA256 = 0x04, + kSE05x_DigestMode_SHA384 = 0x05, + kSE05x_DigestMode_SHA512 = 0x06, +} SE05x_DigestMode_t; + +/** AEAD Algorithms */ +typedef enum +{ + /** Invalid */ + kSE05x_AeadAlgo_NA = 0, + kSE05x_AeadGCMAlgo = 0xB0, + kSE05x_AeadGCM_IVAlgo = 0xF3, + kSE05x_AeadCCMAlgo = 0xF4, +} SE05x_AeadAlgo_t; + +/** PAKE Mode */ +typedef enum +{ + /** Invalid */ + kSE05x_SPAKE2PLUS_NA = 0, + kSE05x_SPAKE2PLUS_P256_SHA256_HKDF_HMAC = 0x01, + kSE05x_SPAKE2PLUS_P256_SHA512_HKDF_HMAC = 0x02, + kSE05x_SPAKE2PLUS_P384_SHA256_HKDF_HMAC = 0x03, + kSE05x_SPAKE2PLUS_P384_SHA512_HKDF_HMAC = 0x04, + kSE05x_SPAKE2PLUS_P521_SHA512_HKDF_HMAC = 0x05, + //kSE05x_SPAKE2PLUS_ED25519_SHA256_HKDF_HMAC = 0x06, //Not supported + //kSE05x_SPAKE2PLUS_ED448_SHA512_HKDF_HMAC = 0x07, //Not supported + kSE05x_SPAKE2PLUS_P256_SHA256_HKDF_CMAC = 0x08, + kSE05x_SPAKE2PLUS_P256_SHA512_HKDF_CMAC = 0x09, +} SE05x_PAKEMode_t; + +/** Cryptographic context for operation */ +typedef enum +{ + /** Invalid */ + kSE05x_CryptoContext_NA = 0, + /** For DigestInit/DigestUpdate/DigestFinal */ + kSE05x_CryptoContext_DIGEST = 0x01, + /** For CipherInit/CipherUpdate/CipherFinal */ + kSE05x_CryptoContext_CIPHER = 0x02, + /** For MACInit/MACUpdate/MACFinal */ + kSE05x_CryptoContext_SIGNATURE = 0x03, + /** For AEADInit/AEADUpdate/AEADFinal */ + kSE05x_CryptoContext_AEAD = 0x04, + /** For PAKE */ + kSE05x_CryptoContext_PAKE = 0x05, +} SE05x_CryptoContext_t; + +/** Crypto module subtype */ +typedef union { + /** In case it's digest */ + SE05x_DigestMode_t digest; + /** In case it's cipher */ + SE05x_CipherMode_t cipher; + /** In case it's mac */ + SE05x_MACAlgo_t mac; + /** In case it's aead */ + SE05x_AeadAlgo_t aead; + /** In case it's pake */ + SE05x_PAKEMode_t pakeMode; + /** Accessing 8 bit value for APDUs */ + uint8_t union_8bit; +} SE05x_CryptoModeSubType_t; + #endif //#ifndef SE05X_TYPES_H_INC From 2f79c24318005b0ae101e2ee1418902e18bd6b0b Mon Sep 17 00:00:00 2001 From: Andrea Gilardoni Date: Mon, 30 Mar 2026 17:58:23 +0200 Subject: [PATCH 4/8] Implementing plugandtrust hal functions --- src/lib/platform/arduino/sm_i2c.cpp | 87 ++++++++++++++++++++ src/lib/platform/arduino/sm_i2c.h | 56 +++++++++++++ src/lib/platform/arduino/sm_port.cpp | 34 ++++++++ src/lib/platform/arduino/sm_port.h | 117 +++++++++++++++++++++++++++ src/lib/platform/arduino/sm_timer.c | 25 ++++++ src/lib/platform/arduino/sm_timer.h | 36 +++++++++ 6 files changed, 355 insertions(+) create mode 100644 src/lib/platform/arduino/sm_i2c.cpp create mode 100644 src/lib/platform/arduino/sm_i2c.h create mode 100644 src/lib/platform/arduino/sm_port.cpp create mode 100644 src/lib/platform/arduino/sm_port.h create mode 100644 src/lib/platform/arduino/sm_timer.c create mode 100644 src/lib/platform/arduino/sm_timer.h diff --git a/src/lib/platform/arduino/sm_i2c.cpp b/src/lib/platform/arduino/sm_i2c.cpp new file mode 100644 index 0000000..0021f8c --- /dev/null +++ b/src/lib/platform/arduino/sm_i2c.cpp @@ -0,0 +1,87 @@ +/* + sm_i2c.cpp + Copyright (c) 2023 Arduino SA. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "../../platform/arduino/sm_i2c.h" +#include + +#if defined(ARDUINO_PORTENTA_C33) && defined(ARDUINO_ARCH_ZEPHYR) +HardwareI2C *CryptoWire = &Wire2; +#elif defined(ARDUINO_PORTENTA_H7) && defined(ARDUINO_ARCH_ZEPHYR) +HardwareI2C *CryptoWire = &Wire2; +#elif defined(ARDUINO_NICLA_VISION) && defined(ARDUINO_ARCH_ZEPHYR) +HardwareI2C *CryptoWire = &Wire2; +#elif defined(ARDUINO_PORTENTA_C33) && defined(ARDUINO_ARCH_RENESAS) +HardwareI2C *CryptoWire = &Wire3; +#elif defined(ARDUINO_NICLA_VISION) && defined(ARDUINO_ARCH_MBED) +HardwareI2C *CryptoWire = &Wire1; +#elif defined(ARDUINO_PORTENTA_H7_M7) && defined(ARDUINO_ARCH_MBED) +HardwareI2C *CryptoWire = &Wire1; +#endif + +i2c_error_t axI2CInit(void **conn_ctx, const char *pDevName) { + (void)pDevName; + + *conn_ctx = CryptoWire; + CryptoWire->begin(); + +#if defined(ARDUINO_ARCH_MBED) + CryptoWire->setClock(400000); +#elif defined(ARDUINO_ARCH_RENESAS) + CryptoWire->setClock(1000000); +#endif + return I2C_OK; +} + +void axI2CTerm(void *conn_ctx, int mode) { + (void)mode; + + HardwareI2C *wire = static_cast(conn_ctx); + + wire->end(); +} + +i2c_error_t axI2CWrite(void *conn_ctx, unsigned char bus, unsigned char addr, unsigned char *pTx, unsigned short txLen) { + (void)bus; + HardwareI2C *wire = static_cast(conn_ctx); + + addr = addr >> 1; + wire->beginTransmission(addr); + wire->write(pTx, txLen); + if (wire->endTransmission() != 0) { + return I2C_FAILED; + } + + return I2C_OK; +} + +i2c_error_t axI2CRead(void *conn_ctx, unsigned char bus, unsigned char addr, unsigned char *pRx, unsigned short rxLen) { + (void)bus; + HardwareI2C *wire = static_cast(conn_ctx); + + addr = addr >> 1; + int retries = 20; + + while (wire->requestFrom((uint8_t)addr, (size_t)rxLen, (bool)true) != rxLen && retries--); + + for (size_t i = 0; wire->available(); i++) { + pRx[i] = wire->read(); + } + + return I2C_OK; +} diff --git a/src/lib/platform/arduino/sm_i2c.h b/src/lib/platform/arduino/sm_i2c.h new file mode 100644 index 0000000..959b116 --- /dev/null +++ b/src/lib/platform/arduino/sm_i2c.h @@ -0,0 +1,56 @@ +/* + sm_i2c.h + Copyright (c) 2023 Arduino SA. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef SM_I2C_H_INC +#define SM_I2C_H_INC + +#define T1oI2C_UM11225 + +#define I2C_IDLE 0 +#define I2C_STARTED 1 +#define I2C_RESTARTED 2 +#define I2C_REPEATED_START 3 +#define DATA_ACK 4 +#define DATA_NACK 5 +#define I2C_BUSY 6 +#define I2C_NO_DATA 7 +#define I2C_NACK_ON_ADDRESS 8 +#define I2C_NACK_ON_DATA 9 +#define I2C_ARBITRATION_LOST 10 +#define I2C_TIME_OUT 11 +#define I2C_OK 12 +#define I2C_FAILED 13 +#define I2C_BUS_0 (0) + +typedef unsigned int i2c_error_t; + +#if defined(__cplusplus) +extern "C" { +#endif + +i2c_error_t axI2CInit(void **conn_ctx, const char *pDevName); +void axI2CTerm(void *conn_ctx, int mode); +i2c_error_t axI2CWrite(void *conn_ctx, unsigned char bus, unsigned char addr, unsigned char *pTx, unsigned short txLen); +i2c_error_t axI2CRead(void *conn_ctx, unsigned char bus, unsigned char addr, unsigned char *pRx, unsigned short rxLen); + +#if defined(__cplusplus) +} +#endif + +#endif // #ifndef SM_I2C_H_INC diff --git a/src/lib/platform/arduino/sm_port.cpp b/src/lib/platform/arduino/sm_port.cpp new file mode 100644 index 0000000..b5892a0 --- /dev/null +++ b/src/lib/platform/arduino/sm_port.cpp @@ -0,0 +1,34 @@ +/* + sm_port.cpp + Copyright (c) 2023 Arduino SA. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "../../platform/arduino/sm_port.h" +#include + +void smlog_print(const char *format, ...) { + char debug_buf[1024]; + va_list argptr; + va_start(argptr, format); + vsnprintf(debug_buf, sizeof(debug_buf), format, argptr); + va_end(argptr); + Serial.print(debug_buf); +} + +void smlog_none(const char *format, ...) { + (void)format; +} diff --git a/src/lib/platform/arduino/sm_port.h b/src/lib/platform/arduino/sm_port.h new file mode 100644 index 0000000..3431920 --- /dev/null +++ b/src/lib/platform/arduino/sm_port.h @@ -0,0 +1,117 @@ +/* + sm_port.h + Copyright (c) 2023 Arduino SA. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef SM_PORT_H_INC +#define SM_PORT_H_INC +#include "Arduino.h" + +/* + * 0: NONE + * 1: ERROR + * 2: WARNING + * 3: INFO + * 4: DEBUG + * 5: APDU + */ +#define DEBUG_LEVEL 0 + +#if DEBUG_LEVEL > 0 + #define SMLOG_E smlog_print +#else + #define SMLOG_E smlog_none +#endif + +#if DEBUG_LEVEL > 1 + #define SMLOG_W smlog_print +#else + #define SMLOG_W smlog_none +#endif + +#if DEBUG_LEVEL > 2 + #define SMLOG_I smlog_print +#else + #define SMLOG_I smlog_none +#endif + +#if DEBUG_LEVEL > 3 + #define SMLOG_D smlog_print +#else + #define SMLOG_D smlog_none +#endif + +#if DEBUG_LEVEL > 4 + #define SMLOG_AU8_D(BUF, LEN) \ + smlog_print("%s", ":"); \ + for (size_t bufIndex = 0; bufIndex < (size_t)LEN; bufIndex++) { \ + smlog_print("%02x ", BUF[bufIndex]); \ + } \ + smlog_print("%s","\n") + + #define SMLOG_MAU8_D(MSG, BUF, LEN) \ + smlog_print("%s", MSG); \ + smlog_print("%s", ":"); \ + for (size_t bufIndex = 0; bufIndex < (size_t)LEN; bufIndex++) { \ + smlog_print("%02x ", BUF[bufIndex]); \ + } \ + smlog_print("%s","\n") + +#else + #define SMLOG_AU8_D(BUF, LEN) + #define SMLOG_MAU8_D(MSG, BUF, LEN) +#endif + +#define SM_MUTEX_DEFINE(x) +#define SM_MUTEX_INIT(x) +#define SM_MUTEX_DEINIT(x) +#define SM_MUTEX_LOCK(x) +#define SM_MUTEX_UNLOCK(x) + +#define sm_malloc malloc +#define sm_free free + +#ifndef FALSE +#define FALSE false +#endif + +#ifndef TRUE +#define TRUE true +#endif + +#if defined(ARDUINO_PORTENTA_C33) && defined(ARDUINO_ARCH_ZEPHYR) +#define SE050_ENA_PIN 84 +#elif defined(ARDUINO_PORTENTA_H7) && defined(ARDUINO_ARCH_ZEPHYR) +#error TODO +#elif defined(ARDUINO_NICLA_VISION) && defined(ARDUINO_ARCH_ZEPHYR) +#error TODO +#elif defined(ARDUINO_PORTENTA_C33) && defined(ARDUINO_ARCH_RENESAS) +#define SE050_ENA_PIN 98 +#elif defined(ARDUINO_PORTENTA_H7_M7) && defined(ARDUINO_ARCH_MBED) +#define SE050_ENA_PIN PI_12 +#endif + +#ifdef __cplusplus +extern "C" { +#endif +void smlog_print(const char *format, ...); +void smlog_none(const char *format, ...); +#ifdef __cplusplus +} +#endif + +#endif // #ifndef SM_PORT_H_INC diff --git a/src/lib/platform/arduino/sm_timer.c b/src/lib/platform/arduino/sm_timer.c new file mode 100644 index 0000000..5be72aa --- /dev/null +++ b/src/lib/platform/arduino/sm_timer.c @@ -0,0 +1,25 @@ +/* + sm_timer.c + Copyright (c) 2023 Arduino SA. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include + +void sm_sleep(uint32_t msec) { + delay(msec); +} diff --git a/src/lib/platform/arduino/sm_timer.h b/src/lib/platform/arduino/sm_timer.h new file mode 100644 index 0000000..e3facd7 --- /dev/null +++ b/src/lib/platform/arduino/sm_timer.h @@ -0,0 +1,36 @@ +/* + sm_timer.h + Copyright (c) 2023 Arduino SA. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef SM_TIMER_H_INC +#define SM_TIMER_H_INC + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* function used for delay loops */ +void sm_sleep(uint32_t msec); + +#ifdef __cplusplus +} +#endif + +#endif //#ifndef SM_TIMER_H_INC From 2f3b98b8ffb603fba99f69bd3bf8ab57cc4ec637 Mon Sep 17 00:00:00 2001 From: Andrea Gilardoni Date: Mon, 30 Mar 2026 17:52:45 +0200 Subject: [PATCH 5/8] Adding Arduino se05x library implementation and entrypoint --- src/Arduino_SE05X.h | 4 + src/SE05X.cpp | 907 ++++++++++++++++++++++++++++++++++++++++++++ src/SE05X.h | 414 ++++++++++++++++++++ 3 files changed, 1325 insertions(+) create mode 100644 src/Arduino_SE05X.h create mode 100644 src/SE05X.cpp create mode 100644 src/SE05X.h diff --git a/src/Arduino_SE05X.h b/src/Arduino_SE05X.h new file mode 100644 index 0000000..d866bb7 --- /dev/null +++ b/src/Arduino_SE05X.h @@ -0,0 +1,4 @@ +// TODO spdx + +#pragma once +#include "SE05X.h" diff --git a/src/SE05X.cpp b/src/SE05X.cpp new file mode 100644 index 0000000..c9c42a5 --- /dev/null +++ b/src/SE05X.cpp @@ -0,0 +1,907 @@ +/* + SE05X.cpp + Copyright (c) 2023 Arduino SA. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "SE05X.h" + +/** + * 26 bytes see ecc_der_header_nist256 + */ +#define SE05X_EC_KEY_DER_HEADER_LENGTH 26 + +/** + * 1 byte for key compression format 0x02 / 0x03 / 0x04 + */ +#define SE05X_EC_KEY_FORMAT_LENGTH 1 + +/** + * 64 bytes X Y uncompressed points + */ +#define SE05X_EC_KEY_RAW_LENGTH 64 + +/** + * 91 bytes total key length in DER format + */ +#define SE05X_EC_KEY_DER_LENGTH SE05X_EC_KEY_DER_HEADER_LENGTH + \ + SE05X_EC_KEY_FORMAT_LENGTH + \ + SE05X_EC_KEY_RAW_LENGTH + +/** + * 32 bytes R values + 32 bytes S values + */ +#define SE05X_EC_SIGNATURE_RAW_LENGTH 64 + +/** + * 8 bytes worst case 30 45 02 21 00 | 32 bytes R values | 02 21 00 | 32 bytes S values + */ +#define SE05X_EC_SIGNATURE_MAX_HEADER_LENGTH 8 + +/** + * 6 bytes best case 30 45 02 21 | 32 bytes R values | 02 21 | 32 bytes S values + */ +#define SE05X_EC_SIGNATURE_MIN_HEADER_LENGTH 6 + +/** + * 72 bytes worst case + */ +#define SE05X_EC_SIGNATURE_MAX_DER_LENGTH SE05X_EC_SIGNATURE_MAX_HEADER_LENGTH + \ + SE05X_EC_SIGNATURE_RAW_LENGTH + +/** + * 70 bytes best case + */ +#define SE05X_EC_SIGNATURE_MIN_DER_LENGTH SE05X_EC_SIGNATURE_MIN_HEADER_LENGTH + \ + SE05X_EC_SIGNATURE_RAW_LENGTH + +#define SE05X_SHA256_LENGTH 32 + +#define SE05X_TEMP_OBJECT 9999 + +#define SE05X_MAX_CHUNK_SIZE 100 + +static const byte ecc_der_header_nist256[SE05X_EC_KEY_DER_HEADER_LENGTH] = +{ + 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, + 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, + 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, + 0x42, 0x00 +}; + +SE05XClass::SE05XClass() { } +SE05XClass::~SE05XClass() { } + +int SE05XClass::begin() +{ + smStatus_t status; + + pinMode(SE050_ENA_PIN, OUTPUT); + digitalWrite(SE050_ENA_PIN, HIGH); + + memset(&_se05x_session, 0, sizeof(_se05x_session)); + + status = Se05x_API_SessionOpen(&_se05x_session); + if(status != SM_OK) { + return 0; + } + + return 1; +} + +void SE05XClass::end() +{ + Se05x_API_SessionClose(&_se05x_session); +} + +int SE05XClass::serialNumber(byte sn[]) +{ + return serialNumber(sn, SE05X_SN_LENGTH); +} + +int SE05XClass::serialNumber(byte sn[], size_t length) +{ + size_t uidLen = length; + const int kSE05x_AppletResID_UNIQUE_ID = 0x7FFF0206; + smStatus_t status; + + status = Se05x_API_ReadObject(&_se05x_session, kSE05x_AppletResID_UNIQUE_ID, 0, length, sn, &uidLen); + if (status != SM_OK || length != uidLen) { + SMLOG_E("Error in Se05x_API_ReadObject \n"); + return 0; + } + return 1; +} + +String SE05XClass::serialNumber() +{ + String result = (char*)NULL; + byte UID[SE05X_SN_LENGTH]; + + serialNumber(UID, sizeof(UID)); + + result.reserve(SE05X_SN_LENGTH * 2); + + for (size_t i = 0; i < SE05X_SN_LENGTH; i++) { + byte b = UID[i]; + + if (b < 16) { + result += "0"; + } + result += String(b, HEX); + } + + result.toUpperCase(); + + return result; +} + +long SE05XClass::random(long max) +{ + return random(0, max); +} + +long SE05XClass::random(long min, long max) +{ + if (min >= max) + { + return min; + } + + long diff = max - min; + + long r; + random((byte*)&r, sizeof(r)); + + if (r < 0) { + r = -r; + } + + r = (r % diff); + + return (r + min); +} + +int SE05XClass::random(byte data[], size_t length) +{ + smStatus_t status; + uint16_t offset = 0; + uint16_t left = length; + + while (left > 0) { + uint16_t chunk = (left > SE05X_MAX_CHUNK_SIZE) ? SE05X_MAX_CHUNK_SIZE : left; + size_t max_buffer = chunk; + + status = Se05x_API_GetRandom(&_se05x_session, chunk, (data + offset), &max_buffer); + if (status != SM_OK) { + SMLOG_E("Error in Se05x_API_GetRandom \n"); + return 0; + } + left = left - chunk; + offset = offset + chunk; + } + + return 1; +} + +int SE05XClass::generatePrivateKey(int keyID, byte keyBuf[], size_t keyBufMaxLen, size_t* keyLen) +{ + if (keyBufMaxLen < SE05X_EC_KEY_DER_LENGTH ) { + SMLOG_E("Error in generatePrivateKey buffer length \n"); + return 0; + } + + *keyLen = SE05X_EC_KEY_DER_LENGTH; + + /* Copy header byte from 0 to 25 */ + memcpy(keyBuf, ecc_der_header_nist256, sizeof(ecc_der_header_nist256)); + + /* Add format byte */ + keyBuf[SE05X_EC_KEY_DER_HEADER_LENGTH] = 0x04; + + /* Add X Y points */ + return generatePrivateKey(keyID, &keyBuf[SE05X_EC_KEY_DER_HEADER_LENGTH + SE05X_EC_KEY_FORMAT_LENGTH]); +} + +int SE05XClass::generatePrivateKey(int keyID, byte publicKey[]) +{ + smStatus_t status; + SE05x_ECCurve_t curveID = kSE05x_ECCurve_NIST_P256; + SE05x_Result_t result; + + /* SE050 fills a buffer with 1 byte key format + 64 bytes of X Y points */ + uint8_t keyBuf[SE05X_EC_KEY_FORMAT_LENGTH + SE05X_EC_KEY_RAW_LENGTH]; + size_t keylen = sizeof(keyBuf); + + status = Se05x_API_CheckObjectExists(&_se05x_session, keyID, &result); + if (status != SM_OK) { + SMLOG_E("Error in Se05x_API_CheckObjectExists \n"); + return 0; + } + + if (result == kSE05x_Result_SUCCESS) { + SMLOG_I("Object already exists \n"); + curveID = kSE05x_ECCurve_NA; + } + + SMLOG_I("Generate ec key \n"); + status = Se05x_API_WriteECKey(&_se05x_session, NULL, 0, keyID, curveID, NULL, 0, NULL, 0, kSE05x_INS_NA, kSE05x_KeyPart_Pair); + if (status != SM_OK) { + SMLOG_E("Error in Se05x_API_WriteECKey \n"); + return 0; + } + + status = Se05x_API_ReadObject(&_se05x_session, keyID, 0, 0, keyBuf, &keylen); + if (status != SM_OK) { + SMLOG_E("Error in Se05x_API_ReadObject \n"); + return 0; + } + + /* To User: copy only 64 bytes of X Y points */ + memcpy(publicKey, &keyBuf[SE05X_EC_KEY_FORMAT_LENGTH], SE05X_EC_KEY_RAW_LENGTH); + + return 1; +} + +int SE05XClass::generatePublicKey(int keyID, byte keyBuf[], size_t keyBufMaxLen, size_t* keyLen) +{ + if (keyBufMaxLen < SE05X_EC_KEY_DER_LENGTH ) { + SMLOG_E("Error in generatePublicKey buffer too short \n"); + return 0; + } + + *keyLen = SE05X_EC_KEY_DER_LENGTH; + + /* Copy header byte from 0 to 25 */ + memcpy(keyBuf, ecc_der_header_nist256, SE05X_EC_KEY_DER_HEADER_LENGTH); + + /* Add format byte */ + keyBuf[SE05X_EC_KEY_DER_HEADER_LENGTH] = 0x04; + + /* Add X Y points */ + return generatePublicKey(keyID, &keyBuf[SE05X_EC_KEY_DER_HEADER_LENGTH + SE05X_EC_KEY_FORMAT_LENGTH]); +} + +int SE05XClass::generatePublicKey(int keyID, byte publicKey[]) +{ + smStatus_t status; + SE05x_Result_t result; + + /* SE050 fills a buffer with 1 byte key format + 64 bytes of X Y points */ + uint8_t keyBuf[SE05X_EC_KEY_FORMAT_LENGTH + SE05X_EC_KEY_RAW_LENGTH]; + size_t keyLen = sizeof(keyBuf); + + status = Se05x_API_CheckObjectExists(&_se05x_session, keyID, &result); + if (status != SM_OK) { + SMLOG_E("Error in Se05x_API_CheckObjectExists \n"); + return 0; + } + + status = Se05x_API_ReadObject(&_se05x_session, keyID, 0, 0, keyBuf, &keyLen); + if (status != SM_OK) { + SMLOG_E("Error in Se05x_API_ReadObject \n"); + return 0; + } + + /* To User: copy only 64 bytes of X Y points */ + memcpy(publicKey, &keyBuf[SE05X_EC_KEY_FORMAT_LENGTH], SE05X_EC_KEY_RAW_LENGTH); + + return 1; +} + +int SE05XClass::importPublicKey(int keyID, const byte publicKey[], size_t keyLen) +{ + smStatus_t status; + SE05x_ECCurve_t curveID = kSE05x_ECCurve_NIST_P256; + SE05x_Result_t result; + + /* SE050 fills a buffer with 1 byte key format + 64 bytes of X Y points */ + uint8_t keyBuf[SE05X_EC_KEY_FORMAT_LENGTH + SE05X_EC_KEY_RAW_LENGTH]; + + if (keyLen < SE05X_EC_KEY_DER_LENGTH) { + SMLOG_E("Error in importPublicKey invalid key length \n"); + return 0; + } + + if (memcmp(ecc_der_header_nist256, publicKey, SE05X_EC_KEY_DER_HEADER_LENGTH)) { + SMLOG_E("Error in importPublicKey invalid key format \n"); + return 0; + } + + status = Se05x_API_CheckObjectExists(&_se05x_session, keyID, &result); + if (status != SM_OK) { + SMLOG_E("Error in Se05x_API_CheckObjectExists \n"); + return 0; + } + + if (result == kSE05x_Result_SUCCESS) { + SMLOG_I("Object already exists \n"); + curveID = kSE05x_ECCurve_NA; + } + + /* To SE050: copy 65 bytes Key format + 64 bytes of X Y points */ + memcpy(keyBuf, &publicKey[SE05X_EC_KEY_DER_HEADER_LENGTH], sizeof(keyBuf)); + + SMLOG_I("Import ec key \n"); + status = Se05x_API_WriteECKey(&_se05x_session, NULL, 0, keyID, curveID, NULL, 0, keyBuf, sizeof(keyBuf), kSE05x_INS_WRITE, kSE05x_KeyPart_Public); + if (status != SM_OK) { + SMLOG_E("Error in Se05x_API_WriteECKey \n"); + return 0; + } + + return 1; +} + +int SE05XClass::beginSHA256() +{ + smStatus_t status; + SE05x_CryptoModeSubType_t subtype; + + subtype.digest = kSE05x_DigestMode_SHA256; + + status = Se05x_API_CreateCryptoObject(&_se05x_session, kSE05x_CryptoObject_DIGEST_SHA256, kSE05x_CryptoContext_DIGEST, subtype); + if (status != SM_OK) { + SMLOG_W("Se05x_API_CreateCryptoObject failed. Object already exists? \n"); + } + + status = Se05x_API_DigestInit(&_se05x_session, kSE05x_CryptoObject_DIGEST_SHA256); + if (status != SM_OK) { + SMLOG_E("Error in Se05x_API_DigestInit \n"); + return 0; + } + + return 1; +} + +int SE05XClass::updateSHA256(const byte in[], size_t inLen) +{ + smStatus_t status; + + status = Se05x_API_DigestUpdate(&_se05x_session, kSE05x_CryptoObject_DIGEST_SHA256, in, inLen); + if (status != SM_OK) { + SMLOG_E("Error in Se05x_API_DigestUpdate \n"); + return 0; + } + + return 1; +} + +int SE05XClass::endSHA256(byte out[], size_t* outLen) +{ + smStatus_t status; + + if (*outLen < SE05X_SHA256_LENGTH) { + SMLOG_E("Error in endSHA256 \n"); + *outLen = 0; + return 0; + } + + status = Se05x_API_DigestFinal(&_se05x_session, kSE05x_CryptoObject_DIGEST_SHA256, NULL, 0, out, outLen); + if (status != SM_OK) { + SMLOG_E("Error in Se05x_API_DigestFinal \n"); + *outLen = 0; + return 0; + } + + status = Se05x_API_DeleteCryptoObject(&_se05x_session, kSE05x_CryptoObject_DIGEST_SHA256); + + return 1; +} + +int SE05XClass::SHA256(const byte in[], size_t inLen, byte out[], size_t outMaxLen, size_t* outLen) +{ + smStatus_t status; + + *outLen = outMaxLen; + status = Se05x_API_DigestOneShot(&_se05x_session, kSE05x_DigestMode_SHA256, in, inLen, out, outLen); + if (status != SM_OK) { + SMLOG_E("Error in Se05x_API_DigestOneShot \n"); + *outLen = 0; + return 0; + } + + return 1; +} + +int SE05XClass::Sign(int keyID, const byte hash[], size_t hashLen, byte sig[], size_t sigMaxLen, size_t* sigLen) +{ + smStatus_t status; + SE05x_Result_t result; + + if (hashLen != SE05X_SHA256_LENGTH) { + SMLOG_E("Error in Sign invalid input SHA256 buffer \n"); + *sigLen = 0; + return 0; + } + + if (sigMaxLen < SE05X_EC_SIGNATURE_MAX_DER_LENGTH) { + SMLOG_E("Error in Sign signature buffer too small \n"); + *sigLen = 0; + return 0; + } + + status = Se05x_API_CheckObjectExists(&_se05x_session, keyID, &result); + if (status != SM_OK) { + SMLOG_E("Error in Se05x_API_CheckObjectExists \n"); + *sigLen = 0; + return 0; + } + + if (result != kSE05x_Result_SUCCESS) { + SMLOG_E("Object not exists \n"); + *sigLen = 0; + return 0; + } + + *sigLen = sigMaxLen; + status = Se05x_API_ECDSASign(&_se05x_session, keyID, kSE05x_ECSignatureAlgo_SHA_256, hash, hashLen, sig, sigLen); + if (status != SM_OK) { + SMLOG_E("Error in Se05x_API_ECDSASign \n"); + return 0; + } + return 1; +} + +int SE05XClass::ecSign(int slot, const byte message[], byte signature[]) +{ + byte signatureDer[SE05X_EC_SIGNATURE_MAX_DER_LENGTH]; + size_t signatureDerLen; + size_t size = SE05X_EC_SIGNATURE_RAW_LENGTH; + + if (!Sign(slot, message, SE05X_SHA256_LENGTH, signatureDer, sizeof(signatureDer), &signatureDerLen)) { + SMLOG_E("Error in ecSign \n"); + return 0; + } + + /* Get r s values from DER buffer */ + if (!getECSignatureRsValuesFromDER(signatureDer, signatureDerLen, signature, &size)) { + SMLOG_E("Error in ecSign cannot get R S values\n"); + return 0; + } + + return 1; +} + +int SE05XClass::Verify(int keyID, const byte hash[], size_t hashLen, const byte sig[], size_t sigLen) +{ + smStatus_t status; + SE05x_Result_t result; + + if (hashLen != SE05X_SHA256_LENGTH) { + SMLOG_E("Error in Verify invalid input SHA256 buffer \n"); + return 0; + } + + if ((sigLen < SE05X_EC_SIGNATURE_MIN_DER_LENGTH) || (sigLen > SE05X_EC_SIGNATURE_MAX_DER_LENGTH)) { + SMLOG_E("Error in Verify invalid signature \n"); + return 0; + } + + status = Se05x_API_CheckObjectExists(&_se05x_session, keyID, &result); + if (status != SM_OK) { + SMLOG_E("Error in Se05x_API_CheckObjectExists \n"); + return 0; + } + + if (result != kSE05x_Result_SUCCESS) { + SMLOG_E("Object not exists \n"); + return 0; + } + + status = Se05x_API_ECDSAVerify(&_se05x_session, keyID, kSE05x_ECSignatureAlgo_SHA_256, hash, hashLen, sig, sigLen, &result); + if (status != SM_OK) { + SMLOG_E("Error in Se05x_API_ECDSASign \n"); + return 0; + } + + if (result != kSE05x_Result_SUCCESS) { + SMLOG_E("Verify failure \n"); + return 0; + } + return 1; +} + +int SE05XClass::ecdsaVerify(const byte message[], const byte signature[], const byte pubkey[]) +{ + byte pubKeyDER[SE05X_EC_KEY_DER_LENGTH]; + size_t pubKeyDERLen = sizeof(pubKeyDER); + byte signatureDER[SE05X_EC_SIGNATURE_MAX_DER_LENGTH]; + size_t signatureDERLen = sizeof(signatureDER); + + if (!setECKeyXyVauesInDER(pubkey, SE05X_EC_KEY_RAW_LENGTH, pubKeyDER, &pubKeyDERLen)) { + SMLOG_E("ecdsaVerify failure creating key DER\n"); + return 0; + } + + if (!importPublicKey(SE05X_TEMP_OBJECT, pubKeyDER, pubKeyDERLen)) { + SMLOG_E("ecdsaVerify failure importing temp key\n"); + return 0; + } + + if (!setECSignatureRsValuesInDER(signature, SE05X_EC_SIGNATURE_RAW_LENGTH, signatureDER, &signatureDERLen)) { + SMLOG_E("ecdsaVerify failure creating signature DER\n"); + return 0; + } + + if (!Verify(SE05X_TEMP_OBJECT, message, SE05X_SHA256_LENGTH, signatureDER, SE05X_EC_SIGNATURE_MAX_DER_LENGTH)) { + SMLOG_E("ecdsaVerify failure\n"); + return 0; + } + + if (!deleteBinaryObject(SE05X_TEMP_OBJECT)) { + SMLOG_E("ecdsaVerify failure deleting temporary object\n"); + return 0; + } + + return 1; +} + +int SE05XClass::readBinaryObject(int objectId, byte data[], size_t dataMaxLen, size_t* length) +{ + smStatus_t status; + SE05x_Result_t result; + uint16_t offset = 0; + uint16_t size; + + status = Se05x_API_CheckObjectExists(&_se05x_session, objectId, &result); + if (status != SM_OK) { + SMLOG_E("Error in Se05x_API_CheckObjectExists \n"); + *length = 0; + return 0; + } + + if (result != kSE05x_Result_SUCCESS) { + SMLOG_E("Object not exists \n"); + *length = 0; + return 0; + } + + status = Se05x_API_ReadSize(&_se05x_session, objectId, &size); + if (status != SM_OK) { + SMLOG_E("Error in Se05x_API_CheckObjectExists \n"); + *length = 0; + return 0; + } + + if (dataMaxLen < size) { + SMLOG_E("Error in readBinaryObject buffer too small \n"); + *length = 0; + return 0; + } + + uint16_t left = size; + while (left > 0) { + uint16_t chunk = (left > SE05X_MAX_CHUNK_SIZE) ? SE05X_MAX_CHUNK_SIZE : left; + size_t max_buffer = chunk; + + status = Se05x_API_ReadObject(&_se05x_session, objectId, offset, chunk, (data + offset), &max_buffer); + if (status != SM_OK) { + SMLOG_E("Error in Se05x_API_ReadObject \n"); + *length = 0; + return 0; + } + left = left - chunk; + offset = offset + chunk; + } + + *length = size; + return 1; +} + +int SE05XClass::readSlot(int slot, byte data[], int length) +{ + size_t size; + return readBinaryObject(slot, data, length, &size); +} + +int SE05XClass::AES_ECB_encrypt(int objectId, const byte data[], size_t data_length, byte output[], size_t *output_len) +{ + smStatus_t status; + status = Se05x_API_CipherOneShot(&_se05x_session, objectId, kSE05x_CipherMode_AES_ECB_NOPAD, data, data_length, 0, 0, output, output_len, kSE05x_Cipher_Oper_OneShot_Encrypt); + if (status != SM_OK) { + SMLOG_E("Error in Se05x_API_CipherOneShot \n"); + return 0; + } + return 1; +} + +int SE05XClass::AES_ECB_decrypt(int objectId, const byte data[], size_t data_length, byte output[], size_t *output_len) +{ + smStatus_t status; + status = Se05x_API_CipherOneShot(&_se05x_session, objectId, kSE05x_CipherMode_AES_ECB_NOPAD, data, data_length, 0, 0, output, output_len, kSE05x_Cipher_Oper_OneShot_Decrypt); + if (status != SM_OK) { + SMLOG_E("Error in Se05x_API_CipherOneShot \n"); + return 0; + } + return 1; +} + +int SE05XClass::writeAESKey(int objectId, const byte data[], size_t length) +{ + smStatus_t status; + SE05x_Result_t result; + + status = Se05x_API_CheckObjectExists(&_se05x_session, objectId, &result); + if (status != SM_OK) { + SMLOG_E("Error in Se05x_API_CheckObjectExists \n"); + return 0; + } + + if (result == kSE05x_Result_SUCCESS) { + SMLOG_E("Object exists \n"); + return 0; + } + + status = Se05x_API_WriteSymmKey(&_se05x_session, NULL, 3, objectId, SE05x_KeyID_KEK_NONE, data, length, kSE05x_INS_NA, kSE05x_SymmKeyType_AES); + + if (status != SM_OK) { + SMLOG_E("Error in Se05x_API_WriteSymmKey \n"); + return 0; + } + return 1; +} + +int SE05XClass::writeHMACKey(int objectId, const byte data[], size_t length) +{ + smStatus_t status; + SE05x_Result_t result; + + status = Se05x_API_CheckObjectExists(&_se05x_session, objectId, &result); + if (status != SM_OK) { + SMLOG_E("Error in Se05x_API_CheckObjectExists \n"); + return 0; + } + + if (result == kSE05x_Result_SUCCESS) { + SMLOG_E("Object exists \n"); + } + + status = Se05x_API_WriteSymmKey(&_se05x_session, NULL, 0, objectId, SE05x_KeyID_KEK_NONE, data, length, kSE05x_INS_NA, kSE05x_SymmKeyType_HMAC); + + if (status != SM_OK) { + SMLOG_E("Error in Se05x_API_WriteSymmKey \n"); + return 0; + } + return 1; +} + +int SE05XClass::HMAC_Generate(int objectId, uint8_t mac_operation, const byte data[], size_t data_length, byte output[], size_t *output_len) +{ + smStatus_t status; + status = Se05x_API_MACOneShot_G(&_se05x_session, objectId, mac_operation, data, data_length, output, output_len); + + if (status != SM_OK) { + SMLOG_E("Error in Se05x_API_CipherOneShot \n"); + return status; + } + return 1; +} + +int SE05XClass::writeBinaryObject(int objectId, const byte data[], size_t length) +{ + smStatus_t status; + SE05x_Result_t result; + uint8_t exists = 0; + uint16_t offset = 0; + uint16_t size; + + status = Se05x_API_CheckObjectExists(&_se05x_session, objectId, &result); + if (status != SM_OK) { + SMLOG_E("Error in Se05x_API_CheckObjectExists \n"); + return 0; + } + + if (result == kSE05x_Result_SUCCESS) { + SMLOG_E("Object exists \n"); + exists = 1; + } + + uint16_t left = length; + + while (left > 0) { + uint16_t chunk = (left > SE05X_MAX_CHUNK_SIZE) ? SE05X_MAX_CHUNK_SIZE : left; + left = left - chunk; + size = exists ? 0 : length; + + status = Se05x_API_WriteBinary(&_se05x_session, NULL, objectId, offset, size, (data + offset), chunk); + if (status != SM_OK) { + SMLOG_E("Error in Se05x_API_WriteBinary \n"); + return 0; + } + exists = 1; + offset = offset + chunk; + } + + return 1; +} + +int SE05XClass::writeSlot(int slot, const byte data[], int length) +{ + if (existsBinaryObject(slot)) { + if (!deleteBinaryObject(slot)) { + return 0; + } + } + return writeBinaryObject(slot, data, length); +} + +int SE05XClass::existsBinaryObject(int objectId) +{ + smStatus_t status; + SE05x_Result_t result; + + status = Se05x_API_CheckObjectExists(&_se05x_session, objectId, &result); + if (status != SM_OK) { + SMLOG_E("Error in Se05x_API_CheckObjectExists \n"); + return 0; + } + + if (result != kSE05x_Result_SUCCESS) { + SMLOG_E("Object not exists \n"); + return 0; + } + + return 1; +} + +int SE05XClass::deleteBinaryObject(int objectId) +{ + smStatus_t status; + + status = Se05x_API_DeleteSecureObject(&_se05x_session, objectId); + if (status != SM_OK) { + SMLOG_E("Error in Se05x_API_DeleteSecureObject \n"); + return 0; + } + + return 1; +} + +int SE05XClass::deleteAllObjects(void) +{ + smStatus_t status; + + status = Se05x_API_DeleteAll_Iterative(&_se05x_session); + if (status != SM_OK) { + SMLOG_E("Error in Se05x_API_CheckObjectExists \n"); + return 0; + } + + return 1; +} + +int SE05XClass::getECKeyXyValuesFromDER(byte* derKey, size_t derLen, byte* rawKey, size_t* rawLen) +{ + if(*rawLen < SE05X_EC_KEY_RAW_LENGTH) { + SMLOG_E("Error in getECKeyXyValuesFromDER \n"); + *rawLen = 0; + return 0; + } + + /* XY values are stored in the last 64 bytes of DER buffer */ + *rawLen = SE05X_EC_KEY_RAW_LENGTH; + memcpy(rawKey, &derKey[derLen - SE05X_EC_KEY_RAW_LENGTH], SE05X_EC_KEY_RAW_LENGTH); + + return 1; +} + +int SE05XClass::setECKeyXyVauesInDER(const byte* rawKey, size_t rawLen, byte* derKey, size_t* derLen) +{ + if(rawLen != SE05X_EC_KEY_RAW_LENGTH) { + SMLOG_E("Error in setECKeyXyVauesInDER invalid raw key\n"); + *derLen = 0; + return 0; + } + + if(*derLen < SE05X_EC_KEY_DER_LENGTH) { + SMLOG_E("Error in setECKeyXyVauesInDER buffer too small\n"); + *derLen = 0; + return 0; + } + + /* Copy header byte from 0 to 25 */ + memcpy(&derKey[0], &ecc_der_header_nist256[0], SE05X_EC_KEY_DER_HEADER_LENGTH); + /* Add format byte */ + derKey[SE05X_EC_KEY_DER_HEADER_LENGTH] = 0x04; + /* Add X Y points */ + memcpy(&derKey[SE05X_EC_KEY_DER_HEADER_LENGTH + SE05X_EC_KEY_FORMAT_LENGTH], &rawKey[0], SE05X_EC_KEY_RAW_LENGTH); + + *derLen = SE05X_EC_KEY_DER_LENGTH; + return 1; +} + +int SE05XClass::getECSignatureRsValuesFromDER(byte* derSignature, size_t derLen, byte* rawSignature, size_t *rawLen) +{ + byte rLen; + byte sLen; + + if ((derLen < SE05X_EC_SIGNATURE_MIN_DER_LENGTH) || (derLen > SE05X_EC_SIGNATURE_MAX_DER_LENGTH)) { + SMLOG_E("Error in getECSignatureRsValuesFromDER invalid signature\n"); + *rawLen = 0; + return 0; + } + + if (*rawLen < SE05X_EC_SIGNATURE_RAW_LENGTH) { + SMLOG_E("Error in getECSignatureRsValuesFromDER buffer too small\n"); + *rawLen = 0; + return 0; + } + + rLen = derSignature[3]; + sLen = derSignature[3 + rLen + 2]; + + byte * out = rawSignature; + + if(rLen == (SE05X_EC_SIGNATURE_RAW_LENGTH / 2)) + { + memcpy(out, &derSignature[4], (SE05X_EC_SIGNATURE_RAW_LENGTH / 2)); + } + else if ((rLen == ((SE05X_EC_SIGNATURE_RAW_LENGTH / 2) + 1)) && (derSignature[4] == 0)) + { + memcpy(out, &derSignature[5], (SE05X_EC_SIGNATURE_RAW_LENGTH / 2)); + } + + out += (SE05X_EC_SIGNATURE_RAW_LENGTH / 2); + + if(sLen == (SE05X_EC_SIGNATURE_RAW_LENGTH / 2)) + { + memcpy(out, &derSignature[3 + rLen + 3], (SE05X_EC_SIGNATURE_RAW_LENGTH / 2)); + } + else if ((sLen == ((SE05X_EC_SIGNATURE_RAW_LENGTH / 2) + 1)) && (derSignature[3 + rLen + 3] == 0)) + { + memcpy(out, &derSignature[3 + rLen + 4], (SE05X_EC_SIGNATURE_RAW_LENGTH / 2)); + } + + return 1; +} + +int SE05XClass::setECSignatureRsValuesInDER(const byte* rawSignature, size_t rawLen, byte* signature, size_t* derLen) +{ + /** + * Always consider worst case with padding + * + * | 0x30 0x46 0x02 0x21 0x00 | R values 32 bytes | 0x02 0x21 0x00 | S values 32 bytes | + * + */ + const int halfSigLen = SE05X_EC_SIGNATURE_RAW_LENGTH / 2; + + if (rawLen != SE05X_EC_SIGNATURE_RAW_LENGTH) { + SMLOG_E("Error in setECSignatureRsValuesInDER invalid signature\n"); + *derLen = 0; + return 0; + } + + if (*derLen < SE05X_EC_SIGNATURE_MAX_DER_LENGTH) { + SMLOG_E("Error in setECSignatureRsValuesInDER buffer too small\n"); + *derLen = 0; + return 0; + } + + signature[0] = 0x30; + signature[1] = 0x46; /* 3 + 32 + 3 + 32*/ + signature[2] = 0x02; + signature[3] = 0x21; + signature[4] = 0x00; + memcpy(&signature[5], &rawSignature[0], halfSigLen); + signature[37] = 0x02; + signature[38] = 0x21; + signature[39] = 0x00; + memcpy(&signature[40], &rawSignature[halfSigLen], halfSigLen); + + return 1; +} + +SE05XClass SE05X; diff --git a/src/SE05X.h b/src/SE05X.h new file mode 100644 index 0000000..124a82c --- /dev/null +++ b/src/SE05X.h @@ -0,0 +1,414 @@ +/* + SE05X.h + Copyright (c) 2023 Arduino SA. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _SE05X_H_ +#define _SE05X_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#include "lib/apdu/se05x_APDU_apis.h" +#include "lib/platform/arduino/sm_port.h" + +#ifdef __cplusplus +} +#endif + +#define SE05X_SN_LENGTH 18 + +class SE05XClass +{ +public: + SE05XClass(); + virtual ~SE05XClass(); + + int begin(); + void end(); + + int serialNumber(byte sn[]); + int serialNumber(byte sn[], size_t length); +#if defined (ARDUINO) + String serialNumber(); +#endif + + long random(long max); + long random(long min, long max); + int random(byte data[], size_t length); + + /** generatePrivateKey + * + * Create a new ECCurve_NIST_P256 keypair. Only public key will be available + * inside KeyBuf with DER format. + * + * | P256 Header (26 bytes)| 0x04 (1 byte)| Public key X Y values (64 bytes) | + * + * @param[in] KeyID Se050 objectID where to store the private key + * @param[out] keyBuf Buffer containing the public key in DER format + * @param[in] keyBufMaxLen Buffer size in bytes + * @param[in,out] keyLen Public key size in bytes + * + * @return 0 on Failure 1 on Success + */ + int generatePrivateKey(int keyID, byte keyBuf[], size_t keyBufMaxLen, size_t* keyLen); + + /** generatePublicKey + * + * Reads ECCurve_NIST_P256 public key from KeyID. Public key will be available + * inside KeyBuf with DER format. + * + * | P256 Header (26 bytes)| 0x04 (1 byte)| Public key X Y values (64 bytes) | + * + * @param[in] KeyID Se050 objectID where is stored the public key or keypair + * @param[out] keyBuf Buffer containing the public key in DER format + * @param[in] keyBufMaxLen Buffer size in bytes + * @param[in,out] keyLen Public key size in bytes + * + * @return 0 on Failure 1 on Success + */ + int generatePublicKey(int keyID, byte keyBuf[], size_t keyBufMaxLen, size_t* keyLen); + + /** importPublicKey + * + * Imports ECCurve_NIST_P256 public key into KeyID. Public key must be provided + * inside publicKey with DER format. + * + * | P256 Header (26 bytes)| 0x04 (1 byte)| Public key X Y values (64 bytes) | + * + * @param[in] KeyID Se050 objectID where to store the private key + * @param[in] keyBuf Buffer containing the public key in DER format + * @param[in] keyLen Public key size in bytes + * + * @return 0 on Failure 1 on Success + */ + int importPublicKey(int keyID, const byte publicKey[], size_t keyLen); + + /** beginSHA256 + * + * Initialize digest context to start a new SHA256 computation. + * + * + * @return 0 on Failure 1 on Success + */ + int beginSHA256(); + + /** updateSHA256 + * + * Updates SHA256 adding new data to the previous iterations + * + * @param[in] in Input data buffer + * @param[in] inLen Input data length + * + * @return 0 on Failure 1 on Success + */ + int updateSHA256(const byte in[], size_t inLen); + + /** endSHA256 + * + * Get SHA256 data and cleanup digest context + * + * @param[out] out Output data buffer + * @param[in,out] outLen Size of output data buffer, SHA256 length + * + * @return 0 on Failure 1 on Success + */ + int endSHA256(byte out[], size_t* outLen); + + /** SHA256 + * + * One-shot SHA256 + * + * @param[in] in Input data buffer + * @param[in] inLen Input data length + * @param[out] out Output buffer + * @param[in] outMaxLen Output buffer size + * @param[out] outLen SHA256 length + * + * @return 0 on Failure 1 on Success + */ + int SHA256(const byte in[], size_t inLen, byte out[], size_t outMaxLen, size_t* outLen); + + /** Sign + * + * Computes ECDSA signature using key stored in KeyID SE050 object. + * Output buffer is filled with the signature in DER format: + * + * | 0x30 | payloadsize 1 byte | 0x02 | R length 1 byte | padding 0x00 (if length 0x21) | R values 32 bytes + * | 0x02 | S length 1 byte | padding 0x00 (if length 0x21) | S values 32 bytes + * + * SHA256 -> private Key -> Signature + * + * @param[in] keyID SE050 object ID containing the key + * @param[in] hash Input SHA256 used to compute the signature + * @param[in] hashLen SHA256 length + * @param[out] sig Output buffer containint the signature + * @param[in] maxSigLen Output buffer size + * @param[out] sigLen signature length + * + * @return 0 on Failure 1 on Success + */ + int Sign(int keyID, const byte hash[], size_t hashLen, byte sig[], size_t maxSigLen, size_t* sigLen); + + /** Verify + * + * Verify ECDSA signature using key stored in KeyID SE050 object. + * + * Input SHA256 + * ? Match ? + * Signature -> public Key -> Original SHA256 + * + * @param[in] keyID SE050 object ID containing the key + * @param[in] hash Input SHA256 used to compute the signature + * @param[in] hashLen SHA256 length + * @param[in] sig Input buffer containint the signature + * @param[in] sigLen signature length + * + * @return 0 on Failure (Not match) 1 on Success (Match) + */ + int Verify(int keyID, const byte hash[], size_t hashLen, const byte sig[],size_t sigLen); + + /** readBinaryObject + * + * Reads binary data from SE050 object. + * + * @param[in] ObjectId SE050 object ID containing data + * @param[out] data Output data buffer + * @param[in] dataMaxLen Output data buffer size + * @param[out] sig Binary object size + * + * @return 0 on Failure 1 on Success + */ + int readBinaryObject(int ObjectId, byte data[], size_t dataMaxLen, size_t* length); + + /** AES_ECB_encrypt + * + * Enrypts something with AES ECB + * + * @param[in] ObjectId SE050 object ID + * @param[in] data Input data buffer + * @param[in] length Input data buffer size (should be a multiple of 16 bytes) + * @param[out] output Output data buffer + * @param[out] output_length Output data buffer size (same as input) + * + * @return 0 on Failure 1 on Success + */ + int AES_ECB_encrypt(int objectId, const byte data[], size_t data_length, byte output[], size_t *output_len); + + /** AES_ECB_decrypt + * + * Enrypts something with AES ECB + * + * @param[in] ObjectId SE050 object ID + * @param[in] data Input data buffer + * @param[in] length Input data buffer size (should be a multiple of 16 bytes) + * @param[out] output Output data buffer + * @param[out] output_length Output data buffer size (same as input) + * + * @return 0 on Failure 1 on Success + */ + int AES_ECB_decrypt(int objectId, const byte data[], size_t data_length, byte output[], size_t *output_len); + + /** writeAESKey + * + * Writes symmetric key into SE050 object. + * + * @param[in] ObjectId SE050 object ID + * @param[in] data Input data buffer + * @param[in] length Input data buffer size + * + * @return 0 on Failure 1 on Success + */ + int writeAESKey(int ObjectId, const byte data[], size_t length); + + /** writeHMACKey + * + * Writes symmetric key into SE050 object. + * + * @param[in] ObjectId SE050 object ID for the hmac key + * @param[in] data Input data buffer + * @param[in] length Input data buffer size + * + * @return 0 on Failure 1 on Success + */ + int writeHMACKey(int ObjectId, const byte data[], size_t length); + + /** HMAC_Generate + * + * Computes the HMAC digest with SE050 chip + * + * @param[in] objectId SE050 object ID for the hmac key + * @param[in] mac_operation Type of Hash function for HMAC + * @param[in] data Input data buffer + * @param[in] length Input data buffer size + * @param[out] output Output data buffer + * @param[out] output_length Output data buffer size (should be 32 bytes for SHA256) + * + * @return 0 on Failure 1 on Success + */ + int HMAC_Generate(int objectId, uint8_t mac_operation, const byte data[], size_t data_length, byte output[], size_t *output_len); + + + /** writeBinaryObject + * + * Writes binary data into SE050 object. + * + * @param[in] ObjectId SE050 object ID + * @param[in] data Input data buffer + * @param[in] length Input data buffer size + * + * @return 0 on Failure 1 on Success + */ + int writeBinaryObject(int ObjectId, const byte data[], size_t length); + + /** existsBinaryObject + * + * Checks if Object exist + * + * @param[in] ObjectId SE050 object ID + * + * @return 0 on Failure (Not exist) 1 on Success (Exists) + */ + int existsBinaryObject(int objectId); + + /** deleteBinaryObject + * + * Deletes SE050 object + * + * @param[in] ObjectId SE050 object ID + * + * @return 0 on Failure 1 on Success + */ + int deleteBinaryObject(int objectId); + + /** deleteBinaryObject + * + * Deletes all SE050 user objects + * + * @param[in] ObjectId SE050 object ID + * + * @return 0 on Failure 1 on Success + */ + int deleteAllObjects(); + + /* ECCX08 legacy API*/ + + /** generatePrivateKey + * + * Create a new ECCurve_NIST_P256 keypair. Only public key X Y values will be available + * inside publicKey buffer. + * + * | Public key X Y values (64 bytes) | + * + * @param[in] slot Se050 objectID where to store the private key + * @param[out] publicKey Buffer containing the public key X Y values + * + * @return 0 on Failure 1 on Success + */ + int generatePrivateKey(int slot, byte publicKey[]); + + /** generatePublicKey + * + * Reads ECCurve_NIST_P256 public key from KeyID. Public key X Y values will be available + * inside publicKey buffer. + * + * | Public key X Y values (64 bytes) | + * + * @param[in] slot Se050 objectID where is stored the public key or keypair + * @param[out] pubkey Buffer containing the public key X Y values + * + * @return 0 on Failure 1 on Success + */ + int generatePublicKey(int slot, byte publicKey[]); + + /** ecdsaVerify + * + * Verify ECDSA signature using public key. + * + * Input SHA256 + * ? Match ? + * Signature -> public Key -> Original SHA256 + * + * @param[in] message Input SHA256 used to compute the signature 32 bytes + * @param[in] sig Input buffer containint the signature R S values 64bytes + * @param[in] pubkey Public key X Y values 64bytes + * + * @return 0 on Failure (Not match) 1 on Success (Match) + */ + int ecdsaVerify(const byte message[], const byte signature[], const byte pubkey[]); + + /** ecSign + * + * Computes ECDSA signature using key stored in KeyID SE050 object. + * Output buffer is filled with the signature R S values: + * + * | R values 32 bytes | S values 32 bytes | + * + * SHA256 -> private Key -> Signature + * + * @param[in] slot SE050 object ID containing the key + * @param[in] message Input SHA256 used to compute the signature 32 bytes + * @param[out] signature Output buffer containint the signature 64 bytes + * + * @return 0 on Failure 1 on Success + */ + int ecSign(int slot, const byte message[], byte signature[]); + + /** readSlot + * + * Reads binary data from SE050 object. + * + * @param[in] ObjecslottId SE050 object ID containing data + * @param[out] data Output data buffer + * @param[in] length Number of bytes to read + * + * @return 0 on Failure 1 on Success + */ + int readSlot(int slot, byte data[], int length); + + /** writeSlot + * + * Writes binary data into SE050 object. + * + * @param[in] ObjectId SE050 object ID + * @param[in] data Input data buffer + * @param[in] length Number of bytes to write + * + * @return 0 on Failure 1 on Success + */ + int writeSlot(int slot, const byte data[], int length); + + inline int locked() { return 1; } + inline int lock() { return 1; } + inline int writeConfiguration(const byte data[]) { (void)data; return 1; } + inline Se05xSession_t* getSession() { return &_se05x_session; } + +private: + static int getECKeyXyValuesFromDER(byte* derKey, size_t derLen, byte* rawKey, size_t* rawLen); + static int setECKeyXyVauesInDER(const byte* rawKey, size_t rawLen, byte* derKey, size_t* derLen); + static int getECSignatureRsValuesFromDER(byte* derSignature, size_t derLen, byte* rawSignature, size_t* rawLen); + static int setECSignatureRsValuesInDER(const byte* rawSignature, size_t rawLen, byte* signature, size_t* derLen); + + Se05xSession_t _se05x_session; +}; + +extern SE05XClass SE05X; + +#endif From e55e69ac836c59d4e80058df08995f953275dd71 Mon Sep 17 00:00:00 2001 From: Andrea Gilardoni Date: Mon, 30 Mar 2026 17:53:46 +0200 Subject: [PATCH 6/8] adding examples for library --- .../SE05XAESEncryptandDecrypt.ino | 56 +++++++++ .../SE05XAESWriteKey/SE05XAESWriteKey.ino | 33 ++++++ .../SE05XCertificate/SE05XCertificate.ino | 109 ++++++++++++++++++ examples/SE05XHMAC/SE05XHMAC.ino | 54 +++++++++ .../SE05XImportPublicKey.ino | 85 ++++++++++++++ examples/SE05XPrivateKey/SE05XPrivateKey.ino | 42 +++++++ .../SE05XRandomNumber/SE05XRandomNumber.ino | 28 +++++ .../SE05XSerialNumber/SE05XSerialNumber.ino | 27 +++++ .../SE05XSignAndVerify/SE05XSignAndVerify.ino | 81 +++++++++++++ 9 files changed, 515 insertions(+) create mode 100644 examples/SE05XAESEncryptandDecrypt/SE05XAESEncryptandDecrypt.ino create mode 100644 examples/SE05XAESWriteKey/SE05XAESWriteKey.ino create mode 100644 examples/SE05XCertificate/SE05XCertificate.ino create mode 100644 examples/SE05XHMAC/SE05XHMAC.ino create mode 100644 examples/SE05XImportPublicKey/SE05XImportPublicKey.ino create mode 100644 examples/SE05XPrivateKey/SE05XPrivateKey.ino create mode 100644 examples/SE05XRandomNumber/SE05XRandomNumber.ino create mode 100644 examples/SE05XSerialNumber/SE05XSerialNumber.ino create mode 100644 examples/SE05XSignAndVerify/SE05XSignAndVerify.ino diff --git a/examples/SE05XAESEncryptandDecrypt/SE05XAESEncryptandDecrypt.ino b/examples/SE05XAESEncryptandDecrypt/SE05XAESEncryptandDecrypt.ino new file mode 100644 index 0000000..3d1ea50 --- /dev/null +++ b/examples/SE05XAESEncryptandDecrypt/SE05XAESEncryptandDecrypt.ino @@ -0,0 +1,56 @@ +/* + SE05X AES Encrypt and Decrypt + + This sketch uses the SE05X to encrypt and decrypt given data + with an AES key, which was uploaded in the SE05XWriteAESKey + example. This sketch encrypts 32 bytes with AES ECB Mode + and then decrypt this data for comparing the results. + + Circuit: + - Portenta C33 +*/ + +#include + + +const int AES_KEY_ID = 666; +const byte data[32] = { + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f +}; + + +void print_hex(const byte in[], size_t len) { + for (size_t i = 0; i < len; i++) { + Serial.print(in[i] >> 4, HEX); + Serial.print(in[i] & 0x0f, HEX); + } + Serial.println(); +} + +void setup() { + Serial.begin(9600); + while (!Serial); + + + if (!SE05X.begin()) { + Serial.println("Error with secure element"); + while(1); + } + + + size_t encrypted_data_len = 32; + size_t decrypted_data_len = 32; + byte encrypted_data[32]; + byte decrypted_data[32]; + + int status1 = SE05X.AES_ECB_encrypt(AES_KEY_ID, data, sizeof(data), encrypted_data, &encrypted_data_len); + int status2 = SE05X.AES_ECB_decrypt(AES_KEY_ID, encrypted_data, sizeof(data), decrypted_data, &decrypted_data_len); + print_hex(data,32); + print_hex(encrypted_data,32); + print_hex(decrypted_data,32); +} + +void loop() { + +} diff --git a/examples/SE05XAESWriteKey/SE05XAESWriteKey.ino b/examples/SE05XAESWriteKey/SE05XAESWriteKey.ino new file mode 100644 index 0000000..29dd90d --- /dev/null +++ b/examples/SE05XAESWriteKey/SE05XAESWriteKey.ino @@ -0,0 +1,33 @@ +/* + SE05X WriteAESKey + + This sketch uses the SE05X to securely store an AES key. When the key is uploaded to + SE05X, the sketch on the Arduino should be overwritten. + + Circuit: + - Portenta C33 +*/ + +#include + +const int AES_KEY_ID = 666; +const byte aes_key[32] = { + 0xFF, 0x33, 0xFF, 0x33, 0xFF, 0x33, 0xFF, 0x33, 0xFF, 0x33, 0xFF, 0x33, 0x33, 0x33, 0xFF, 0x33, + 0xFF, 0x33, 0xFF, 0x33, 0xFF, 0x33, 0xFF, 0x33, 0xFF, 0x33, 0xFF, 0x33, 0x33, 0x33, 0xFF, 0x44 +}; + +void setup() { + Serial.begin(9600); + + if (!SE05X.begin()) { + Serial.println("Error with secure element"); + while(1); + } + + SE05X.deleteBinaryObject(AES_KEY_ID); + SE05X.writeAESKey(AES_KEY_ID, aes_key, sizeof(aes_key)); +} + +void loop() { + +} diff --git a/examples/SE05XCertificate/SE05XCertificate.ino b/examples/SE05XCertificate/SE05XCertificate.ino new file mode 100644 index 0000000..766e664 --- /dev/null +++ b/examples/SE05XCertificate/SE05XCertificate.ino @@ -0,0 +1,109 @@ +/* + SE05X Certificate + + This sketch uses the SE05X to store device certificate and read it back. + + Circuit: + - Portenta C33 +*/ + +#include + +const byte certificate[410] = { + 0x30 ,0x82 ,0x01 ,0x96 ,0x30 ,0x82 ,0x01 ,0x3D ,0xA0 ,0x03 ,0x02 ,0x01 ,0x02 ,0x02 ,0x10 ,0x37, + 0xFE ,0x48 ,0x92 ,0xE6 ,0xC0 ,0xA0 ,0x64 ,0x68 ,0x91 ,0x66 ,0x5F ,0x7D ,0xE3 ,0x02 ,0xDE ,0x30, + 0x0A ,0x06 ,0x08 ,0x2A ,0x86 ,0x48 ,0xCE ,0x3D ,0x04 ,0x03 ,0x02 ,0x30 ,0x45 ,0x31 ,0x0B ,0x30, + 0x09 ,0x06 ,0x03 ,0x55 ,0x04 ,0x06 ,0x13 ,0x02 ,0x55 ,0x53 ,0x31 ,0x17 ,0x30 ,0x15 ,0x06 ,0x03, + 0x55 ,0x04 ,0x0A ,0x13 ,0x0E ,0x41 ,0x72 ,0x64 ,0x75 ,0x69 ,0x6E ,0x6F ,0x20 ,0x4C ,0x4C ,0x43, + 0x20 ,0x55 ,0x53 ,0x31 ,0x0B ,0x30 ,0x09 ,0x06 ,0x03 ,0x55 ,0x04 ,0x0B ,0x13 ,0x02 ,0x49 ,0x54, + 0x31 ,0x10 ,0x30 ,0x0E ,0x06 ,0x03 ,0x55 ,0x04 ,0x03 ,0x13 ,0x07 ,0x41 ,0x72 ,0x64 ,0x75 ,0x69, + 0x6E ,0x6F ,0x30 ,0x20 ,0x17 ,0x0D ,0x32 ,0x33 ,0x30 ,0x33 ,0x33 ,0x31 ,0x30 ,0x37 ,0x30 ,0x30, + 0x30 ,0x30 ,0x5A ,0x18 ,0x0F ,0x32 ,0x30 ,0x35 ,0x34 ,0x30 ,0x33 ,0x33 ,0x31 ,0x30 ,0x37 ,0x30, + 0x30 ,0x30 ,0x30 ,0x5A ,0x30 ,0x2F ,0x31 ,0x2D ,0x30 ,0x2B ,0x06 ,0x03 ,0x55 ,0x04 ,0x03 ,0x13, + 0x24 ,0x37 ,0x61 ,0x31 ,0x39 ,0x39 ,0x65 ,0x62 ,0x30 ,0x2D ,0x38 ,0x33 ,0x64 ,0x38 ,0x2D ,0x34, + 0x63 ,0x34 ,0x34 ,0x2D ,0x39 ,0x66 ,0x66 ,0x32 ,0x2D ,0x30 ,0x32 ,0x33 ,0x35 ,0x37 ,0x38 ,0x30, + 0x31 ,0x35 ,0x64 ,0x33 ,0x39 ,0x30 ,0x59 ,0x30 ,0x13 ,0x06 ,0x07 ,0x2A ,0x86 ,0x48 ,0xCE ,0x3D, + 0x02 ,0x01 ,0x06 ,0x08 ,0x2A ,0x86 ,0x48 ,0xCE ,0x3D ,0x03 ,0x01 ,0x07 ,0x03 ,0x42 ,0x00 ,0x04, + 0x60 ,0x53 ,0x94 ,0x10 ,0x8C ,0xA6 ,0xB6 ,0xC8 ,0xD2 ,0x05 ,0x22 ,0x61 ,0xD9 ,0x5D ,0xF8 ,0xDB, + 0xD1 ,0xF4 ,0xE4 ,0xAC ,0xC9 ,0x96 ,0x8E ,0xFF ,0xB8 ,0x7E ,0x0D ,0xDC ,0xA1 ,0xB8 ,0x0F ,0x4C, + 0xF5 ,0x66 ,0x68 ,0xF0 ,0xF4 ,0xF0 ,0x70 ,0xF3 ,0xF6 ,0xFD ,0x70 ,0xD2 ,0x7A ,0xFB ,0x20 ,0x70, + 0x30 ,0x82 ,0x5F ,0x34 ,0xF8 ,0x2A ,0x1B ,0xC5 ,0xB1 ,0x38 ,0xE5 ,0xA5 ,0xF7 ,0xC7 ,0xB4 ,0x62, + 0xA3 ,0x23 ,0x30 ,0x21 ,0x30 ,0x1F ,0x06 ,0x03 ,0x55 ,0x1D ,0x23 ,0x04 ,0x18 ,0x30 ,0x16 ,0x80, + 0x14 ,0x5B ,0x3E ,0x2A ,0x6B ,0x8E ,0xC9 ,0xB0 ,0x1A ,0xA8 ,0x54 ,0xE6 ,0x36 ,0x9B ,0x8C ,0x09, + 0xF9 ,0xFC ,0xE1 ,0xB9 ,0x80 ,0x30 ,0x0A ,0x06 ,0x08 ,0x2A ,0x86 ,0x48 ,0xCE ,0x3D ,0x04 ,0x03, + 0x02 ,0x03 ,0x47 ,0x00 ,0x30 ,0x44 ,0x02 ,0x20 ,0x16 ,0x85 ,0x8A ,0x58 ,0x07 ,0x28 ,0xEF ,0x6D, + 0x93 ,0x86 ,0xA0 ,0x0E ,0xC8 ,0xB0 ,0x0A ,0xAD ,0x3B ,0xCE ,0xBB ,0x6A ,0x19 ,0x94 ,0xF9 ,0xD3, + 0x05 ,0x2E ,0x15 ,0xF1 ,0x5E ,0x9F ,0x59 ,0xD2 ,0x02 ,0x20 ,0x45 ,0x30 ,0x88 ,0x1D ,0x24 ,0xDA, + 0xE4 ,0x60 ,0xE2 ,0xD0 ,0x6E ,0x02 ,0xB0 ,0x7D ,0x65 ,0xA8 ,0x09 ,0x63 ,0x0B ,0x44 ,0xBC ,0x24, + 0x1A ,0xE2 ,0xEC ,0x64 ,0x19 ,0xB4 ,0x59 ,0xB8 ,0x09 ,0x78 +}; + +void printBufferHex(const byte input[], size_t inputLength) { + Serial.println(inputLength); + for (size_t i = 0; i < inputLength; i++) { + Serial.print(input[i] >> 4, HEX); + Serial.print(input[i] & 0x0f, HEX); + } + Serial.println(); +} + +void setup() { + Serial.begin(9600); + while (!Serial); + + if (!SE05X.begin()) { + Serial.println("Failed to communicate with SE05X!"); + while (1); + } + + const int certId = 799; + + if (SE05X.existsBinaryObject(certId)) { + Serial.println("Object already present, deleting..."); + SE05X.deleteBinaryObject(certId); + } + + if (SE05X.writeBinaryObject(certId, certificate, sizeof(certificate))) { + Serial.println("Certificate stored into SE050"); + } else { + Serial.println("Failed to store certificate"); + return; + } + + byte buf[512]; + size_t len; + + if (SE05X.readBinaryObject(certId, buf, sizeof(buf), &len)) { + Serial.print("Certificate is: "); + printBufferHex(buf, len); + } else { + Serial.println("Failed to read certificate"); + return; + } + + /* Rewrite some random data using alternative APIs */ + if(SE05X.random(buf, sizeof(buf))) { + Serial.print("New data is: "); + printBufferHex(buf, sizeof(buf)); + } + + if(SE05X.writeSlot(certId, buf, sizeof(buf))) { + Serial.println("Data stored into SE050"); + } else { + Serial.println("Failed to store data"); + return; + } + + if(SE05X.readSlot(certId, buf, sizeof(buf))) { + Serial.print("Readback data is: "); + printBufferHex(buf, sizeof(buf)); + } else { + Serial.println("Failed to read data"); + return; + } + +} + +void loop() { + +} diff --git a/examples/SE05XHMAC/SE05XHMAC.ino b/examples/SE05XHMAC/SE05XHMAC.ino new file mode 100644 index 0000000..fb394ad --- /dev/null +++ b/examples/SE05XHMAC/SE05XHMAC.ino @@ -0,0 +1,54 @@ +/* + SE05X HMAC + + This sketch uses the SE05X to securely store and use an HMAC Key + and calculates the HMAC-SHA512 sum of a given message + + Circuit: + - Portenta C33 +*/ + +#include + +const int HMAC_KEY_ID = 667; +const byte hmac_key[32] = { + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F +}; + + +void print_hex(const byte in[], size_t len) { + for (size_t i = 0; i < len; i++) { + Serial.print(in[i] >> 4, HEX); + Serial.print(in[i] & 0x0f, HEX); + } + Serial.println(); +} + +void setup() { + Serial.begin(9600); + while (!Serial); + + if (!SE05X.begin()) { + Serial.println("Error with secure element"); + while(1); + } + + SE05X.deleteBinaryObject(HMAC_KEY_ID); //remove key if already exists + + SE05X.writeHMACKey(HMAC_KEY_ID, hmac_key, sizeof(hmac_key)); + String message = "This is a test for the Arduino Portenta C33 to test HMAC with SHA512 algorithm. This are some bytes of data, which should work"; + + + byte buffer[64]; + for(int i = 0; i < 64; i++) + buffer[i] = 0; + + size_t len = 64; // 64 byte = 512 bit, length for SHA512 + SE05X.HMAC_Generate(HMAC_KEY_ID, kSE05x_MACAlgo_HMAC_SHA512, (const byte*)message.c_str(), message.length(), buffer, &len); + print_hex(buffer,len); +} + +void loop() { + +} diff --git a/examples/SE05XImportPublicKey/SE05XImportPublicKey.ino b/examples/SE05XImportPublicKey/SE05XImportPublicKey.ino new file mode 100644 index 0000000..ef67dab --- /dev/null +++ b/examples/SE05XImportPublicKey/SE05XImportPublicKey.ino @@ -0,0 +1,85 @@ +/* + SE05X ImportAndVerify + + This sketch uses the SE05X to generate a new EC NIST P-256 keypair + and store it with id 999, then input buffer SHA256 is signed with the private + key. The public key is imported with another id 899 into SE05X and the + signature is checked using the imported public key. + + Circuit: + - Portenta C33 +*/ + +#include + +const byte input[64] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f +}; + +void printBufferHex(const byte input[], size_t inputLength) { + for (size_t i = 0; i < inputLength; i++) { + Serial.print(input[i] >> 4, HEX); + Serial.print(input[i] & 0x0f, HEX); + } + Serial.println(); +} + +void setup() { + Serial.begin(9600); + while (!Serial); + + if (!SE05X.begin()) { + Serial.println("Failed to communicate with SE05X!"); + while (1); + } + + const int privKeyId = 999; + const int publKeyId = 899; + byte derBuf[256]; + size_t derSize; + + SE05X.generatePrivateKey(privKeyId, derBuf, sizeof(derBuf), &derSize); + + // print the input + Serial.print("Input is: "); + printBufferHex(input, sizeof(input)); + + //calculate the input SHA256 + byte sha256[256]; + size_t sha256Len; + SE05X.SHA256(input, sizeof(input), sha256, sizeof(sha256), &sha256Len); + Serial.print("Input SHA256 is: "); + printBufferHex(sha256, sha256Len); + + // calculate the signature, input MUST be SHA256 + byte signature[256]; + size_t signatureLen; + SE05X.Sign(privKeyId, sha256, sha256Len, signature, sizeof(signature), &signatureLen); + + // print the signature + Serial.print("Signature using KeyId "); + Serial.print(privKeyId); + Serial.print(" is: "); + printBufferHex(signature, signatureLen); + + Serial.println(); + + SE05X.importPublicKey(publKeyId, derBuf, derSize); + + // To make the signature verifcation fail, uncomment the next line: + // signature[0] = 0x00; + + // validate the signature + if (SE05X.Verify(publKeyId, sha256, sha256Len, signature, signatureLen)) { + Serial.println("Verified signature successfully :D"); + } else { + Serial.println("oh no! failed to verify signature :("); + } +} + +void loop() { + +} diff --git a/examples/SE05XPrivateKey/SE05XPrivateKey.ino b/examples/SE05XPrivateKey/SE05XPrivateKey.ino new file mode 100644 index 0000000..f4d5eee --- /dev/null +++ b/examples/SE05XPrivateKey/SE05XPrivateKey.ino @@ -0,0 +1,42 @@ +/* + SE05X Private Key + + This sketch uses the SE05X to generate a new EC NIST P-256 keypair + and store it with id 999, then the public key is printed in DER format. + + Circuit: + - Portenta C33 +*/ + +#include +#include + +void printBufferHex(const byte input[], size_t inputLength) { + for (size_t i = 0; i < inputLength; i++) { + Serial.print(input[i] >> 4, HEX); + Serial.print(input[i] & 0x0f, HEX); + } + Serial.println(); +} + +void setup() { + Serial.begin(9600); + while (!Serial); + + if (!SE05X.begin()) { + Serial.println("Failed to communicate with SE05X!"); + while (1); + } + + const int KeyId = 999; + byte derBuf[256]; + size_t derSize; + + SE05X.generatePrivateKey(KeyId, derBuf, sizeof(derBuf), &derSize); + printBufferHex(derBuf, derSize); +} + +void loop() { + + +} diff --git a/examples/SE05XRandomNumber/SE05XRandomNumber.ino b/examples/SE05XRandomNumber/SE05XRandomNumber.ino new file mode 100644 index 0000000..3453d99 --- /dev/null +++ b/examples/SE05XRandomNumber/SE05XRandomNumber.ino @@ -0,0 +1,28 @@ +/* + SE05X Random Number + + This sketch uses the SE05X to generate a random number + every second and print it to the Serial monitor + + Circuit: + - Portenta C33 +*/ + +#include + +void setup() { + Serial.begin(9600); + while (!Serial); + + if (!SE05X.begin()) { + Serial.println("Failed to communicate with SE05X!"); + while (1); + } +} + +void loop() { + Serial.print("Random number = "); + Serial.println(SE05X.random(65535)); + + delay(1000); +} diff --git a/examples/SE05XSerialNumber/SE05XSerialNumber.ino b/examples/SE05XSerialNumber/SE05XSerialNumber.ino new file mode 100644 index 0000000..4b66ee1 --- /dev/null +++ b/examples/SE05XSerialNumber/SE05XSerialNumber.ino @@ -0,0 +1,27 @@ +/* + SE05X serial number + + This sketch prints the SE050 serial number + + Circuit: + - Portenta C33 +*/ + +#include + +void setup() { + Serial.begin(9600); + while (!Serial); + + if (!SE05X.begin()) { + Serial.println("Failed to communicate with SE05X!"); + while (1); + } +} + +void loop() { + Serial.print("S/N = "); + Serial.println(SE05X.serialNumber()); + + delay(1000); +} diff --git a/examples/SE05XSignAndVerify/SE05XSignAndVerify.ino b/examples/SE05XSignAndVerify/SE05XSignAndVerify.ino new file mode 100644 index 0000000..042d9da --- /dev/null +++ b/examples/SE05XSignAndVerify/SE05XSignAndVerify.ino @@ -0,0 +1,81 @@ +/* + SE05X SignAndVerify + + This sketch uses the SE05X to generate a new EC NIST P-256 keypair + and store it with id 999, then input buffer SHA256 is signed with the private + key and verified with the public key. + + Circuit: + - Portenta C33 +*/ + +#include + +const byte input[64] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f +}; + +void printBufferHex(const byte input[], size_t inputLength) { + for (size_t i = 0; i < inputLength; i++) { + Serial.print(input[i] >> 4, HEX); + Serial.print(input[i] & 0x0f, HEX); + } + Serial.println(); +} + +void setup() { + Serial.begin(9600); + while (!Serial); + + if (!SE05X.begin()) { + Serial.println("Failed to communicate with SE05X!"); + while (1); + } + + const int KeyId = 999; + byte derBuf[256]; + size_t derSize; + + SE05X.generatePrivateKey(KeyId, derBuf, sizeof(derBuf), &derSize); + + // print the input + Serial.print("Input is: "); + printBufferHex(input, sizeof(input)); + + //calculate the input SHA256 + byte sha256[256]; + size_t sha256Len; + SE05X.SHA256(input, sizeof(input), sha256, sizeof(sha256), &sha256Len); + Serial.print("Input SHA256 is: "); + printBufferHex(sha256, sha256Len); + + // calculate the signature, input MUST be SHA256 + byte signature[256]; + size_t signatureLen; + SE05X.Sign(KeyId, sha256, sha256Len, signature, sizeof(signature), &signatureLen); + + // print the signature + Serial.print("Signature using KeyId "); + Serial.print(KeyId); + Serial.print(" is: "); + printBufferHex(signature, signatureLen); + + Serial.println(); + + // To make the signature verifcation fail, uncomment the next line: + // signature[0] = 0x00; + + // validate the signature + if (SE05X.Verify(KeyId, sha256, sha256Len, signature, signatureLen)) { + Serial.println("Verified signature successfully :D"); + } else { + Serial.println("oh no! failed to verify signature :("); + } +} + +void loop() { + +} From 9853b9bb46bc019efaa4f46a564ac980a2fc34e5 Mon Sep 17 00:00:00 2001 From: Andrea Gilardoni Date: Mon, 30 Mar 2026 17:54:06 +0200 Subject: [PATCH 7/8] Adding CI for library --- .github/dependabot.yml | 13 +++ .github/workflows/check-arduino.yml | 27 +++++ .github/workflows/compile-examples.yml | 106 +++++++++++++++++ .github/workflows/report-size-deltas.yml | 24 ++++ .github/workflows/spell-check.yml | 16 +++ .github/workflows/sync-labels.yml | 138 +++++++++++++++++++++++ .github/workflows/unit-tests.yml | 56 +++++++++ 7 files changed, 380 insertions(+) create mode 100644 .github/dependabot.yml create mode 100644 .github/workflows/check-arduino.yml create mode 100644 .github/workflows/compile-examples.yml create mode 100644 .github/workflows/report-size-deltas.yml create mode 100644 .github/workflows/spell-check.yml create mode 100644 .github/workflows/sync-labels.yml create mode 100644 .github/workflows/unit-tests.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..03b0e93 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,13 @@ +# See: https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file#about-the-dependabotyml-file +version: 2 + +updates: + # Configure check for outdated GitHub Actions actions in workflows. + # Source: https://github.com/arduino/tooling-project-assets/blob/main/workflow-templates/assets/dependabot/README.md + # See: https://docs.github.com/code-security/dependabot/working-with-dependabot/keeping-your-actions-up-to-date-with-dependabot + - package-ecosystem: github-actions + directory: /.github/workflows/ + schedule: + interval: daily + labels: + - "topic: infrastructure" diff --git a/.github/workflows/check-arduino.yml b/.github/workflows/check-arduino.yml new file mode 100644 index 0000000..19bd32d --- /dev/null +++ b/.github/workflows/check-arduino.yml @@ -0,0 +1,27 @@ +name: Check Arduino + +# See: https://docs.github.com/en/actions/reference/events-that-trigger-workflows +on: + push: + pull_request: + schedule: + # Run every Tuesday at 8 AM UTC to catch breakage caused by new rules added to Arduino Lint. + - cron: "0 8 * * TUE" + workflow_dispatch: + repository_dispatch: + +jobs: + lint: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Arduino Lint + uses: arduino/arduino-lint-action@v1 + with: + compliance: specification + library-manager: update + # Always use this setting for official repositories. Remove for 3rd party projects. + official: true diff --git a/.github/workflows/compile-examples.yml b/.github/workflows/compile-examples.yml new file mode 100644 index 0000000..6935cd6 --- /dev/null +++ b/.github/workflows/compile-examples.yml @@ -0,0 +1,106 @@ +name: Compile Examples + +on: + pull_request: + paths: + - ".github/workflows/compile-examples.yml" + - "examples/**" + - "src/**" + push: + paths: + - ".github/workflows/compile-examples.yml" + - "examples/**" + - "src/**" + +jobs: + build: + runs-on: ubuntu-latest + + env: + # libraries to install for all boards + UNIVERSAL_LIBRARIES: | + - source-path: ./ + # sketch paths to compile (recursive) for all boards + UNIVERSAL_SKETCH_PATHS: | + - examples/SE05XAESEncryptandDecrypt + - examples/SE05XAESWriteKey + - examples/SE05XCertificate + - examples/SE05XHMAC + - examples/SE05XImportPublicKey + - examples/SE05XPrivateKey + - examples/SE05XRandomNumber + - examples/SE05XSerialNumber + - examples/SE05XSignAndVerify + + SKETCHES_REPORTS_PATH: sketches-reports + + strategy: + fail-fast: false + + matrix: + board: + - fqbn: arduino:mbed_portenta:envie_m7 + type: mbed_portenta + artifact-name-suffix: arduino-mbed_portenta-envie_m7 + - fqbn: arduino:mbed_nicla:nicla_vision + type: mbed_nicla + artifact-name-suffix: arduino-mbed_nicla-nicla_vision + - fqbn: arduino:mbed_opta:opta + type: mbed_opta + artifact-name-suffix: arduino-mbed_opta-opta + - fqbn: arduino:mbed_giga:giga + type: mbed_giga + artifact-name-suffix: arduino-mbed_giga-giga + - fqbn: arduino:renesas_portenta:portenta_c33 + type: renesas_portenta + artifact-name-suffix: arduino-renesas_portenta-portenta_c33 + - fqbn: "arduino:zephyr_main:portentah7" + platform-name: arduino:zephyr_main + artifact-name-suffix: arduino-zephyr_main-portentah7 + - fqbn: "arduino:zephyr_main:portentac33" + platform-name: arduino:zephyr_main + artifact-name-suffix: arduino-zephyr_main-portentac33 + - fqbn: "arduino:zephyr_main:giga" + platform-name: arduino:zephyr_main + artifact-name-suffix: arduino-zephyr_main-giga + - fqbn: "arduino:zephyr_main:opta" + platform-name: arduino:zephyr_main + artifact-name-suffix: arduino-zephyr_main-opta + + # make board type-specific customizations to the matrix jobs + include: + - board: + platform-name: arduino:zephyr_main + platforms: | + # Install Arduino Zephyr Boards via Boards Manager + - name: arduino:zephyr_main + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Install ESP32 platform dependencies + if: matrix.board.type == 'esp32' + run: pip3 install pyserial + + - name: Compile examples + uses: arduino/compile-sketches@v1 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + platforms: ${{ matrix.platforms }} + fqbn: ${{ matrix.board.fqbn }} + libraries: | + ${{ env.UNIVERSAL_LIBRARIES }} + ${{ matrix.libraries }} + sketch-paths: | + ${{ env.UNIVERSAL_SKETCH_PATHS }} + ${{ matrix.sketch-paths }} + enable-deltas-report: "true" + sketches-report-path: ${{ env.SKETCHES_REPORTS_PATH }} + + - name: Save memory usage change report as artifact + if: github.event_name == 'pull_request' + uses: actions/upload-artifact@v4 + with: + name: sketches-report-${{ matrix.board.artifact-name-suffix }} + path: ${{ env.SKETCHES_REPORTS_PATH }} diff --git a/.github/workflows/report-size-deltas.yml b/.github/workflows/report-size-deltas.yml new file mode 100644 index 0000000..39e2a0a --- /dev/null +++ b/.github/workflows/report-size-deltas.yml @@ -0,0 +1,24 @@ +name: Report Size Deltas + +# See: https://docs.github.com/en/free-pro-team@latest/actions/reference/events-that-trigger-workflows +on: + push: + paths: + - ".github/workflows/report-size-deltas.yml" + schedule: + # Run at the minimum interval allowed by GitHub Actions. + # Note: GitHub Actions periodically has outages which result in workflow failures. + # In this event, the workflows will start passing again once the service recovers. + - cron: "*/5 * * * *" + workflow_dispatch: + repository_dispatch: + +jobs: + report: + runs-on: ubuntu-latest + steps: + - name: Comment size deltas reports to PRs + uses: arduino/report-size-deltas@v1 + with: + # Regex matching the names of the workflow artifacts created by the "Compile Examples" workflow + sketches-reports-source: ^sketches-report-.+ diff --git a/.github/workflows/spell-check.yml b/.github/workflows/spell-check.yml new file mode 100644 index 0000000..4253ed8 --- /dev/null +++ b/.github/workflows/spell-check.yml @@ -0,0 +1,16 @@ +name: Spell Check + +on: + - push + - pull_request + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Spell check + uses: codespell-project/actions-codespell@master diff --git a/.github/workflows/sync-labels.yml b/.github/workflows/sync-labels.yml new file mode 100644 index 0000000..8c422de --- /dev/null +++ b/.github/workflows/sync-labels.yml @@ -0,0 +1,138 @@ +# Source: https://github.com/arduino/tooling-project-assets/blob/main/workflow-templates/sync-labels.md +name: Sync Labels + +# See: https://docs.github.com/en/actions/reference/events-that-trigger-workflows +on: + push: + paths: + - ".github/workflows/sync-labels.ya?ml" + - ".github/label-configuration-files/*.ya?ml" + pull_request: + paths: + - ".github/workflows/sync-labels.ya?ml" + - ".github/label-configuration-files/*.ya?ml" + schedule: + # Run daily at 8 AM UTC to sync with changes to shared label configurations. + - cron: "0 8 * * *" + workflow_dispatch: + repository_dispatch: + +env: + CONFIGURATIONS_FOLDER: .github/label-configuration-files + CONFIGURATIONS_ARTIFACT: label-configuration-files + +jobs: + check: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Download JSON schema for labels configuration file + id: download-schema + uses: carlosperate/download-file-action@v1 + with: + file-url: https://raw.githubusercontent.com/arduino/tooling-project-assets/main/workflow-templates/assets/sync-labels/arduino-tooling-gh-label-configuration-schema.json + location: ${{ runner.temp }}/label-configuration-schema + + - name: Install JSON schema validator + run: | + sudo npm install \ + --global \ + ajv-cli \ + ajv-formats + + - name: Validate local labels configuration + run: | + # See: https://github.com/ajv-validator/ajv-cli#readme + ajv validate \ + --all-errors \ + -c ajv-formats \ + -s "${{ steps.download-schema.outputs.file-path }}" \ + -d "${{ env.CONFIGURATIONS_FOLDER }}/*.{yml,yaml}" + + download: + needs: check + runs-on: ubuntu-latest + + strategy: + matrix: + filename: + # Filenames of the shared configurations to apply to the repository in addition to the local configuration. + # https://github.com/arduino/tooling-project-assets/blob/main/workflow-templates/assets/sync-labels + - universal.yml + + steps: + - name: Download + uses: carlosperate/download-file-action@v1 + with: + file-url: https://raw.githubusercontent.com/arduino/tooling-project-assets/main/workflow-templates/assets/sync-labels/${{ matrix.filename }} + + - name: Pass configuration files to next job via workflow artifact + uses: actions/upload-artifact@v4 + with: + path: | + *.yaml + *.yml + if-no-files-found: error + name: ${{ env.CONFIGURATIONS_ARTIFACT }} + + sync: + needs: download + runs-on: ubuntu-latest + + steps: + - name: Set environment variables + run: | + # See: https://docs.github.com/en/actions/reference/workflow-commands-for-github-actions#setting-an-environment-variable + echo "MERGED_CONFIGURATION_PATH=${{ runner.temp }}/labels.yml" >> "$GITHUB_ENV" + + - name: Determine whether to dry run + id: dry-run + if: > + github.event_name == 'pull_request' || + ( + ( + github.event_name == 'push' || + github.event_name == 'workflow_dispatch' + ) && + github.ref != format('refs/heads/{0}', github.event.repository.default_branch) + ) + run: | + # Use of this flag in the github-label-sync command will cause it to only check the validity of the + # configuration. + echo "::set-output name=flag::--dry-run" + + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Download configuration files artifact + uses: actions/download-artifact@v4 + with: + name: ${{ env.CONFIGURATIONS_ARTIFACT }} + path: ${{ env.CONFIGURATIONS_FOLDER }} + + - name: Remove unneeded artifact + uses: geekyeggo/delete-artifact@v5 + with: + name: ${{ env.CONFIGURATIONS_ARTIFACT }} + + - name: Merge label configuration files + run: | + # Merge all configuration files + shopt -s extglob + cat "${{ env.CONFIGURATIONS_FOLDER }}"/*.@(yml|yaml) > "${{ env.MERGED_CONFIGURATION_PATH }}" + + - name: Install github-label-sync + run: sudo npm install --global github-label-sync + + - name: Sync labels + env: + GITHUB_ACCESS_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + # See: https://github.com/Financial-Times/github-label-sync + github-label-sync \ + --labels "${{ env.MERGED_CONFIGURATION_PATH }}" \ + ${{ steps.dry-run.outputs.flag }} \ + ${{ github.repository }} diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml new file mode 100644 index 0000000..f489ca6 --- /dev/null +++ b/.github/workflows/unit-tests.yml @@ -0,0 +1,56 @@ +name: Unit Tests + +on: + pull_request: + paths: + - ".github/workflows/unit-tests.yml" + - 'extras/test/**' + - 'src/**' + + push: + paths: + - ".github/workflows/unit-tests.yml" + - 'extras/test/**' + - 'src/**' + +jobs: + test: + name: Run unit tests + runs-on: ubuntu-latest + + env: + COVERAGE_DATA_PATH: extras/coverage-data/coverage.info + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - uses: arduino/cpp-test-action@main + with: + runtime-paths: | + - extras/test/build/bin/testArduinoCloudUtils + coverage-exclude-paths: | + - '*/extras/test/*' + - '/usr/*' + coverage-data-path: ${{ env.COVERAGE_DATA_PATH }} + + # A token is used to avoid intermittent spurious job failures caused by rate limiting. + - name: Set up Codecov upload token + run: | + if [[ "${{ github.repository }}" == "arduino-libraries/Arduino_CloudUtils" ]]; then + # In order to avoid uploads of data from forks, only use the token for runs in the parent repo. + # Token is intentionally exposed. + # See: https://community.codecov.com/t/upload-issues-unable-to-locate-build-via-github-actions-api/3954 + CODECOV_TOKEN="bf6a7f2a-362b-43a8-ac34-c0fd5ef11d6a" + else + # codecov/codecov-action does unauthenticated upload if empty string is passed via the `token` input. + CODECOV_TOKEN="" + fi + echo "CODECOV_TOKEN=$CODECOV_TOKEN" >> "$GITHUB_ENV" + + - name: Upload coverage report to Codecov + uses: codecov/codecov-action@v3 + with: + file: "${{ env.COVERAGE_DATA_PATH }}" + fail_ci_if_error: true + token: ${{ env.CODECOV_TOKEN }} From 610ae1915bdbe4e248f9b2f8fc91625feb456083 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 Mar 2026 16:05:09 +0000 Subject: [PATCH 8/8] Bump geekyeggo/delete-artifact from 5 to 6 in /.github/workflows Bumps [geekyeggo/delete-artifact](https://github.com/geekyeggo/delete-artifact) from 5 to 6. - [Release notes](https://github.com/geekyeggo/delete-artifact/releases) - [Changelog](https://github.com/GeekyEggo/delete-artifact/blob/main/CHANGELOG.md) - [Commits](https://github.com/geekyeggo/delete-artifact/compare/v5...v6) --- updated-dependencies: - dependency-name: geekyeggo/delete-artifact dependency-version: '6' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/sync-labels.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/sync-labels.yml b/.github/workflows/sync-labels.yml index 8c422de..1e1a9a5 100644 --- a/.github/workflows/sync-labels.yml +++ b/.github/workflows/sync-labels.yml @@ -114,7 +114,7 @@ jobs: path: ${{ env.CONFIGURATIONS_FOLDER }} - name: Remove unneeded artifact - uses: geekyeggo/delete-artifact@v5 + uses: geekyeggo/delete-artifact@v6 with: name: ${{ env.CONFIGURATIONS_ARTIFACT }}