@@ -27,8 +27,6 @@ var stream = require('stream');
2727var END_OF_FILE = 42 ;
2828var assert = require ( 'assert' ) . ok ;
2929
30- var NPN_ENABLED = process . binding ( 'constants' ) . NPN_ENABLED ;
31-
3230var debug ;
3331if ( process . env . NODE_DEBUG && / t l s / . test ( process . env . NODE_DEBUG ) ) {
3432 debug = function ( a ) { console . error ( 'TLS:' , a ) ; } ;
@@ -40,7 +38,6 @@ if (process.env.NODE_DEBUG && /tls/.test(process.env.NODE_DEBUG)) {
4038var Connection = null ;
4139try {
4240 Connection = process . binding ( 'crypto' ) . Connection ;
43- exports . NPN_ENABLED = NPN_ENABLED ;
4441} catch ( e ) {
4542 throw new Error ( 'node.js not compiled with openssl crypto support.' ) ;
4643}
@@ -478,17 +475,19 @@ EncryptedStream.prototype._pusher = function(pool, offset, length) {
478475 */
479476
480477function SecurePair ( credentials , isServer , requestCert , rejectUnauthorized ,
481- NPNProtocols ) {
478+ options ) {
482479 if ( ! ( this instanceof SecurePair ) ) {
483480 return new SecurePair ( credentials ,
484481 isServer ,
485482 requestCert ,
486483 rejectUnauthorized ,
487- NPNProtocols ) ;
484+ options ) ;
488485 }
489486
490487 var self = this ;
491488
489+ options || ( options = { } ) ;
490+
492491 events . EventEmitter . call ( this ) ;
493492
494493 this . _secureEstablished = false ;
@@ -514,11 +513,19 @@ function SecurePair(credentials, isServer, requestCert, rejectUnauthorized,
514513 this . _requestCert = requestCert ? true : false ;
515514
516515 this . ssl = new Connection ( this . credentials . context ,
517- this . _isServer ? true : false , this . _requestCert ,
516+ this . _isServer ? true : false ,
517+ this . _isServer ? this . _requestCert : options . servername ,
518518 this . _rejectUnauthorized ) ;
519519
520- if ( NPN_ENABLED && NPNProtocols ) {
521- this . ssl . setNPNProtocols ( NPNProtocols ) ;
520+ if ( process . features . tls_sni ) {
521+ if ( this . _isServer && options . SNICallback ) {
522+ this . ssl . setSNICallback ( options . SNICallback ) ;
523+ }
524+ this . servername = null ;
525+ }
526+
527+ if ( process . features . tls_npn && options . NPNProtocols ) {
528+ this . ssl . setNPNProtocols ( options . NPNProtocols ) ;
522529 this . npnProtocol = null ;
523530 }
524531
@@ -629,9 +636,14 @@ SecurePair.prototype.cycle = function(depth) {
629636
630637SecurePair . prototype . maybeInitFinished = function ( ) {
631638 if ( this . ssl && ! this . _secureEstablished && this . ssl . isInitFinished ( ) ) {
632- if ( NPN_ENABLED ) {
639+ if ( process . features . tls_npn ) {
633640 this . npnProtocol = this . ssl . getNegotiatedProtocol ( ) ;
634641 }
642+
643+ if ( process . features . tls_sni ) {
644+ this . servername = this . ssl . getServername ( ) ;
645+ }
646+
635647 this . _secureEstablished = true ;
636648 debug ( 'secure established' ) ;
637649 this . emit ( 'secure' ) ;
@@ -789,14 +801,19 @@ function Server(/* [options], listener */) {
789801 true ,
790802 self . requestCert ,
791803 self . rejectUnauthorized ,
792- self . NPNProtocols ) ;
804+ {
805+ NPNProtocols : self . NPNProtocols ,
806+ SNICallback : self . SNICallback
807+ } ) ;
793808
794809 var cleartext = pipe ( pair , socket ) ;
795810 cleartext . _controlReleased = false ;
796811
797812 pair . on ( 'secure' , function ( ) {
798813 pair . cleartext . authorized = false ;
799814 pair . cleartext . npnProtocol = pair . npnProtocol ;
815+ pair . cleartext . servername = pair . servername ;
816+
800817 if ( ! self . requestCert ) {
801818 cleartext . _controlReleased = true ;
802819 self . emit ( 'secureConnection' , pair . cleartext , pair . encrypted ) ;
@@ -858,6 +875,38 @@ Server.prototype.setOptions = function(options) {
858875 if ( options . secureProtocol ) this . secureProtocol = options . secureProtocol ;
859876 if ( options . secureOptions ) this . secureOptions = options . secureOptions ;
860877 if ( options . NPNProtocols ) convertNPNProtocols ( options . NPNProtocols , this ) ;
878+ if ( options . SNICallback ) {
879+ this . SNICallback = options . SNICallback ;
880+ } else {
881+ this . SNICallback = this . SNICallback . bind ( this ) ;
882+ }
883+ } ;
884+
885+ // SNI Contexts High-Level API
886+ Server . prototype . _contexts = [ ] ;
887+ Server . prototype . addContext = function ( servername , credentials ) {
888+ if ( ! servername ) {
889+ throw 'Servername is required parameter for Server.addContext' ;
890+ }
891+
892+ var re = new RegExp ( '^' +
893+ servername . replace ( / ( [ \. ^ $ + ? \- \\ [ \] { } ] ) / g, '\\$1' )
894+ . replace ( / \* / g, '.*' ) +
895+ '$' ) ;
896+ this . _contexts . push ( [ re , crypto . createCredentials ( credentials ) . context ] ) ;
897+ } ;
898+
899+ Server . prototype . SNICallback = function ( servername ) {
900+ var ctx ;
901+
902+ this . _contexts . some ( function ( elem ) {
903+ if ( servername . match ( elem [ 0 ] ) !== null ) {
904+ ctx = elem [ 1 ] ;
905+ return true ;
906+ }
907+ } ) ;
908+
909+ return ctx ;
861910} ;
862911
863912
@@ -902,7 +951,10 @@ exports.connect = function(port /* host, options, cb */) {
902951
903952 convertNPNProtocols ( options . NPNProtocols , this ) ;
904953 var pair = new SecurePair ( sslcontext , false , true , false ,
905- this . NPNProtocols ) ;
954+ {
955+ NPNProtocols : this . NPNProtocols ,
956+ servername : options . servername
957+ } ) ;
906958
907959 var cleartext = pipe ( pair , socket ) ;
908960
0 commit comments