skip to Main Content

Code snippet:

......
  (dio.httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate =
      (client) {
    SecurityContext securityContext = SecurityContext(withTrustedRoots: true);
    // securityContext.setTrustedCertificatesBytes(certBytes);
    securityContext.setTrustedCertificates('assets/ca-cert.crt');
    HttpClient httpClient = HttpClient(context: securityContext);
    httpClient.badCertificateCallback =
        (X509Certificate cert, String host, int port) {
      return true;
    };
  };
......

Error prompt:

Failed to load "...dio_ca_trust_test.dart":
DioError [DioErrorType.other]: TlsException: Failure trusting builtin roots (OS Error: 
    CERT_ALREADY_IN_HASH_TABLE(../../third_party/boringssl/src/crypto/x509/x509_lu.c:357), errno = 184549481)

reference document:
3.2.flutter-https验证
Flutter 自签名证书

2

Answers


  1. Chosen as BEST ANSWER

    Previously, the IP certificate was deployed on the HTTP server, now replace the certificate with the domain name certificate! Create a new test code in the test directory.

    dio.httpClientAdapter = IOHttpClientAdapter(
          createHttpClient: () {
            SecurityContext securityContext =
                SecurityContext(withTrustedRoots: true);
            **securityContext.setTrustedCertificates('assets/ca-cert.crt'); or
            securityContext.useCertificateChainBytes(File('assets/ca-cert.crt').readAsBytesSync());**
            final client = HttpClient(
              context: securityContext,
            );
            client.badCertificateCallback = (cert, host, port) => true;
    
            return client;
          },
        );
    

    This code will work in a separate test file with setTrustedCertificates and useCertificateChainBytes Settings. But placing the code in the project indicates that the certificate file is not found

    I/flutter ( 6689): Error: FileSystemException: Cannot open file, path = 'assets/ca-cert.crt' (OS Error: No such file or directory, errno = 2)
    

    1. Dio (HttpClient) certificate authentication The support for IP certificate authentication is not perfect.

    2. Using File(‘assets/ca.crt’).readAsBytesSync() or await rootBundle.load("assets/ca.crt") in the Widget neither of these methods work properly FileSystemException: Cannot open file. But it works fine until the main function calls runApp(const App()), I don’t know why!

    3. In the main () function configuration HttpOverrides. The method of HttpOverrides.global = _HttpOverrides _HttpOverrides. createHttpClient will be multiple calls even if I just call the HTTP request at a time, Setting the certificate is also invalid, and this method is only suitable for ignoring the certificate globally.

    The solution:
    Adds a global variable, initialized before runApp(const App()).Use this global variable where http requests are required

    Future<void> main() async {
      WidgetsFlutterBinding.ensureInitialized();
      var chainBytes = await rootBundle.load("assets/ca.crt");
    
      Global.dio.httpClientAdapter = IOHttpClientAdapter(
        createHttpClient: () {
          SecurityContext securityContext = SecurityContext(withTrustedRoots: true);
          securityContext.setTrustedCertificatesBytes(chainBytes.buffer.asUint8List());
          // securityContext.useCertificateChainBytes(chainBytes.buffer.asUint8List());
          final client = HttpClient(
            context: securityContext,
          );
          // client.badCertificateCallback = (cert, host, port) => true;
    
          return client;
        },
      );
    
      runApp(const BiliApp());
    }
    

    This may not be the best way but it’s the one I can think of right now.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search