github.com/arduino/arduino-cloud-cli@v0.0.0-20240517070944-e7a449561083/firmware/provision/CryptoProvision/CryptoProvision.ino (about)

     1  /*
     2     This file is part of ArduinoIoTCloud.
     3  
     4     Copyright 2019 ARDUINO SA (http://www.arduino.cc/)
     5  
     6     This software is released under the GNU General Public License version 3,
     7     which covers the main part of arduino-cli.
     8     The terms of this license can be found at:
     9     https://www.gnu.org/licenses/gpl-3.0.en.html
    10  
    11     You can be released from the requirements of the above licenses by purchasing
    12     a commercial license. Buying such a license is mandatory if you want to modify or
    13     otherwise use the software for commercial activities involving the Arduino
    14     software without disclosing the source code of your own applications. To purchase
    15     a commercial license, send an email to license@arduino.cc.
    16  */
    17  
    18  #include <ArduinoIoTCloud.h>
    19  #include "ECCX08TLSConfig.h"
    20  
    21  #include "uCRC16Lib.h"
    22  const uint8_t SKETCH_INFO[] = {0x55, 0xaa, 0x01, 0x00, 0x01, 0xff, 0xaa, 0x55};
    23  const bool DEBUG = true;
    24  
    25  ArduinoIoTCloudCertClass Cert;
    26  CryptoUtil Crypto;
    27  
    28  enum class MESSAGE_TYPE { NONE = 0, COMMAND, DATA, RESPONSE };
    29  enum class COMMAND {
    30    GET_SKETCH_INFO = 1,
    31    GET_CSR,
    32    SET_LOCKED,
    33    GET_LOCKED,
    34    WRITE_CRYPTO,
    35    BEGIN_STORAGE,
    36    SET_DEVICE_ID,
    37    SET_YEAR,
    38    SET_MONTH,
    39    SET_DAY,
    40    SET_HOUR,
    41    SET_VALIDITY,
    42    SET_CERT_SERIAL,
    43    SET_AUTH_KEY,
    44    SET_SIGNATURE,
    45    END_STORAGE,
    46    RECONSTRUCT_CERT
    47  
    48  };
    49  enum class PROVISIONING_ERROR : uint8_t {
    50    NONE = 0,
    51    SYNC,
    52    LOCK_FAIL,
    53    LOCK_SUCCESS,
    54    WRITE_CONFIG_FAIL,
    55    CRC_FAIL,
    56    CSR_GEN_FAIL,
    57    CSR_GEN_SUCCESS,
    58    SKETCH_UNKNOWN,
    59    GENERIC,
    60    NO_DATA
    61  };
    62  
    63  enum class RESPONSE {
    64    RESPONSE_NONE = 1,
    65    RESPONSE_ACK,
    66    RESPONSE_NACK,
    67    RESPONSE_ERROR
    68  };
    69  
    70  #define MAX_PAYLOAD_LENGTH 130
    71  #define CRC_SIZE 2
    72  uint8_t
    73  payloadBuffer[MAX_PAYLOAD_LENGTH +
    74                CRC_SIZE]; // max 64 bytes will be stored before next round
    75  uint8_t msgStart[] = {0x55, 0xaa};
    76  uint8_t msgEnd[] = {0xaa, 0x55};
    77  MESSAGE_TYPE msgType = MESSAGE_TYPE::NONE;
    78  uint16_t msgLength = 0;
    79  uint16_t msgByteIndex = 0;
    80  // message is structured as such {START H}{START L}{TYPE}{LENGTH H}{LENGHT L}{PAYLOAD}{PAYLOAD CRC H}{PAYLOAD CRC L}{END}
    81  // minimum length is by commands with no payload 2+1+1+1+1+2+2 => 10
    82  
    83  const uint16_t minMessageLength = 10;
    84  
    85  enum class MACHINE_STATE {
    86    IDLE = 0,
    87    RECEIVING_PAYLOAD,
    88    PROCESS_CMD,
    89    PROCESS_MSG,
    90    PROCESS_MSG_END,
    91    SENDING,
    92    WRITING,
    93    LOCKING
    94  };
    95  
    96  
    97  MACHINE_STATE machineState = MACHINE_STATE::IDLE;
    98  uint8_t deviceIDBytes[72];
    99  String deviceIDstring;
   100  String csr;
   101  
   102  String issueYear;
   103  String issueMonth;
   104  String issueDay;
   105  String issueHour;
   106  String expireYears;
   107  String authorityKeyIdentifier;
   108  String signature;
   109  
   110  void setup() {
   111  
   112    Serial.begin(57600);
   113    Serial1.begin(115200);
   114    uint8_t cryptoInitOK = cryptoInit();
   115    if (!cryptoInitOK) {
   116      Serial1.println("FAILED TO DETECT CRYPTO ELEMENT");
   117      while (1);
   118    } else {
   119      Serial1.println("Crypto-element initialized");
   120    }
   121    if (cryptoLock() != PROVISIONING_ERROR::LOCK_SUCCESS) {
   122      Serial1.println("FAILED TO LOCK CRYPTO ELEMENT");
   123      while (1);
   124    } else {
   125      Serial1.println("Crypto-element locked");
   126    }
   127  }
   128  
   129  void loop() {
   130    if (machineState == MACHINE_STATE::IDLE) {
   131      waitForMessage();
   132  
   133    }
   134    if (machineState == MACHINE_STATE::RECEIVING_PAYLOAD) {
   135      payloadBuffer[msgByteIndex] = (uint8_t)Serial.read();
   136      Serial1.print(payloadBuffer[msgByteIndex], HEX);
   137      Serial1.print(" ");
   138      msgByteIndex++;
   139      if (msgByteIndex >= msgLength) {
   140        changeState(MACHINE_STATE::PROCESS_MSG_END);
   141      }
   142    }
   143    if (machineState == MACHINE_STATE::PROCESS_MSG_END) {
   144      checkMessageEnd();
   145    }
   146  
   147  }
   148  
   149  void waitForMessage() {
   150    if (Serial.available() >= minMessageLength) {
   151      uint8_t msgStartBuffer[2];
   152      uint8_t byteIn;
   153      bool msgStartByteOK = false;
   154      while (!msgStartByteOK && Serial.available()) {
   155        byteIn = (uint8_t)Serial.read();
   156        if (byteIn == msgStart[0]) {
   157          msgStartBuffer[0] = byteIn;
   158          byteIn = (uint8_t)Serial.read();
   159          if (byteIn == msgStart[1]) {
   160            msgStartBuffer[1] = byteIn;
   161            msgStartByteOK = true;
   162          }
   163        }
   164      }
   165  
   166      //Serial.readBytes(msgStartBuffer, sizeof(msgStart));
   167      if (memcmp(msgStartBuffer, msgStart, sizeof(msgStart)) == 0) {
   168        Serial1.println("message START");
   169        msgType = (MESSAGE_TYPE)Serial.read();
   170        uint8_t lengthH = (uint8_t)Serial.read();
   171        uint8_t lengthL = (uint8_t)Serial.read();
   172        Serial1.print(lengthH);
   173        Serial1.print(" - ");
   174        Serial1.println(lengthL);
   175        msgLength = lengthH << 8 | lengthL;
   176  
   177        Serial1.print("TYPE: ");
   178        Serial1.println((int)msgType);
   179        Serial1.print("LENGTH: ");
   180        Serial1.println((int)msgLength);
   181  
   182        //delay(1000);
   183  
   184        if (msgLength > 0) {
   185          changeState(MACHINE_STATE::RECEIVING_PAYLOAD);
   186        } else {
   187          changeState(MACHINE_STATE::PROCESS_MSG_END);
   188        }
   189      }
   190    }
   191  }
   192  void checkMessageEnd() {
   193    if (Serial.available() >= sizeof(msgEnd)) {
   194      uint8_t msgEndBuffer[2];
   195      Serial.readBytes((char*)msgEndBuffer, sizeof(msgEnd));
   196      if (memcmp(msgEndBuffer, msgEnd, sizeof(msgEnd)) == 0) {
   197        Serial1.println("message END");
   198        if (processMessage() == PROVISIONING_ERROR::CRC_FAIL) {
   199          Serial1.println("ERROR:: CRC FAIL");
   200          sendData(MESSAGE_TYPE::RESPONSE, (char*)RESPONSE::RESPONSE_NACK, 1);
   201        }
   202        //delay(2000);
   203        // Serial.end();
   204        // for(;;) {
   205        //   delay(500);
   206        // };
   207        changeState(MACHINE_STATE::IDLE);
   208      }
   209    }
   210  }
   211  
   212  PROVISIONING_ERROR processMessage() {
   213    bool checkSumOK = false;
   214    if (msgLength > 0) {
   215      // checksum verification
   216      // uint8_t csHI = payloadBuffer[msgLength - 2];
   217      // uint8_t csLO = payloadBuffer[msgLength - 1];
   218      // char receivedCS[] = {csHI, csLO};
   219      uint16_t receivedCRC = ((uint16_t)payloadBuffer[msgLength - 2] << 8 | payloadBuffer[msgLength - 1]);
   220      uint16_t computedCRC = uCRC16Lib::calculate((char *)payloadBuffer, msgLength - CRC_SIZE);
   221      Serial1.print("DATA CRC: ");
   222      Serial1.println(receivedCRC, HEX);
   223  
   224      Serial1.print("COMPUTED CRC: ");
   225      Serial1.println(computedCRC, HEX);
   226      if (receivedCRC != computedCRC) return PROVISIONING_ERROR::CRC_FAIL;
   227      Serial1.println("CRC aligned");
   228      checkSumOK = true;
   229    }
   230  
   231    if (msgType == MESSAGE_TYPE::COMMAND) {
   232      processCommand();
   233    }
   234    if (msgType == MESSAGE_TYPE::DATA) {
   235      processRawData(checkSumOK);
   236    }
   237    return PROVISIONING_ERROR::NONE;
   238  }
   239  
   240  void processCommand() {
   241    Serial1.print("%%%%% ");
   242    Serial1.println(">> processing command");
   243    COMMAND cmdCode = (COMMAND)payloadBuffer[0];
   244  
   245    if (cmdCode == COMMAND::GET_SKETCH_INFO) {
   246      Serial1.println("get sketch info");
   247      char response[] = {char(RESPONSE::RESPONSE_ACK)};
   248      sendData(MESSAGE_TYPE::RESPONSE, response, 1);
   249    }
   250    if (cmdCode == COMMAND::GET_CSR) {
   251      // extract payload from [1] to [payloadLength]
   252      // this will be the device_id used to generate a valid CSR
   253      Serial1.println("get CSR");
   254      for (uint8_t i = 1; i < msgLength - CRC_SIZE; i++) {
   255        deviceIDBytes[i - 1] = payloadBuffer[i];
   256      }
   257  
   258      // clear device ID string
   259      // this will be sent to the host
   260      deviceIDstring = "";
   261      Serial1.print("Device ID from host: ");
   262      char charBuffer[2];
   263      for (uint8_t i = 0; i < msgLength - CRC_SIZE - 1; i++) {
   264        Serial1.print(deviceIDBytes[i], HEX);
   265      }
   266  
   267      deviceIDstring = String((char*)deviceIDBytes);
   268  
   269      Serial1.println();
   270      Serial1.print("request for CSR with device ID ");
   271      Serial1.println(deviceIDstring);
   272  
   273      if (generateCSR() == PROVISIONING_ERROR::CSR_GEN_SUCCESS) {
   274        sendData(MESSAGE_TYPE::DATA, csr.c_str(), csr.length());
   275        Serial1.println("CSR GENERATED ON BOARD");
   276      } else {
   277        Serial1.println("SOMETHING WENT WRONG");
   278        while (1);
   279      }
   280    }
   281    if (cmdCode == COMMAND::BEGIN_STORAGE) {
   282      Serial1.println("begin storage");
   283      if (!Crypto.writeDeviceId(deviceIDstring, CryptoSlot::DeviceId)) {
   284        Serial1.println("Error storing device id!");
   285        char response[] = {char(RESPONSE::RESPONSE_ERROR)};
   286        sendData(MESSAGE_TYPE::RESPONSE, response, 1);
   287        return;
   288      }
   289      if (!Cert.begin()) {
   290        Serial1.println("Error starting Crypto storage!");
   291        char response[] = {char(RESPONSE::RESPONSE_ERROR)};
   292        sendData(MESSAGE_TYPE::RESPONSE, response, 1);
   293        return;
   294      }
   295      Cert.setSubjectCommonName(deviceIDstring);
   296      Cert.setIssuerCountryName("US");
   297      Cert.setIssuerOrganizationName("Arduino LLC US");
   298      Cert.setIssuerOrganizationalUnitName("IT");
   299      Cert.setIssuerCommonName("Arduino");
   300      char response[] = {char(RESPONSE::RESPONSE_ACK)};
   301      sendData(MESSAGE_TYPE::RESPONSE, response, 1);
   302    }
   303    if (cmdCode == COMMAND::SET_YEAR) {
   304      Serial1.println("set year");
   305      char yearBytes[4];
   306      String yearString;
   307      for (uint8_t i = 1; i < msgLength - CRC_SIZE; i++) {
   308        yearBytes[i - 1] = payloadBuffer[i];
   309      }
   310      Serial1.print("Year from host: ");
   311      char charBuffer[2];
   312      for (uint8_t i = 0; i < msgLength - CRC_SIZE - 1; i++) {
   313        Serial1.print(yearBytes[i], HEX);
   314        sprintf(charBuffer, "%d", yearBytes[i]);
   315        yearString += String(yearBytes[i]);//String(deviceIDBytes[i], 16);
   316      }
   317  
   318      Serial1.println();
   319      Serial1.print("set Cert YEAR to ");
   320      Serial1.println(yearString);
   321      Cert.setIssueYear(yearString.toInt());
   322  
   323      char response[] = {char(RESPONSE::RESPONSE_ACK)};
   324      sendData(MESSAGE_TYPE::RESPONSE, response, 1);
   325    }
   326    if (cmdCode == COMMAND::SET_MONTH) {
   327      Serial1.println("set month");
   328      char monthBytes[4];
   329      String monthString;
   330      for (uint8_t i = 1; i < msgLength - CRC_SIZE; i++) {
   331        monthBytes[i - 1] = payloadBuffer[i];
   332      }
   333      Serial1.print("month from host: ");
   334      char charBuffer[2];
   335      for (uint8_t i = 0; i < msgLength - CRC_SIZE - 1; i++) {
   336        Serial1.print(monthBytes[i], HEX);
   337        sprintf(charBuffer, "%d", monthBytes[i]);
   338        monthString += String(monthBytes[i]);//String(deviceIDBytes[i], 16);
   339      }
   340  
   341      Serial1.println();
   342      Serial1.print("set Cert MONTH to ");
   343      Serial1.println(monthString);
   344      Cert.setIssueMonth(monthString.toInt());
   345  
   346      char response[] = {char(RESPONSE::RESPONSE_ACK)};
   347      sendData(MESSAGE_TYPE::RESPONSE, response, 1);
   348    }
   349    if (cmdCode == COMMAND::SET_DAY) {
   350      Serial1.println("set day");
   351      char dayBytes[4];
   352      String dayString;
   353      for (uint8_t i = 1; i < msgLength - CRC_SIZE; i++) {
   354        dayBytes[i - 1] = payloadBuffer[i];
   355      }
   356      Serial1.print("day from host: ");
   357      char charBuffer[2];
   358      for (uint8_t i = 0; i < msgLength - CRC_SIZE - 1; i++) {
   359        Serial1.print(dayBytes[i], HEX);
   360        sprintf(charBuffer, "%d", dayBytes[i]);
   361        dayString += String(dayBytes[i]);//String(deviceIDBytes[i], 16);
   362      }
   363  
   364      Serial1.println();
   365      Serial1.print("set Cert day to ");
   366      Serial1.println(dayString);
   367      Cert.setIssueDay(dayString.toInt());
   368  
   369      char response[] = {char(RESPONSE::RESPONSE_ACK)};
   370      sendData(MESSAGE_TYPE::RESPONSE, response, 1);
   371    }
   372    if (cmdCode == COMMAND::SET_HOUR) {
   373      Serial1.println("set hour");
   374      char hourBytes[4];
   375      String hourString;
   376      for (uint8_t i = 1; i < msgLength - CRC_SIZE; i++) {
   377        hourBytes[i - 1] = payloadBuffer[i];
   378      }
   379      Serial1.print("hour from host: ");
   380      char charBuffer[2];
   381      for (uint8_t i = 0; i < msgLength - CRC_SIZE - 1; i++) {
   382        Serial1.print(hourBytes[i], HEX);
   383        sprintf(charBuffer, "%d", hourBytes[i]);
   384        hourString += String(hourBytes[i]);//String(deviceIDBytes[i], 16);
   385      }
   386  
   387      Serial1.println();
   388      Serial1.print("set Cert hour to ");
   389      Serial1.println(hourString);
   390      Cert.setIssueHour(hourString.toInt());
   391  
   392      char response[] = {char(RESPONSE::RESPONSE_ACK)};
   393      sendData(MESSAGE_TYPE::RESPONSE, response, 1);
   394    }
   395    if (cmdCode == COMMAND::SET_VALIDITY) {
   396      Serial1.println("set validity");
   397      char validityBytes[4];
   398      String validityString;
   399      for (uint8_t i = 1; i < msgLength - CRC_SIZE; i++) {
   400        validityBytes[i - 1] = payloadBuffer[i];
   401      }
   402      Serial1.print("validity from host: ");
   403      char charBuffer[2];
   404      for (uint8_t i = 0; i < msgLength - CRC_SIZE - 1; i++) {
   405        Serial1.print(validityBytes[i], HEX);
   406        sprintf(charBuffer, "%d", validityBytes[i]);
   407        validityString += String(validityBytes[i]);//String(deviceIDBytes[i], 16);
   408      }
   409  
   410      Serial1.println();
   411      Serial1.print("set Cert validity to ");
   412      Serial1.println(validityString);
   413      Cert.setExpireYears(validityString.toInt());
   414  
   415      char response[] = {char(RESPONSE::RESPONSE_ACK)};
   416      sendData(MESSAGE_TYPE::RESPONSE, response, 1);
   417    }
   418    if (cmdCode == COMMAND::SET_CERT_SERIAL) {
   419      // extract payload from [1] to [payloadLength]
   420      // this will be the certificate serial number included in the device certificate
   421      Serial1.println("set CERT Serial");
   422      byte certSerialBytes[msgLength - CRC_SIZE - 1];
   423  
   424      for (uint8_t i = 1; i < msgLength - CRC_SIZE; i++) {
   425        certSerialBytes[i - 1] = payloadBuffer[i];
   426      }
   427  
   428      Serial1.print("Serial Number from host: ");
   429      for (uint8_t i = 0; i < msgLength - CRC_SIZE - 1; i++) {
   430        Serial1.print(certSerialBytes[i], HEX);
   431      }
   432      Serial1.println();
   433  
   434      if(!Cert.setSerialNumber(certSerialBytes, sizeof(certSerialBytes))) {
   435        Serial1.println("set CERT Error");
   436        char response[] = {char(RESPONSE::RESPONSE_ERROR)};
   437        sendData(MESSAGE_TYPE::RESPONSE, response, 1);
   438        return;
   439      }
   440  
   441      char response[] = {char(RESPONSE::RESPONSE_ACK)};
   442      sendData(MESSAGE_TYPE::RESPONSE, response, 1);
   443    }
   444    if (cmdCode == COMMAND::SET_AUTH_KEY) {
   445      // extract payload from [1] to [payloadLength]
   446      // this will be the authority key id included in the device certificate
   447      Serial1.println("set Auth Key Id");
   448      byte authKeyBytes[msgLength - CRC_SIZE - 1];
   449  
   450      for (uint8_t i = 1; i < msgLength - CRC_SIZE; i++) {
   451        authKeyBytes[i - 1] = payloadBuffer[i];
   452      }
   453  
   454      Serial1.print("Authority Key Id from host: ");
   455      for (uint8_t i = 0; i < msgLength - CRC_SIZE - 1; i++) {
   456        Serial1.print(authKeyBytes[i], HEX);
   457      }
   458      Serial1.println();
   459  
   460      if(!Cert.setAuthorityKeyId(authKeyBytes, sizeof(authKeyBytes))) {
   461        Serial1.println("set AuthorityKeyId Error");
   462        char response[] = {char(RESPONSE::RESPONSE_ERROR)};
   463        sendData(MESSAGE_TYPE::RESPONSE, response, 1);
   464        return;
   465      }
   466  
   467      char response[] = {char(RESPONSE::RESPONSE_ACK)};
   468      sendData(MESSAGE_TYPE::RESPONSE, response, 1);
   469    }
   470    if (cmdCode == COMMAND::SET_SIGNATURE) {
   471      // extract payload from [1] to [payloadLength]
   472      // this will be the signature included in the device certificate
   473      Serial1.println("set Signature ");
   474      byte signatureBytes[msgLength - CRC_SIZE - 1];
   475  
   476      for (uint8_t i = 1; i < msgLength - CRC_SIZE; i++) {
   477        signatureBytes[i - 1] = payloadBuffer[i];
   478      }
   479  
   480      Serial1.print("Signature from host: ");
   481      for (uint8_t i = 0; i < msgLength - CRC_SIZE - 1; i++) {
   482        Serial1.print(signatureBytes[i], HEX);
   483      }
   484      Serial1.println();
   485  
   486      if(!Cert.setSignature(signatureBytes, sizeof(signatureBytes))) {
   487        Serial1.println("set signature Error");
   488        char response[] = {char(RESPONSE::RESPONSE_ERROR)};
   489        sendData(MESSAGE_TYPE::RESPONSE, response, 1);
   490        return;
   491      }
   492  
   493      char response[] = {char(RESPONSE::RESPONSE_ACK)};
   494      sendData(MESSAGE_TYPE::RESPONSE, response, 1);
   495    }
   496    if (cmdCode == COMMAND::END_STORAGE) {
   497      Serial1.println("end storage");
   498      if (!Crypto.buildCert(Cert, CryptoSlot::Key)) {
   499        Serial1.println("Error creating cert!");
   500        char response[] = {char(RESPONSE::RESPONSE_ERROR)};
   501        sendData(MESSAGE_TYPE::RESPONSE, response, 1);
   502        return;
   503      }
   504  
   505      if (!Crypto.writeCert(Cert, CryptoSlot::CompressedCertificate)) {
   506        Serial1.println("Error storing Crypto cert!");
   507        char response[] = {char(RESPONSE::RESPONSE_ERROR)};
   508        sendData(MESSAGE_TYPE::RESPONSE, response, 1);
   509        return;
   510      }
   511  
   512      Serial1.println("Certificate PEM file");
   513      Serial1.println(Cert.getCertPEM());
   514  
   515      char response[] = {char(RESPONSE::RESPONSE_ACK)};
   516      sendData(MESSAGE_TYPE::RESPONSE, response, 1);
   517    }
   518    if (cmdCode == COMMAND::RECONSTRUCT_CERT) {
   519      Serial1.println("reconstruct certificate");
   520      if (!Crypto.readCert(Cert, CryptoSlot::CompressedCertificate)) {
   521        Serial1.println("Error reconstructing Crypto cert!");
   522        char response[] = {char(RESPONSE::RESPONSE_ERROR)};
   523        sendData(MESSAGE_TYPE::RESPONSE, response, 1);
   524        return;
   525      }
   526  
   527      Serial1.println("Compressed cert = ");
   528  
   529      const byte *certData = Cert.bytes();
   530      int certLength = Cert.length();
   531  
   532      for (int i = 0; i < certLength; i++) {
   533        byte b = certData[i];
   534  
   535        if (b < 16) {
   536          Serial1.print('0');
   537        }
   538        Serial1.print(b, HEX);
   539      }
   540      Serial1.println();
   541      char response[] = {char(RESPONSE::RESPONSE_ACK)};
   542      sendData(MESSAGE_TYPE::RESPONSE, response, 1);
   543    }
   544  
   545  }
   546  
   547  void processRawData(bool checkSumOK) {
   548    Serial1.println(">> processing raw data");
   549  
   550    if (checkSumOK) {
   551      uint8_t resp[] = {0x55, 0xaa, (uint8_t)MESSAGE_TYPE::RESPONSE, 0x01, (uint8_t)RESPONSE::RESPONSE_ACK, 0xaa, 0x55};
   552      for (uint8_t i = 0; i < sizeof(resp); i++) {
   553        Serial1.print(resp[i]);
   554        Serial1.print(" ");
   555      }
   556      Serial.write(resp, sizeof(resp));
   557    } else {
   558      uint8_t resp[] = {0x55, 0xaa, (uint8_t)MESSAGE_TYPE::RESPONSE, 0x01, (uint8_t)RESPONSE::RESPONSE_NACK, 0xaa, 0x55};
   559      for (uint8_t i = 0; i < sizeof(resp); i++) {
   560        Serial1.print(resp[i]);
   561        Serial1.print(" ");
   562      }
   563      Serial.write(resp, sizeof(resp));
   564    }
   565  }
   566  
   567  void sendData(MESSAGE_TYPE _msgType, const char* _msgPayload, uint16_t _payloadSize) {
   568    Serial1.print("payload size: ");
   569    Serial1.print(_payloadSize);
   570    Serial1.print(" [");
   571    Serial1.print(_payloadSize, HEX);
   572    Serial1.println("]");
   573    Serial1.println(_msgPayload);
   574  
   575    Serial.write(msgStart, sizeof(msgStart));
   576    Serial.write((uint8_t)_msgType);
   577    Serial.write((_payloadSize + CRC_SIZE) >> 8) ;
   578    Serial.write((_payloadSize + CRC_SIZE) & 0xff);
   579    Serial.write(_msgPayload, _payloadSize);
   580    uint16_t payloadCRC = uCRC16Lib::calculate((char *)_msgPayload, _payloadSize);
   581    Serial1.print("payload CRC out: ");
   582    Serial1.println(payloadCRC, HEX);
   583    Serial.write((uint8_t)(payloadCRC >> 8));
   584    Serial.write((uint8_t)(payloadCRC & 0xff));
   585    Serial.write(msgEnd, sizeof(msgEnd));
   586  
   587  }
   588  
   589  void sendResponse() {
   590  
   591  }
   592  void changeState(MACHINE_STATE _newState) {
   593    Serial1.print("changing state to ");
   594    Serial1.println((uint8_t)_newState);
   595    if (_newState == machineState)
   596      return;
   597    if (_newState == MACHINE_STATE::RECEIVING_PAYLOAD) {
   598      msgByteIndex = 0;
   599    }
   600    if (_newState == MACHINE_STATE::IDLE) {
   601  
   602    }
   603    machineState = _newState;
   604  }
   605  
   606  uint8_t cryptoInit() {
   607    unsigned long ecctimeout = 1000;
   608    unsigned long beginOfTime = millis();
   609    bool eccOK = 0;
   610    while (!(eccOK = Crypto.begin()) || (millis() - beginOfTime < ecctimeout)) {
   611    }
   612    return eccOK;
   613  }
   614  
   615  PROVISIONING_ERROR cryptoLock() {
   616    if (!Crypto.locked()) {
   617  
   618      if (!Crypto.writeConfiguration(DEFAULT_ECCX08_TLS_CONFIG)) {
   619        return PROVISIONING_ERROR::WRITE_CONFIG_FAIL;
   620      }
   621  
   622      if (!Crypto.lock()) {
   623        return PROVISIONING_ERROR::LOCK_FAIL;
   624      }
   625      return PROVISIONING_ERROR::LOCK_SUCCESS;
   626    }
   627    return PROVISIONING_ERROR::LOCK_SUCCESS;
   628  }
   629  
   630  PROVISIONING_ERROR generateCSR() {
   631    if (!Crypto.locked()) {
   632      Serial1.println("Chip is not locked");
   633      return PROVISIONING_ERROR::LOCK_FAIL;
   634    }
   635    Serial1.println("CSR generation in progress");
   636  
   637    if (!Cert.begin()) {
   638      Serial1.println("Error initializing CSR data!");
   639      return PROVISIONING_ERROR::CSR_GEN_FAIL;
   640    }
   641  
   642    Cert.setSubjectCommonName(deviceIDstring);
   643  
   644    if (!Crypto.buildCSR(Cert, CryptoSlot::Key, true)) {
   645      Serial1.println("Error generating CSR!");
   646      return PROVISIONING_ERROR::CSR_GEN_FAIL;
   647    }
   648  
   649    csr = Cert.getCSRPEM();
   650    if (!csr) {
   651      Serial1.println("Error reading CSR PEM data!");
   652      return PROVISIONING_ERROR::CSR_GEN_FAIL;
   653    }
   654    Serial1.println(csr.length());
   655    Serial1.println(csr);
   656  
   657    return PROVISIONING_ERROR::CSR_GEN_SUCCESS;
   658  }