Dart gRPC TLS certificates with PEMs
I ended up receiving somewhat of a proper answer on the grpc-dart issues page. The solution looks something like this:
class MyChannelCredentials extends ChannelCredentials {
final Uint8List? certificateChain;
final Uint8List? privateKey;
MyChannelCredentials({
Uint8List? trustedRoots,
this.certificateChain,
this.privateKey,
String? authority,
BadCertificateHandler? onBadCertificate,
}) : super.secure(
certificates: trustedRoots,
authority: authority,
onBadCertificate: onBadCertificate);
@override
SecurityContext get securityContext {
final ctx = super.securityContext;
if (certificateChain != null) {
ctx.useCertificateChainBytes(certificateChain);
}
if (privateKey != null) {
ctx.usePrivateKeyBytes(privateKey);
}
return ctx;
}
}
final cred = MyChannelCredentials(
trustedRoots: File('pems/ca-cert.pem').readAsBytesSync(),
certificateChain: File('pems/client-cert.pem').readAsBytesSync(),
privateKey: File('pems/client-key.pem').readAsBytesSync(),
authority: 'localhost',
);
pilotguy
Updated on December 01, 2022Comments
-
pilotguy over 1 year
I'm having a bit of trouble sorting out how to adapt my Dart gRPC client to use the same TLS settings that are working with my Go client. I've already validated that I can interface with the server suppling the correct CA cert, client cert and client key. In Go I'm using:
pemServerCA, err := ioutil.ReadFile("pems/ca-cert.pem") if err != nil { return nil, err } certPool := x509.NewCertPool() if !certPool.AppendCertsFromPEM(pemServerCA) { return nil, fmt.Errorf("failed to add server CA's certificate") } // Load client's certificate and private key clientCert, err := tls.LoadX509KeyPair("pems/client-cert.pem", "pems/client-key.pem") if err != nil { return nil, err } // Create the credentials and return it config := &tls.Config{ Certificates: []tls.Certificate{clientCert}, RootCAs: certPool, }
Just supplying that in case it helps demonstrate what's working. In Dart I'm doing this:
ChannelCredentials credentials = ChannelCredentials.secure( certificates: utf8.encode(grpcCertificate), onBadCertificate: (certificate, host) { return host == apiURL + ':' + apiPort.toString(); }, );
grpcCertificate contains the contents of client-key.pem. I suspect this is not correct. I'm not very skilled with certificates like this so I'm a bit at a loss. What value should I be supplying to certificates to achieve a successful handshake with the server?
From the above it seems like I need to parse my PEMs into X.509. In Go that's super easy, not sure how to handle this in Dart.
Edit: I've made a bit of progress:
List<int> list = grpcCertificate.codeUnits; Uint8List cert = Uint8List.fromList(list); ChannelCredentials credentials = ChannelCredentials.secure( certificates: cert, authority: 'localhost', onBadCertificate: (certificate, host) { return host == apiURL + ':' + apiPort.toString(); }, );
The server seems to hate this less and spits out:
flutter: gRPC Error (code: 14, codeName: UNAVAILABLE, message: Error connecting: TlsException: Failure trusting builtin roots (OS Error: BAD_PKCS12_DATA(pkcs8_x509.c:645), errno = 0), details: null, rawResponse: null)
Thanks.
-
Guy Luz almost 3 yearsHow funny, I have just created question that is similar in some way. If you think my questio will help you too please up vote it. stackoverflow.com/questions/68330923/…
-
Guy Luz almost 3 yearsI add answer to my question. If you find how to do this for .pem file please post here answer since I also need a solution for .pem file and not .crt and .key files.
-