Dart https要求提供SSL证书

Pys*_*ete 5 ssl https certificate request dart

我有以下Javascript代码,当我使用nodejs运行它时可以正常工作。但是,我想写一些与Dart相似的东西。我已经遍历了Dart文档,找不到任何示例。如果有人可以告诉我如何使用Google Dart重写以下内容,我将不胜感激。提前谢谢了!

var https = require('https');
var fs = require('fs');
var url = require('url');

var uri = "https://identitysso-api.betfair.com:443/api/certlogin";
var data = 'username=xxxxxxxx&password=xxxxxxxx';
var appKey = 'xxxxxxxxxxxxxx'

var options = url.parse(uri);
options.method = 'POST';
options.headers = {
    'Content-Type': 'application/x-www-form-urlencoded',
    'X-Application': appKey
};
options.key = fs.readFileSync('client-2048.key');
options.cert = fs.readFileSync('client-2048.crt');
options.agent = new https.Agent(options);

var req = https.request(options, function(res) {
    console.log("statusCode:", res.statusCode);
    var responseData = "";
    res.on('data', function(d) {
        responseData += d;
    });
    res.on('end', function() {
        var response = JSON.parse(responseData);
        console.log("sessionToken:", response.sessionToken.replace(/\d/g, ''));
    });
    res.on('error', function(e) {
        console.error(e);
    });
});

req.end(data);
Run Code Online (Sandbox Code Playgroud)

我已经了解到以下内容:

import 'dart:io';

void main() {
    var uri = "https://identitysso-api.betfair.com:443/api/certlogin";
    var data = 'username=xxxxxxxx&password=xxxxxxxx';
    var appKey = 'xxxxxxxxxxxx';
    var method = 'POST';

    HttpClient client = new HttpClient();
    client.openUrl(method,Uri.parse(uri))
    .then((HttpClientRequest request) {
        request.headers.set(HttpHeaders.CONTENT_TYPE, 'application/x-www-form-urlencoded');
        request.headers.set('X-Application', appKey);
        request.write(data);
        return request.close();
     })
     .then((HttpClientResponse response) {
    // Process the response.
     });
}
Run Code Online (Sandbox Code Playgroud)

但是在文档中找不到任何内容,该文档告诉您如何向HttpClient或HttpRequest添加证书?任何帮助表示感谢,预先表示感谢。

小智 6

从版本 1.13.0 开始,现在可以在 Dart 中像在 node.js 中一样轻松地在 HTTPS 请求中发送客户端证书。在您发出 HTTPS 请求之前,可以将 PEM 格式的客户端证书和密钥添加到默认的 SecurityContext 对象。

Dart 现在已改用 BoringSSL,这是 Google 维护的 OpenSSL 的一个分支。BoringSSL 使用以 PEM 格式存储在文件中的 X509 证书(SSL 和 TLS 使用的证书)。旧版本的 Dart 使用 NSS,它有自己的证书和密钥数据库,由命令行工具维护。Dart 更改了 SecureSocket 方法的一些参数,并添加了一个 SecurityContext 类。

SecurityContext.defaultContext 是一个包含知名证书颁发机构的内置可信根的对象,取自 Mozilla 用于 Firefox 和 NSS 的数据库。所以你的客户端应该使用这个对象,并向它添加客户端证书和私钥,这样它们将用于向请求它们的服务器进行身份验证:

Future postWithClientCertificate() async {
  var context = SecurityContext.defaultContext;
  context.useCertificateChain('client-2048.crt');
  context.usePrivateKey('client-2048.key',
                        password:'keyfile_password');
  HttpClient client = new HttpClient(context: context);

  // The rest of this code comes from your question.
  var uri = "https://identitysso-api.betfair.com:443/api/certlogin";
  var data = 'username=xxxxxxxx&password=xxxxxxxx';
  var appKey = 'xxxxxxxxxxxx';
  var method = 'POST';

  var request = await client.openUrl(method,Uri.parse(uri))
  request.headers.set(HttpHeaders.CONTENT_TYPE,
                      'application/x-www-form-urlencoded');
  request.headers.set('X-Application', appKey);
  request.write(data);
  var response = await request.close();
  // Process the response.
}
Run Code Online (Sandbox Code Playgroud)

函数 SecurityContext.useCertificateChain 和 SecurityContext.usePrivateKey 与用于为 SecureServerSocket 设置服务器证书和密钥的函数相同,但是当上下文用于客户端连接时,它们指定要根据请求发送的客户端证书。


sgj*_*sse 3

可以将客户端证书与HTTPS 请求一起dart:io使用。然而,由于 Dart 中 SSL/TLS 的实现方式,它有点复杂。

Dart 使用 Mozilla NSS 库来实现 SSL/TLS。NSS 将其所有密钥和证书存储在数据库中。该SecureSocket.initialize调用用于选择要使用的 NSS 数据库。如果未指定数据库,则将使用内置数据库。内置数据库仅包含受信任的根证书。

要使用客户端证书,您需要使用证书和密钥创建 NSS 数据库。使用 NSS 工具操作数据库certutil,该工具记录在此处:

https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSS/Reference/NSS_tools_:_certutil

此示例创建一个包含三个证书的数据库:一个自签名 CA、一个本地主机服务器证书和一个客户端证书。用作testtest密码。

$ mkdir certdb
$ certutil -N -d sql:certdb
$ certutil -S -s "CN=Example CA" -n my-ca-cert -x -t "TCu,u,u" -5 sslCA -m 1234 -d sql:certdb
Run Code Online (Sandbox Code Playgroud)

答案 9 和 N

$ certutil -S -s "CN=localhost" -n my-server-cert -c "my-ca-cert" -t "u,u,u" -m 730 -d sql:certdb
$ certutil -S -s "CN=sgjesse" -n my-client-cert -c "my-ca-cert" -t "Pu,u,u" -m 731 -d sql:certdb
Run Code Online (Sandbox Code Playgroud)

然后你可以运行这个服务器:

import "dart:async";
import "dart:io";

void serve() {
  HttpServer.bindSecure('localhost',
                        8080,
                        certificateName: 'my-server-cert',
                        requestClientCertificate: true).then((server) {
    server.listen((HttpRequest request) {
      if (request.certificate != null) {
        print('Client certificate ${request.certificate.subject}');
      } else {
        print('No client certificate');
      }
      request.response.write("Hello");
      request.response.close();
    });
  });
}

void InitializeSSL() {
  var testPkcertDatabase = Platform.script.resolve('certdb').toFilePath();
  SecureSocket.initialize(database: testPkcertDatabase,
                          password: 'testtest');
}

void main() {
  InitializeSSL();
  serve();
}
Run Code Online (Sandbox Code Playgroud)

还有这个客户:

import "dart:async";
import "dart:io";

void request() {
  HttpClient client = new HttpClient();
  client.getUrl(Uri.parse("https://localhost:8080/"))
      .then((request) => request.close())
      .then((response) {
        print('Subject: ${response.certificate.subject}');
        print('Issuer: ${response.certificate.issuer}');
        return response.transform(UTF8.decoder).join('');
      })
     .then(print);
}

void InitializeSSL() {
  var testPkcertDatabase = Platform.script.resolve('certdb').toFilePath();
  SecureSocket.initialize(database: testPkcertDatabase,
                          password: 'testtest');
}

void main() {
  InitializeSSL();
  request();
}
Run Code Online (Sandbox Code Playgroud)

希望客户能够出示客户证书。然而,这依赖于 NSS 选择客户端证书,我不确定这方面的规则。如果您使用 a,则SecureSocket可以显式选择客户端证书,但目前对于 HTTPS 来说这是不可能的,请参阅https://code.google.com/p/dart/issues/detail?id=8872

这是一个使用的客户端SecureSocket

import "dart:async";
import "dart:io";

void request() {
  SecureSocket.connect('localhost',
                       8080,
                       sendClientCertificate: true,
                       certificateName: 'my-client-cert').then((socket) {
    socket.write("GET / HTTP/1.0\r\n\r\n");
    socket.listen(print);
  });
}

void InitializeSSL() {
  var testPkcertDatabase = Platform.script.resolve('certdb').toFilePath();
  SecureSocket.initialize(database: testPkcertDatabase,
                          password: 'testtest');
}

void main() {
  InitializeSSL();
  request();
}
Run Code Online (Sandbox Code Playgroud)

希望有帮助。