Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue at br_sslio_flush(&_ioc) inside int BearSSLClient::connectSSL(const char* host) when using MQTT on Arduino MKRNB 1500 #92

Open
itadminkema opened this issue Aug 9, 2024 · 0 comments
Labels
type: imperfection Perceived defect in any part of project

Comments

@itadminkema
Copy link

itadminkema commented Aug 9, 2024

Hello,

I am facing an issue while attempting to connect my Arduino MKR 1500 NB to an MQTT broker using a combination of NBClient, BearSSLClient, and arduinoMqttClient libraries. Despite successfully connecting to the NB IoT network and establishing a UDP connection to an NTP server, the connection to the MQTT broker fails during the inital BearSSL connect process. The failure occurs specifically during the br_sslio_flush(&_ioc) call in the BearSSLClient::connectSSL function, where the program freezes without generating a response, timeout, or error. Could this issue be related to an inconsistency in the character sequence length following the AT command issued to the NBIoT module? Or is it something else?


I am using an Arduino MKR 1500 NB client -> BearSSLClient ->arduinoMqttClient

// Initialize MQTT and SSL clients  from library
NBClient nbClient;
BearSSLClient sslClient(nbClient);
MqttClient arduinoMqttClient(sslClient);

I am able to connect to the NB IoT network and I am even able to start a UDP connection to an NTP server (which is used for
ArduinoBearSSL.onGetTime(get_time); // Required for server trusted root validation.
)

We then get ready to initialize the MQTT client, and the problem comes up when we run arduinoMqttClient.connect(address,port) link:

arduinoMqttClient.setId(client_id);
arduinoMqttClient.setUsernamePassword(username, password);
arduinoMqttClient.setCleanSession(true);
arduinoMqttClient.onMessage(on_message_received);

LogInfo("MQTT Client ID: %s", client_id);
LogInfo("MQTT Username: %s", username);
LogInfo("MQTT Password: ***");
LogInfo("MQTT client address: %s", address);
LogInfo("MQTT client port: %d", port);

bool mqtt_connected = false;
Serial.println("MQTT Connecting MQTT client...");
while (!mqtt_connected)  {
  if (arduinoMqttClient.connect(address, port)){
    Serial.println("Succesful MQTT connection to Azure broker!");
    mqtt_connected = true;
  }
  else {
    Serial.print("MQTT connection failed! Error code = ");
    Serial.println(arduinoMqttClient.connectError());
    //int code = arduinoMqttClient.connectError();
    //LogError("Cannot connect. Error Code: %d", code);
    delay(5000);
  }
}

arduinoMqttClient.connect(address,port) calls, which runs until _client->connect(host, port):

int MqttClient::connect(IPAddress ip, const char* host, uint16_t port)
{
  Serial.println("MQTTClient : Start connect");
  if (clientConnected()) {
    _client->stop();
  }
  _rxState = MQTT_CLIENT_RX_STATE_READ_TYPE;
  _connected = false;
  _txPacketId = 0x0000;

  if (host) {
    Serial.println("MQTTClient : Connecting by host");
    if (!_client->connect(host, port)) {
      _connectError = MQTT_CONNECTION_REFUSED;
      Serial.println("MQTTClient : 0 - host connection refused");
      return 0;
    }
}

_client->connect(host, port) seems to trigger a call to two functions:

  1. First it calls int NBClient::connect() link which executes successfully and creates a TCP socket with "global.azure-devices-provisioning.net",8883:
  2. After that in triggers int BearSSLClient::connectSSL(const char* host) which is where the failure occurs, specifically on the call to br_sslio_flush(&_ioc); function:
  • At that time there is an AT command issued to the NBIoT module and after that the program doesn't genereate any reposnse or timeout or error return. It just freezes.

  • One thing that I did note is that the character sequence following the AT+USOWR command is not of the same length as specified in the start of the AT command (178 vs the 242 supposed to be sent). But I don't know if this is just an issue with MAX number of characters in arduino's Serial.println()

-Here are the Serial.print() statments I am using for debugging aling with the AT commands sent by MKRNB module:

14:03:39.127 -> MQTTClient : Start connect
14:03:39.127 -> MQTTClient : Connecting by host
14:03:39.127 -> NBC : Starting NB connect
14:03:39.127 -> 1
14:03:39.218 -> AT+USOCR=6

14:03:39.218 -> +USOCR: 1
14:03:39.218 -> 
14:03:39.252 -> OK
14:03:39.428 -> AT+USOCO=1,"global.azure-devices-provisioning.net",8883

14:03:43.042 -> OK
14:03:43.042 -> NBC : 1 - success END

14:03:43.042 -> BSSL : Starting BSSL connect
14:03:43.168 -> AT+USOST=0,"129.6.15.28",123,48,"E30006EC0000000000000000314E31340000000000000000000000000000000000000000000000000000000000000000"

14:03:43.168 -> +USOST: 0,48
14:03:43.214 -> 
14:03:43.214 -> OK
14:03:43.214 -> 1 - Waiting for time packet....
14:03:44.199 -> +UUSORF: 0,48
14:03:44.199 -> AT+USORF=0,512

14:03:44.240 -> 
14:03:44.240 -> +USORF: 0,"129.6.15.28",123,48,"1C010DE300000010000000204E495354EA60F480000000000000000000000000EA60F4A027DB0056EA60F4A027DB15F6"
14:03:44.240 -> OK
14:03:44.240 ->  NTP packet received
14:03:44.240 -> BSSL : Finish random - get_time()
14:03:44.240 -> BSSL : Begin socket init
14:03:44.240 -> BSSL : socketflush
14:03:44.240 -> AT+USORD=1,512

14:03:44.240 -> +USORD: 1,""
14:03:44.240 -> 
14:03:44.240 -> OK
14:03:44.308 -> AT+USOWR=1,242,"16030100ED010000E9030300000000D7C94A75B33CD7C36976D1E83A101F715E653FA3017151659FDD639900005ACCA9CCA8C02BC02FC02CC030C0ACC0ADC0AEC0AFC023C027C024C028C009C013C00AC014C02DC031C02EC032C025C029C026C02AC004C00EC005C00F009C009DC09CC09DC0A0C0A1003C003D002F0035C008C012C003C00D000A01000066FF010001000000002A0028000025676C6F62616C2E617A7572652D646576696365732D70726F

Additional int BearSSLClient::connectSSL(const char* host) reference code with debug Serial.println() statements added:

int BearSSLClient::connectSSL(const char* host)
{
  Serial.println("BSSL : Starting BSSL connect");
  if (!_br_ssl_client_init_function) {
    return 0;
  }

  // initialize client context with enabled algorithms and trust anchors
  _br_ssl_client_init_function(&_sc, &_xc, _TAs, _numTAs);

  br_ssl_engine_set_buffers_bidi(&_sc.eng, _ibuf, sizeof(_ibuf), _obuf, sizeof(_obuf));

  // inject entropy in engine
  unsigned char entropy[32];

#ifndef ARDUINO_DISABLE_ECCX08
  if (!ECCX08.begin() || !ECCX08.locked() || !ECCX08.random(entropy, sizeof(entropy))) {
#endif
    // no ECCX08 or random failed, fallback to pseudo random
    for (size_t i = 0; i < sizeof(entropy); i++) {
      entropy[i] = random(0, 255);
    }
#ifndef ARDUINO_DISABLE_ECCX08
  }
#endif
  br_ssl_engine_inject_entropy(&_sc.eng, entropy, sizeof(entropy));

  // add custom ECDSA vfry and EC sign
  br_ssl_engine_set_ecdsa(&_sc.eng, _ecVrfy);
  br_x509_minimal_set_ecdsa(&_xc, br_ssl_engine_get_ec(&_sc.eng), br_ssl_engine_get_ecdsa(&_sc.eng));

  // enable client auth
  if (_ecCert[0].data_len) {
#ifndef ARDUINO_BEARSSL_DISABLE_KEY_DECODER
    if (_skeyDecoder) {
      int skeyType = br_skey_decoder_key_type(_skeyDecoder);

      if (skeyType == BR_KEYTYPE_EC) {
        br_ssl_client_set_single_ec(&_sc, _ecCert, _ecChainLen, br_skey_decoder_get_ec(_skeyDecoder), BR_KEYTYPE_KEYX | BR_KEYTYPE_SIGN, BR_KEYTYPE_EC, br_ec_get_default(), br_ecdsa_sign_asn1_get_default());
      } else if (skeyType == BR_KEYTYPE_RSA) {
        br_ssl_client_set_single_rsa(&_sc, _ecCert, _ecChainLen, br_skey_decoder_get_rsa(_skeyDecoder), br_rsa_pkcs1_sign_get_default());
      }
    } else {
#endif
      br_ssl_client_set_single_ec(&_sc, _ecCert, _ecChainLen, &_ecKey, BR_KEYTYPE_KEYX | BR_KEYTYPE_SIGN, BR_KEYTYPE_EC, br_ec_get_default(), _ecSign);
#ifndef ARDUINO_BEARSSL_DISABLE_KEY_DECODER
    }
#endif
  }

  // set the hostname used for SNI
  br_ssl_client_reset(&_sc, host, 0);

  // get the current time and set it for X.509 validation
  uint32_t now = ArduinoBearSSL.getTime();
  uint32_t days = now / 86400 + 719528;
  uint32_t sec = now % 86400;
  Serial.println("BSSL : Finish random - get_time()");

  br_x509_minimal_set_time(&_xc, days, sec);

  Serial.println("BSSL : Begin socket init");
  // use our own socket I/O operations
  br_sslio_init(&_ioc, &_sc.eng, BearSSLClient::clientRead, _client, BearSSLClient::clientWrite, _client);

  Serial.println("BSSL : socketflush");
  br_sslio_flush(&_ioc);
  Serial.println("BSSL : PROBLEM HERE!");

  while (1) {
    Serial.println("BSSL : get state, on loop");
    unsigned state = br_ssl_engine_current_state(&_sc.eng);

    Serial.println("BSSL : run ifs");
    if (state & BR_SSL_SENDAPP) {
      break;
    } else if (state & BR_SSL_CLOSED) {
      return 0;
    }
    Serial.println("BSSL : help, trap");
  }

  Serial.println("BSSL : 1 - success END");
  return 1;
}
@itadminkema itadminkema changed the title Issue at br_sslio_flush(&_ioc) inside int BearSSLClient::connectSSL(const char* host) when using MQTT on Arduino MKRNB 1500 Issue at br_sslio_flush(&_ioc) inside int BearSSLClient::connectSSL(const char* host) when using MQTT on Arduino MKRNB 1500 Aug 9, 2024
@per1234 per1234 added the type: imperfection Perceived defect in any part of project label Aug 9, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: imperfection Perceived defect in any part of project
Projects
None yet
Development

No branches or pull requests

2 participants