title: NodeJS STARTTLS Use SNI
body: <p>I'm building a simple, STARTTLS capable POP3 Proxy in Node.JS and I'm having quite a hard time.</p>
  
  <p>The proxy serves as a front-end for many back-end servers, so it must load their certificates dynamically, depending on the Client's connection.</p>
  
  <p>I'm trying to use the SNICallback, which brings me the servername the client uses, but I can't set the right certificate after this, because I need one certificate before I have this call, when I create the secure context.</p>
  
  <p>The code is as bellow:</p>
  
  <pre><code>// 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 &lt;= 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);
  </code></pre>
  
  <p>and upgradeSocket() is as follows:</p>
  
  <pre><code>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");
     });
  }
  </code></pre>
  
  <p>It handshakes correctly but the certificate I use is the static one in 'details', not the one I get in the SNICallback.</p>
  
  <p>To test it I'm running the server and using gnutls-cli as a Client:</p>
  
  <pre><code>~$ gnutls-cli -V -s -p 10110 --crlf --insecure -d 5 localhost3
  STLS
  ^D (Control+D)
  </code></pre>
  
  <p>The above command is supposed to get me the 'localhost3' certificate but it's getting the 'localhost1' because it's defined in 'details' var;</p>
  
  <p>There are just too many examples throughout the internet with HTTPS or for TLS Clients, which it's a lot different from what I have here, and even for Servers as well but they're not using SNI. Any help will be appreciated.</p>
  
  <p>Thanks in advance.</p>