带PEM的Dart gRPC TLS证书

dced5bon  于 2022-12-20  发布在  其他
关注(0)|答案(1)|浏览(160)

我遇到了一点麻烦,就是如何让Dart gRPC客户端使用与Go语言客户端相同的TLS设置。我已经验证了我可以通过提供正确的CA证书、客户端证书和客户端密钥来与服务器接口。在Go语言中,我使用的是:

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,
    }

只是为了证明什么是有效的,在Dart中我是这样做的:

ChannelCredentials credentials = ChannelCredentials.secure(
    certificates: utf8.encode(grpcCertificate),
    onBadCertificate: (certificate, host) {
      return host == apiURL + ':' + apiPort.toString();
    },
  );

grpcCertificate包含client-key. pem的内容。我怀疑这是不正确的。我对这类证书不是很熟练,所以我有点不知所措。我应该为证书提供什么值才能实现与服务器的成功握手?
从上面的内容看,我似乎需要将PEM解析为X.509。在Go语言中,这非常容易,但不知道如何在Dart中处理这一点。
编辑:我取得了一点进展:

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();
      },
    );

服务器似乎不太讨厌这种情况,并吐出:

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)

谢谢。

stszievb

stszievb1#

最后我在grpc-dart问题页面上得到了一个比较恰当的答案,解决方案如下所示:

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',
);

相关问题