@@ -27,8 +27,6 @@ var stream = require('stream');
27
27
var END_OF_FILE = 42 ;
28
28
var assert = require ( 'assert' ) . ok ;
29
29
30
- var NPN_ENABLED = process . binding ( 'constants' ) . NPN_ENABLED ;
31
-
32
30
var debug ;
33
31
if ( process . env . NODE_DEBUG && / t l s / . test ( process . env . NODE_DEBUG ) ) {
34
32
debug = function ( a ) { console . error ( 'TLS:' , a ) ; } ;
@@ -40,7 +38,6 @@ if (process.env.NODE_DEBUG && /tls/.test(process.env.NODE_DEBUG)) {
40
38
var Connection = null ;
41
39
try {
42
40
Connection = process . binding ( 'crypto' ) . Connection ;
43
- exports . NPN_ENABLED = NPN_ENABLED ;
44
41
} catch ( e ) {
45
42
throw new Error ( 'node.js not compiled with openssl crypto support.' ) ;
46
43
}
@@ -478,17 +475,19 @@ EncryptedStream.prototype._pusher = function(pool, offset, length) {
478
475
*/
479
476
480
477
function SecurePair ( credentials , isServer , requestCert , rejectUnauthorized ,
481
- NPNProtocols ) {
478
+ options ) {
482
479
if ( ! ( this instanceof SecurePair ) ) {
483
480
return new SecurePair ( credentials ,
484
481
isServer ,
485
482
requestCert ,
486
483
rejectUnauthorized ,
487
- NPNProtocols ) ;
484
+ options ) ;
488
485
}
489
486
490
487
var self = this ;
491
488
489
+ options || ( options = { } ) ;
490
+
492
491
events . EventEmitter . call ( this ) ;
493
492
494
493
this . _secureEstablished = false ;
@@ -514,11 +513,19 @@ function SecurePair(credentials, isServer, requestCert, rejectUnauthorized,
514
513
this . _requestCert = requestCert ? true : false ;
515
514
516
515
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 ,
518
518
this . _rejectUnauthorized ) ;
519
519
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 ) ;
522
529
this . npnProtocol = null ;
523
530
}
524
531
@@ -629,9 +636,14 @@ SecurePair.prototype.cycle = function(depth) {
629
636
630
637
SecurePair . prototype . maybeInitFinished = function ( ) {
631
638
if ( this . ssl && ! this . _secureEstablished && this . ssl . isInitFinished ( ) ) {
632
- if ( NPN_ENABLED ) {
639
+ if ( process . features . tls_npn ) {
633
640
this . npnProtocol = this . ssl . getNegotiatedProtocol ( ) ;
634
641
}
642
+
643
+ if ( process . features . tls_sni ) {
644
+ this . servername = this . ssl . getServername ( ) ;
645
+ }
646
+
635
647
this . _secureEstablished = true ;
636
648
debug ( 'secure established' ) ;
637
649
this . emit ( 'secure' ) ;
@@ -789,14 +801,19 @@ function Server(/* [options], listener */) {
789
801
true ,
790
802
self . requestCert ,
791
803
self . rejectUnauthorized ,
792
- self . NPNProtocols ) ;
804
+ {
805
+ NPNProtocols : self . NPNProtocols ,
806
+ SNICallback : self . SNICallback
807
+ } ) ;
793
808
794
809
var cleartext = pipe ( pair , socket ) ;
795
810
cleartext . _controlReleased = false ;
796
811
797
812
pair . on ( 'secure' , function ( ) {
798
813
pair . cleartext . authorized = false ;
799
814
pair . cleartext . npnProtocol = pair . npnProtocol ;
815
+ pair . cleartext . servername = pair . servername ;
816
+
800
817
if ( ! self . requestCert ) {
801
818
cleartext . _controlReleased = true ;
802
819
self . emit ( 'secureConnection' , pair . cleartext , pair . encrypted ) ;
@@ -858,6 +875,38 @@ Server.prototype.setOptions = function(options) {
858
875
if ( options . secureProtocol ) this . secureProtocol = options . secureProtocol ;
859
876
if ( options . secureOptions ) this . secureOptions = options . secureOptions ;
860
877
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 ;
861
910
} ;
862
911
863
912
@@ -902,7 +951,10 @@ exports.connect = function(port /* host, options, cb */) {
902
951
903
952
convertNPNProtocols ( options . NPNProtocols , this ) ;
904
953
var pair = new SecurePair ( sslcontext , false , true , false ,
905
- this . NPNProtocols ) ;
954
+ {
955
+ NPNProtocols : this . NPNProtocols ,
956
+ servername : options . servername
957
+ } ) ;
906
958
907
959
var cleartext = pipe ( pair , socket ) ;
908
960
0 commit comments