diff --git a/.github/workflows/compile-examples.yml b/.github/workflows/compile-examples.yml index 5da349cf5..bffbffe9f 100644 --- a/.github/workflows/compile-examples.yml +++ b/.github/workflows/compile-examples.yml @@ -95,6 +95,7 @@ jobs: - libraries/WiFiS3 - libraries/OTAUpdate - libraries/OPAMP + - libraries/SoftwareATSE - libraries/Preferences - board: fqbn: "arduino-git:renesas:minima" diff --git a/libraries/SoftwareATSE/.unor4_only b/libraries/SoftwareATSE/.unor4_only new file mode 100644 index 000000000..e69de29bb diff --git a/libraries/SoftwareATSE/examples/SATSECertificate/SATSECertificate.ino b/libraries/SoftwareATSE/examples/SATSECertificate/SATSECertificate.ino new file mode 100644 index 000000000..54c54e82e --- /dev/null +++ b/libraries/SoftwareATSE/examples/SATSECertificate/SATSECertificate.ino @@ -0,0 +1,85 @@ +/* + Software Secure Element Certificate + + This sketch uses the Software Secure Element to store device certificate and read it back. + + Circuit: + - UNO R4 WiFi +*/ + +#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 (!SATSE.begin()) { + Serial.println("Failed to communicate with Software Secure Element!"); + Serial.println("Make sure your WiFi firmware version is greater than 0.3.0"); + while (1); + } + + const int certId = 799; + + if(SATSE.writeSlot(certId, certificate, sizeof(certificate))) { + Serial.println("Data stored"); + } else { + Serial.println("Failed to store data"); + return; + } + + byte buf[512]; + int ret = 0; + + if((ret = SATSE.readSlot(certId, buf, sizeof(buf))) > 0) { + Serial.print("Readback data is: "); + int len = (buf[2] << 8) + buf[3] + 4; + printBufferHex(buf, len); + } else { + Serial.println("Failed to read data"); + return; + } + +} + +void loop() { + +} diff --git a/libraries/SoftwareATSE/examples/SATSEPrivateKey/SATSEPrivateKey.ino b/libraries/SoftwareATSE/examples/SATSEPrivateKey/SATSEPrivateKey.ino new file mode 100644 index 000000000..fe33374da --- /dev/null +++ b/libraries/SoftwareATSE/examples/SATSEPrivateKey/SATSEPrivateKey.ino @@ -0,0 +1,44 @@ +/* + Software Secure Element Private Key + + This sketch uses the Software Secure Element to generate a new EC NIST P-256 keypair + and store it with id 999, then the public key is printed in raw format. + + Circuit: + - UNO R4 WiFi +*/ + +#include +#include + +const int KeyId = 999; +byte rawBuf[64]; + +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 (!SATSE.begin()) { + Serial.println("Failed to communicate with Software Secure Element!"); + Serial.println("Make sure your WiFi firmware version is greater than 0.3.0"); + while (1); + } + + SATSE.generatePrivateKey(KeyId, rawBuf); + printBufferHex(rawBuf, sizeof(rawBuf)); + +} + +void loop() { + SATSE.generatePublicKey(KeyId, rawBuf); + printBufferHex(rawBuf, sizeof(rawBuf)); + delay(5000); +} diff --git a/libraries/SoftwareATSE/examples/SATSERandomNumber/SATSERandomNumber.ino b/libraries/SoftwareATSE/examples/SATSERandomNumber/SATSERandomNumber.ino new file mode 100644 index 000000000..fca8f40ad --- /dev/null +++ b/libraries/SoftwareATSE/examples/SATSERandomNumber/SATSERandomNumber.ino @@ -0,0 +1,29 @@ +/* + Software Secure Element Random Number + + This sketch uses the Software Secure Element to generate a random number + every second and print it to the Serial monitor + + Circuit: + - UNO R4 WiFi +*/ + +#include + +void setup() { + Serial.begin(9600); + while (!Serial); + + if (!SATSE.begin()) { + Serial.println("Failed to communicate with Software Secure Element!"); + Serial.println("Make sure your WiFi firmware version is greater than 0.3.0"); + while (1); + } +} + +void loop() { + Serial.print("Random number = "); + Serial.println(SATSE.random(65535)); + + delay(1000); +} diff --git a/libraries/SoftwareATSE/examples/SATSESerialNumber/SATSESerialNumber.ino b/libraries/SoftwareATSE/examples/SATSESerialNumber/SATSESerialNumber.ino new file mode 100644 index 000000000..57a454587 --- /dev/null +++ b/libraries/SoftwareATSE/examples/SATSESerialNumber/SATSESerialNumber.ino @@ -0,0 +1,29 @@ +/* + Software Secure Element serial number + + This sketch prints the Software Secure Element serial number: + ESP32-S3-MINI-1 efuse mac address + + Circuit: + - UNO R4 WiFi +*/ + +#include + +void setup() { + Serial.begin(9600); + while (!Serial); + + if (!SATSE.begin()) { + Serial.println("Failed to communicate with Software Secure Element!"); + Serial.println("Make sure your WiFi firmware version is greater than 0.3.0"); + while (1); + } +} + +void loop() { + Serial.print("S/N = "); + Serial.println(SATSE.serialNumber()); + + delay(1000); +} diff --git a/libraries/SoftwareATSE/examples/SATSESignAndVerify/SATSESignAndVerify.ino b/libraries/SoftwareATSE/examples/SATSESignAndVerify/SATSESignAndVerify.ino new file mode 100644 index 000000000..25ce45f12 --- /dev/null +++ b/libraries/SoftwareATSE/examples/SATSESignAndVerify/SATSESignAndVerify.ino @@ -0,0 +1,84 @@ +/* + Software Secure Element SignAndVerify + + This sketch uses the Software Secure Element 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: + - UNO R4 WiFi +*/ + +#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 (!SATSE.begin()) { + Serial.println("Failed to communicate with Software Secure Element!"); + Serial.println("Make sure your WiFi firmware version is greater than 0.3.0"); + while (1); + } + + const int KeyId = 999; + byte pubKey[256]; + + SATSE.generatePrivateKey(KeyId, pubKey); + + // print the public key + Serial.print("Public key is: "); + printBufferHex(pubKey, 64); + + // print the input + Serial.print("Input is: "); + printBufferHex(input, sizeof(input)); + + // calculate the input SHA256 + byte sha256[256]; + size_t sha256Len; + SATSE.SHA256(input, sizeof(input), sha256); + Serial.print("Input SHA256 is: "); + printBufferHex(sha256, 32); + + // calculate the signature, input MUST be SHA256 + byte signature[256]; + SATSE.ecSign(KeyId, sha256, signature); + + // print the signature + Serial.print("Signature using KeyId "); + Serial.print(KeyId); + Serial.print(" is: "); + printBufferHex(signature, 64); + + Serial.println(); + + // To make the signature verifcation fail, uncomment the next line: + // signature[0] = 0x00; + + // validate the signature + if (SATSE.ecdsaVerify(sha256, signature, pubKey)) { + Serial.println("Verified signature successfully :D"); + } else { + Serial.println("oh no! failed to verify signature :("); + } +} + +void loop() { + +} diff --git a/libraries/SoftwareATSE/library.properties b/libraries/SoftwareATSE/library.properties new file mode 100644 index 000000000..c4820efeb --- /dev/null +++ b/libraries/SoftwareATSE/library.properties @@ -0,0 +1,9 @@ +name=SoftwareATSE +version=0.0.1 +author=Arduino +maintainer=Arduino +sentence=Arduino Library implementing base secure element functions in software +paragraph= +category=Communication +url= +architectures=renesas,renesas_uno \ No newline at end of file diff --git a/libraries/SoftwareATSE/src/SoftwareATSE.cpp b/libraries/SoftwareATSE/src/SoftwareATSE.cpp new file mode 100644 index 000000000..43990aee3 --- /dev/null +++ b/libraries/SoftwareATSE/src/SoftwareATSE.cpp @@ -0,0 +1,249 @@ +/* + SoftwareATSE.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 "SoftwareATSE.h" +#include "Modem.h" + +using namespace std; + +static uint8_t constexpr SATSE_SHA256_LENGTH = 32; +static uint8_t constexpr SATSE_EC256_SIGNATURE_LENGTH = 64; +static uint8_t constexpr SATSE_EC256_PUB_KEY_LENGTH = 64; + +SoftwareATSEClass::SoftwareATSEClass() { + +} + +SoftwareATSEClass::~SoftwareATSEClass() { + end(); +} + +int SoftwareATSEClass::begin(const char * name, bool readOnly, const char* partition_label) +{ + string res = ""; + modem.begin(); + if (name != nullptr && strlen(name) > 0) { + if (modem.write(string(PROMPT(_SOFTSE_BEGIN)), res, "%s%s,%d,%s\r\n", CMD_WRITE(_SOFTSE_BEGIN), name, readOnly, partition_label != NULL ? partition_label : "")) { + return atoi(res.c_str()); + } + } + return 0; +} + +void SoftwareATSEClass::end() +{ + string res = ""; + modem.write(string(PROMPT(_SOFTSE_END)), res, "%s", CMD(_SOFTSE_END)); +} + +void SoftwareATSEClass::debug(Stream &u, uint8_t level) +{ + modem.debug(u,level); +} + +String SoftwareATSEClass::serialNumber() +{ + string res = ""; + modem.read_using_size(); + if (modem.write(string(PROMPT(_SOFTSE_SERIAL)), res, "%s", CMD(_SOFTSE_SERIAL))) { + if (res.size()) { + String result = (char*)NULL; + result.reserve(res.size() * 2); + + for (size_t i = 0; i < res.size(); i++) { + byte b = res.data()[i]; + + if (b < 16) { + result += "0"; + } + result += String(b, HEX); + } + result.toUpperCase(); + return result; + } + } + return ""; +} + +long SoftwareATSEClass::random(long max) +{ + return random(0, max); +} + +long SoftwareATSEClass::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 SoftwareATSEClass::random(byte data[], size_t length) +{ + string res = ""; + if (data != nullptr && length > 0) { + modem.read_using_size(); + if (modem.write(string(PROMPT(_SOFTSE_RND)), res, "%s%d\r\n", CMD_WRITE(_SOFTSE_RND), length)) { + if (res.size() >= length) { + memcpy(data, (uint8_t*)&res[0], length); + return 1; + } + } + } + return 0; +} + +int SoftwareATSEClass::generatePrivateKey(int keyID, byte publicKey[]) +{ + string res = ""; + if (publicKey != nullptr) { + modem.read_using_size(); + if (modem.write(string(PROMPT(_SOFTSE_PRI_KEY)), res, "%s%d\r\n", CMD_WRITE(_SOFTSE_PRI_KEY), keyID)) { + if (res.size() == SATSE_EC256_PUB_KEY_LENGTH) { + memcpy(publicKey, (uint8_t*)&res[0], SATSE_EC256_PUB_KEY_LENGTH); + return 1; + } + } + } + return 0; +} + +int SoftwareATSEClass::generatePublicKey(int keyID, byte publicKey[]) +{ + string res = ""; + if (publicKey != nullptr) { + modem.read_using_size(); + if (modem.write(string(PROMPT(_SOFTSE_PUB_KEY)), res, "%s%d\r\n", CMD_WRITE(_SOFTSE_PUB_KEY), keyID)) { + if (res.size() == SATSE_EC256_PUB_KEY_LENGTH) { + memcpy(publicKey, (uint8_t*)&res[0], SATSE_EC256_PUB_KEY_LENGTH); + return 1; + } + } + } + return 0; +} + +int SoftwareATSEClass::ecSign(int slot, const byte message[], byte signature[]) +{ + string res = ""; + if ( message != nullptr) { + modem.write_nowait(string(PROMPT(_SOFTSE_S_V_BUF_SET)), res, "%s%d\r\n", CMD_WRITE(_SOFTSE_S_V_BUF_SET), SATSE_SHA256_LENGTH); + if(!modem.passthrough(message, SATSE_SHA256_LENGTH)) { + return 0; + } + } + + if (signature != nullptr) { + modem.read_using_size(); + if (modem.write(string(PROMPT(_SOFTSE_SIGN_GET)), res, "%s%d\r\n", CMD_WRITE(_SOFTSE_SIGN_GET), slot)) { + if (res.size() == SATSE_EC256_SIGNATURE_LENGTH) { + memcpy(signature, (uint8_t*)&res[0], SATSE_EC256_SIGNATURE_LENGTH); + return 1; + } + } + } + return 0; +} + +int SoftwareATSEClass::ecdsaVerify(const byte message[], const byte signature[], const byte pubkey[]) +{ + string res = ""; + if ( message != nullptr && signature!= nullptr) { + static const byte len = SATSE_SHA256_LENGTH + SATSE_EC256_SIGNATURE_LENGTH + SATSE_EC256_PUB_KEY_LENGTH; + byte tmp[len]; + memcpy(tmp, message, SATSE_SHA256_LENGTH); + memcpy(&tmp[SATSE_SHA256_LENGTH], signature, SATSE_EC256_SIGNATURE_LENGTH); + memcpy(&tmp[SATSE_SHA256_LENGTH + SATSE_EC256_SIGNATURE_LENGTH], pubkey, SATSE_EC256_PUB_KEY_LENGTH); + modem.write_nowait(string(PROMPT(_SOFTSE_S_V_BUF_SET)), res, "%s%d\r\n", CMD_WRITE(_SOFTSE_S_V_BUF_SET), len); + if(!modem.passthrough(tmp, len)) { + return 0; + } + } + + if (signature != nullptr) { + if (modem.write(string(PROMPT(_SOFTSE_VERIFY_GET)), res, "%s", CMD(_SOFTSE_VERIFY_GET))) { + return atoi(res.c_str()) == 0 ? 1: 0; + } + } + return 0; +} + +int SoftwareATSEClass::SHA256(const uint8_t *buffer, size_t size, uint8_t *digest) { + string res = ""; + if ( buffer != nullptr) { + modem.write_nowait(string(PROMPT(_SOFTSE_S_V_BUF_SET)), res, "%s%d\r\n", CMD_WRITE(_SOFTSE_S_V_BUF_SET), size); + if(!modem.passthrough(buffer, size)) { + return 0; + } + } + + if (digest != nullptr) { + modem.read_using_size(); + if (modem.write(string(PROMPT(_SOFTSE_SHA256_GET)), res, "%s", CMD(_SOFTSE_SHA256_GET))) { + if (res.size() == SATSE_SHA256_LENGTH) { + memcpy(digest, (uint8_t*)&res[0], SATSE_SHA256_LENGTH); + return 1; + } + } + } + return 0; +} + +int SoftwareATSEClass::readSlot(int slot, byte data[], int length) +{ + string res = ""; + if (data != nullptr) { + modem.read_using_size(); + if (modem.write(string(PROMPT(_SOFTSE_READ_SLOT)), res, "%s%d\r\n", CMD_WRITE(_SOFTSE_READ_SLOT), slot)) { + if (res.size()) { + int len = res.size() > length ? length : res.size(); + memcpy(data, (uint8_t*)&res[0], len); + return 1; + } + } + } + return 0; +} + +int SoftwareATSEClass::writeSlot(int slot, const byte data[], int length) +{ + string res = ""; + if ( data != nullptr && length > 0) { + modem.write_nowait(string(PROMPT(_SOFTSE_WRITE_SLOT)), res, "%s%d,%d\r\n", CMD_WRITE(_SOFTSE_WRITE_SLOT), slot, length); + if(modem.passthrough(data, length)) { + return 1; + } + } + return 0; +} + +SoftwareATSEClass SATSE; diff --git a/libraries/SoftwareATSE/src/SoftwareATSE.h b/libraries/SoftwareATSE/src/SoftwareATSE.h new file mode 100644 index 000000000..030d2fdb8 --- /dev/null +++ b/libraries/SoftwareATSE/src/SoftwareATSE.h @@ -0,0 +1,154 @@ +/* + SoftwareATSE.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 _SOFTWARE_ATSE_H_ +#define _SOFTWARE_ATSE_H_ + +#include + + +class SoftwareATSEClass +{ +public: + SoftwareATSEClass(); + virtual ~SoftwareATSEClass(); + + int begin(const char * name = "se", bool readOnly = false, const char* partition_label = NULL); + void end(); + + void debug(Stream &u, uint8_t level = 0); + + String serialNumber(); + + long random(long min, long max); + long random(long max); + int random(byte data[], size_t length); + + /** generatePrivateKey + * + * Create a new ECCurve_NIST_P256 keypair and stores it in the WiFi chip NVS. + * Public key X Y values will be available inside publicKey buffer that should + * be at least 64 bytes long. + * + * | Public key X Y values (64 bytes) | + * + * @param[in] slot 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 that should be at least 64 bytes long. + * + * | Public key X Y values (64 bytes) | + * + * @param[in] slot objectID where is stored the 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 signature buffer is filled with the signature R S values + * and should be at least 64 bytes long: + * + * | R values 32 bytes | S values 32 bytes | + * + * SHA256 -> private Key -> Signature + * + * @param[in] slot 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[]); + + /** SHA256 + * + * One-shot SHA256 + * + * @param[in] buffer Input data buffer + * @param[in] size Input data length + * @param[out] digest Output buffer should be at least 32 bytes long + * + * @return 0 on Failure 1 on Success + */ + int SHA256(const uint8_t *buffer, size_t size, uint8_t *digest); + + /** readSlot + * + * Reads binary data from Software AT Secure Element object. + * + * @param[in] slot 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 Software AT Secure Element object. + * + * @param[in] slot 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 config[] = nullptr) { (void)config; return 1; } + + +private: + +}; + +extern SoftwareATSEClass SATSE; + +#endif