This article is from: 103Style blog

Revision record:

2019/11/05 13:12: Changes to the certificate verification content. Currently there are problems with flutter issues

2019/11/05 17:26: Modified the content of certificate authentication to handle the problem of bidirectional authentication failure.

directory

  • The related error message was encountered
  • The environment
  • The integration process
  • Certificate authentication

The related error message was encountered

Unhandled Exception: FileSystemException: Cannot open file, path = '... ' 
(OS Error: No such file or directory, errno = 2)

TlsException: Failure trusting builtin roots

SocketException: OS Error: Connection reset by peer, errno = 104
Copy the code

The environment

flutter doctor -v

>flutter doctor -v [√] flutter (Channel stable, v1.9.1+hotfix.5, on Microsoft Windows [Version 10.0.17134.1006], Locale zh-CN) • Flutter version 1.9.1+hotfix.5 at D:\ Flutter • Framework Revision 1aEDbb1835 (2 weeks ago), Dart Version 2.5.0 [√] Android Toolchchain - DevelopforAndroid Devices (Android SDK Version 28.0.3) • Android SDK at D:\Android\ SDK • Android NDK location not configured (optional; usefulforNative profiling support) • Platform Android-29, build-tools 28.0.3 • Java binary at: D:\Android\AndroidStudio\jre\bin\ Java • Java version OpenJDK Runtime Environment (build 1.8.0_202-release-1483-b03) • All Android licenses accepted. [√] AndroidStudio (Version 3.5) • AndroidStudio at D:\Android\AndroidStudio • Flutter Dart Plugin version 191.8593 • Java Version OpenJDK Runtime Environment (build 1.8.0 comes with _202 - release - 1483 - b03)Copy the code

The integration process

First go to the website of the flutter package library, then search MQTT and find the library MQTT_client. The above provides the following usage examples without security authentication. Original example Address: pub.flutter-io.cn/packages/mq…

import 'dart:async';
import 'dart:io';
import 'package:mqtt_client/mqtt_client.dart'; /// the server address is test.mosquitto.org, the default port is 1883 /// the custom port can call mqttClient.withport (server address, identity, port number); final MqttClient client = MqttClient('test.mosquitto.org'.' ');

Future<int> main() async {
  client.logging(on: false); KeepAlivePeriod = 20; /// Set timeout. Client. OnDisconnected = onDisconnected; // Set the connection callback client. OnConnected = onConnected; $subscribed = $subscribed; $subscribed = $subscribed; // Subscribe to the callback client. PongCallback = pong; // Ping callback try {await client.connect(); } on Exception catch (e) {print('EXAMPLE::client exception - $e'); client.disconnect(); } /// Check the connection resultif (client.connectionStatus.state == MqttConnectionState.connected) {
    print('EXAMPLE::Mosquitto client connected');
  } else {
    print('EXAMPLE::ERROR Mosquitto client connection failed - disconnecting, status is ${client.connectionStatus}');
    client.disconnect();
    exit(1); } /// Subscribe to a topic: server-defined event when the server sends this message, it receives a const String topic = in client.updates. Listen'test/lol'; client.subscribe(topic, MqttQos.atMostOnce); Client.updates. Listen ((List<MqttReceivedMessage<MqttMessage>> c) {final MqttPublishMessage recMess = c[0].payload; / / / the server returns the data information of final String pt = MqttPublishPayload. BytesToStringAsString (recMess. Content. The message).print( 'EXAMPLE::Change notification:: topic is <${c[0].topic}>, payload is <-- $pt -->'); }); Client.published. Listen ((MqttPublishMessage) {/// Set public listener, when we call publishMessage, it will tell you if it is published successfully.print('EXAMPLE::Published notification:: topic is ${message.variableHeader.topicName}, with Qos ${message.header.qos}'); }); /// example of sending a message to the server const String pubTopic ='Dart/Mqtt_client/testtopic';
  final MqttClientPayloadBuilder builder = MqttClientPayloadBuilder();
  builder.addString('Hello from mqtt_client'); Client.publishmessage (pubTopic, mqttqos.exactlyonce, Builder.payload); /// Unsubscribe client. Unsubscribe (topic); /// Disconnect client.disconnect();return 0;
}
void onSubscribed(String topic) {
  print('EXAMPLE::Subscription confirmed for topic $topic');
}
void onDisconnected() {
  print('EXAMPLE::OnDisconnected client callback - Client disconnection');
  if (client.connectionStatus.returnCode == MqttConnectReturnCode.solicited) {
    print('EXAMPLE::OnDisconnected callback is solicited, this is correct');
  }
  exit(1); } voidonConnected() {
  print('EXAMPLE::OnConnected client callback - Client connection was sucessful');
}
void pong() {
  print('EXAMPLE::Ping response client callback invoked');
}
Copy the code

Then I ran the following example, provided the test server can be successfully connected.


Certificate authentication

However, I have done certificate verification on my server, and need to configure the certificate. Then I found the Github address of mqTT_client library.

Then I found in Issue 107 that the author provided an example of configuring certificates. Example Address: github.com/shamblett/m…

The author in this directory/example/pem provides a certificate file, and then by flutter providing context. SetTrustedCertificates certificate (filepath) Settings. The main logic is as follows:

import 'dart:async';
import 'dart:io';
import 'package:path/path.dart' as path;
import 'package:mqtt_client/mqtt_client.dart';

Future<int> main() async {
  ... 
  client.secure = true;
  final String currDir =
      '${path.current}${path.separator}example${path.separator}';
  final SecurityContext context = SecurityContext.defaultContext;
  context.setTrustedCertificates(currDir + path.join('pem'.'roots.pem')); client.securityContext = context; client.setProtocolV311(); await client.connect(); .return 0;
}
Copy the code

Then I ran and found the first problem:

Unhandled Exception: FileSystemException: Cannot open file, path = '... ' 
(OS Error: No such file or directory, errno = 2)
Copy the code

Then I asked the author of this library under issue 107. You can see our conversation there. The author of the library finally said that the path of flutter does not support // CRT/CRT /cilent.crt access.

I also tried to access by configuring assets, but there was no corresponding method to obtain the path.

Then I went to the Github address of Flutter to mention this issue: Flutter /issues/43472. However, until now, the developers of Flutter have not provided relevant solutions.


And then, finally, I thought, even if I can’t read the file in the project, I’ll write it to the phone file system and then get the path to the file. Refer to the official document reading and writing tutorial. As follows:

Future<String> _getLocalFile(String filename, {bool deleteExist:false}) async {
  String dir = (await getApplicationDocumentsDirectory()).path;
  log('dir = $dir');
  File file = new File('$dir/$filename');
  bool exist = await file.exists();
  log('exist = $exist');
  if (deleteExist) {
    if (exist) {
      file.deleteSync();
    }
    exist = false;
  }
  if(! exist) {log("MqttUtils: start write cert in local"); await file.writeAsString(mqtt_cert); //mqtt_cert is the corresponding content of the certificate}return file.path;
}
Copy the code

Updated at 2019/11/05 17:26 START

Then change the connection code to:

_client.secure = true;
final SecurityContext context = SecurityContext.defaultContext;

String caPath =
    await _getLocalFile("ca.pem", cert_ca, deleteExist: deleteExist);
String clientKeyPath = await _getLocalFile("clientkey.pem", cert_client_key,
    deleteExist: deleteExist);
String clientCrtPath = await _getLocalFile("client.pem", cert_client_crt, deleteExist: deleteExist); try { context.setTrustedCertificates(caPath); context.useCertificateChain(clientCrtPath); context.usePrivateKey(clientKeyPath); } on Exception catch (e) {// An Exception occurred and an attempt was made to delete the local certificate and then write the certificate againlog("SecurityContext set error : " + e.toString());
  return- 1; } _client.securityContext = context; _client.setProtocolV311();Copy the code

Cert_ca: contents of the root certificate cert_client_key: contents of the client private key cert_client_crt: contents of the client certificate

Updated at 2019/11/05 17:26 END

If the certificate content is incorrect, the following error will be reported:

TlsException: Failure trusting builtin roots
Copy the code

Updated at 2019/11/05 13:12 START

SecurityContext has a way of providing direct access to the content, it doesn’t have to be a path…

You can also read the contents of assets by using the following methods:

String cerData = await rootBundle.loadString("assets/cc.pem");
utf8.encode(caPath);
Copy the code

Then call the following bytes method.

void usePrivateKey(String file, {String password});
void usePrivateKeyBytes(List<int> keyBytes, {String password});
void setTrustedCertificates(String file, {String password});
void setTrustedCertificatesBytes(List<int> certBytes, {String password});
void useCertificateChain(String file, {String password});
void useCertificateChainBytes(List<int> chainBytes, {String password});
void setClientAuthorities(String file, {String password});
void setClientAuthoritiesBytes(List<int> authCertBytes, {String password});
Copy the code

Updated at 2019/11/05 13:12 END


Then good use for a few days, yesterday afternoon when the connection suddenly can not connect!! Error message:

SocketException: OS Error: Connection reset by peer, errno = 104
Copy the code

Then I searched around and asked the author of the MQTT_client library… Mqtt_client /issues/131. And he didn’t either.

TLSv1.2 Handshake Failure error message TLSv1.2 Handshake Failure error message TLSv1.2 Handshake Failure error message TLSv1.2 Handshake Failure error message May also be yesterday afternoon server colleagues changed the configuration after the restart caused by the feeling should be the latter….

Finally found that is their certificate configuration problem! Fixed in the above code example and demo! This connection was possible because two-way authentication was not configured on the server.


Finally provide a Demo: github.com/103style/mq…

The above

If you like it, please give it a thumbs up.


Scan the qr code below, follow my public account Android1024, click attention, don’t get lost.