Flutter add self signed certificate from asset folder

Issue

My server provides a Self Signed certificate when calling its HTTPS API. I have the certificate file in the asset folder and referenced its path in pubspec.yaml
I have tried passing the certificate to SecurityContext and then using that context to create an HttpClient. But the way I’m passing the certificate to SecurityContext is not working. Here is the code:

Future<ByteData> getFileData(String path) async {
    return await rootBundle.load(path);
}

void initializeHttpClient() async {
    try {
         Future<ByteData> data = getFileData('assets/raw/certificate.crt');
         await data.then((value) {
             var context = SecurityContext.defaultContext;
             context.useCertificateChainBytes(value.buffer.asInt8List());
             client = HttpClient(context: context);
         });

    } on Exception catch (exception) {
         print(exception.toString());
    }
}

The SecurityContext has two methods:
1) useCertificateChain() this accepts a file path. But when I give the path of the file in my asset folder (‘assets/raw/certificate.crt’). It says file not found.
2) useCertificateChainBytes() the above code is using this method. But this also gives me error like (unexpected end of file).

Solution as of now

I am bypassing it using client.badCertificateCallback = (X509Certificate cert, String host, int port)=> true;.

but I’d like to make it work with certificate

Solution

It’s not clear from your question what the role of the self-signed certificate is. Based on your work around, I assume that it’s a server side certificate that you have installed in the HTTPS server. (It’s not a client side certificate that you would like to pass to the server.)

So, what you need to do is to get the Dart HttpClient to trust that certificate, which will be passed to it by the server as part of the TLS handshake. (By setting the callback you have made the client trust any certificate, not just your server’s.)

To set the trusted certificate use setTrustedCertificatesBytes in place of useCertificateChainBytes (which you would use if your certificate was a client side one).

You cannot access assets directly as Files as they are bundled by the build. You are doing the right thing by loading them and using the ...Bytes methods. You could improve the readability of your code like this (removing the then). Also, note the subtle change to Uint8List

ByteData data = await rootBundle.load('assets/raw/certificate.crt');
SecurityContext context = SecurityContext.defaultContext;
context.setTrustedCertificatesBytes(data.buffer.asUint8List());
client = HttpClient(context: context);

Answered By – Richard Heap

Answer Checked By – Mary Flores (FlutterFixes Volunteer)

Leave a Reply

Your email address will not be published. Required fields are marked *