请使用ssl证书进行dart https请求

时间:2014-08-19 16:42:42

标签: ssl https request dart certificate

我有以下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);

我已经达到以下目标: -

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.
     });
}

但是在文档中找不到任何东西,它告诉你如何将证书添加到HttpClient或HttpRequest?感谢任何帮助提前多多感谢。

2 个答案:

答案 0 :(得分:4)

现在可以在Dart中完成在HTTPS请求中发送客户端证书,就像在node.js中一样,从版本1.13.0开始。在发出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.
}

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

答案 1 :(得分:3)

可以使用带有dart:io HTTPS请求的客户端证书。然而,由于在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,一个localhost服务器证书和一个客户端证书。使用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

回答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

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

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

这个客户:

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

希望客户提供客户证书。然而,这依赖于NSS选择客户端证书,我不确定这个规则。如果您使用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();
}

希望有所帮助。