首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >NodeJS STARTTLS使用SNI

NodeJS STARTTLS使用SNI
EN

Stack Overflow用户
提问于 2016-02-23 19:56:12
回答 1查看 2K关注 0票数 2

我正在Node.JS中构建一个简单的、具有STARTTLS功能的Node.JS代理,而且我遇到了很大的困难。

代理作为许多后端服务器的前端,因此它必须根据客户端的连接动态加载它们的证书。

我正在尝试使用SNICallback,这给我带来了客户端使用的服务器名,但在此之后我无法设置正确的证书,因为在创建安全上下文时,在调用之前我需要一个证书。

守则如下:

代码语言:javascript
复制
// Load libraries
var net = require('net');
var tls = require('tls');
var fs = require('fs');

// Load certificates (created with openssl)
var certs = [];
for (var i = 1; i <= 8; i++) {
   var hostName = 'localhost' + i;
   certs[hostName] = {
      key : fs.readFileSync('./private-key.pem'),
      cert : fs.readFileSync('./public-cert' + i + '.pem'),
   }
}

var server = net.createServer(function(socket) {
   socket.write('+OK localhost POP3 Proxy Ready\r\n');

   socket.on('data', function(data) {
      if (data == "STLS\r\n") {
         socket.write("+OK begin TLS negotiation\r\n");
         upgradeSocket(socket);
      } else if (data == "QUIT\r\n") {
         socket.write("+OK Logging out.\r\n");
         socket.end();
      } else {
         socket.write("-ERR unknown command.\r\n");
      }
   });

}).listen(10110);

upgradeSocket()如下所示:

代码语言:javascript
复制
function upgradeSocket(socket) {
   // I need this 'details' or handshake will fail with a message: 
   // SSL routines:ssl3_get_client_hello:no shared cipher
   var details = {
       key : fs.readFileSync('./private-key.pem'),
       cert : fs.readFileSync('./public-cert1.pem'),
   }

   var options = {
      isServer : true,
      server : server,
      SNICallback : function(serverName) {
         return tls.createSecureContext(certs[serverName]);
      },
   }

   sslcontext = tls.createSecureContext(details);
   pair = tls.createSecurePair(sslcontext, true, false, false, options);

   pair.encrypted.pipe(socket);
   socket.pipe(pair.encrypted);

   pair.fd = socket.fd;
   pair.on("secure", function() {
      console.log("TLS connection secured");
   });
}

它正确地握手,但我使用的证书是“详细信息”中的静态证书,而不是我在SNICallback中获得的证书。

为了测试它,我正在运行服务器并使用gnutls作为客户端:

代码语言:javascript
复制
~$ gnutls-cli -V -s -p 10110 --crlf --insecure -d 5 localhost3
STLS
^D (Control+D)

上面的命令应该为我获得'localhost3‘证书,但是它得到'localhost1’,因为它是在'details‘var中定义的;

对于HTTPS或TLS客户端,整个互联网上有太多的例子,这与我在这里有很大的不同,甚至对于服务器也是如此,但它们没有使用SNI。任何帮助都将不胜感激。

提前谢谢。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-06-21 12:52:44

使用tls.TLSSocket解决这个问题非常简单,尽管侦听器有一个问题。

您必须从常规net.Socket中删除所有侦听器,使用net.Socket实例化一个新的tls.TLSSocket,并将侦听器重新放到tls.TLSSocket上。

要实现这一点,可以在常规的套接字pluggableStream上使用类似于net.Socket的包装器,并将“升级”函数替换为如下所示:

代码语言:javascript
复制
pluggableStream.prototype.upgrade = function(options) {
    var self = this;
    var socket = self;
    var netSocket = self.targetsocket;

    socket.clean();

    var secureContext = tls.createSecureContext(options)
    var tlsSocket = new tls.TLSSocket(netSocket, {
        // ...
        secureContext : secureContext,
        SNICallback : options.SNICallback
        // ...
    });

    self.attach(tlsSocket);
}

您的options对象将将SNICallback定义为:

代码语言:javascript
复制
var options {
    // ...
    SNICallback : function(serverName, callback){
        callback(null, tls.createSecureContext(getCertificateFor(serverName));
    // ...
    }
}
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/35586957

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档