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
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 File
s 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);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With