@@ -9,7 +9,6 @@ var debugLevel = process.env['NODE_DEBUG'] ? 1 : 0;
9
9
function debug ( ) {
10
10
if ( debugLevel > 0 ) sys . error . apply ( this , arguments ) ;
11
11
}
12
-
13
12
var binding = process . binding ( 'net' ) ;
14
13
15
14
// Note about Buffer interface:
@@ -45,6 +44,14 @@ var EINPROGRESS = binding.EINPROGRESS;
45
44
var ENOENT = binding . ENOENT ;
46
45
var END_OF_FILE = 42 ;
47
46
47
+ // Do we have openssl crypto?
48
+ try {
49
+ var SecureContext = process . binding ( 'crypto' ) . SecureContext ;
50
+ var SecureStream = process . binding ( 'crypto' ) . SecureStream ;
51
+ var crypto = true ;
52
+ } catch ( e ) {
53
+ var crypto = false ;
54
+ }
48
55
49
56
// IDLE TIMEOUTS
50
57
//
@@ -246,6 +253,16 @@ function allocNewPool () {
246
253
pool . used = 0 ;
247
254
}
248
255
256
+ var securePool = null ;
257
+ function allocNewSecurePool ( ) {
258
+ securePool = new Buffer ( 40 * 1024 ) ;
259
+ }
260
+ var emptyBuffer = null ;
261
+ function allocEmptyBuffer ( ) {
262
+ emptyBuffer = new Buffer ( 1 ) ;
263
+ emptyBuffer . sent = 0 ;
264
+ emptyBuffer . length = 0 ;
265
+ }
249
266
250
267
function _doFlush ( ) {
251
268
var socket = this . socket ;
@@ -271,20 +288,46 @@ function initStream (self) {
271
288
272
289
//debug('pool.used ' + pool.used);
273
290
var bytesRead ;
291
+ var secureBytesRead ;
274
292
275
293
try {
276
- bytesRead = read ( self . fd ,
294
+ if ( self . secure ) {
295
+ if ( ! securePool ) allocNewSecurePool ( ) ;
296
+ secureBytesRead = read ( self . fd , securePool , 0 , securePool . length ) ;
297
+ self . secureStream . readInject ( securePool , 0 , secureBytesRead ) ;
298
+ bytesRead = self . secureStream . readExtract ( pool , pool . used , pool . length - pool . used ) ;
299
+ if ( ! self . secureEstablished ) {
300
+ if ( self . secureStream . isInitFinished ( ) ) {
301
+ self . secureEstablished = true ;
302
+ if ( self . _events && self . _events [ 'secure' ] ) self . emit ( 'secure' ) ;
303
+ }
304
+ }
305
+ if ( secureBytesRead === null && ! self . server ) {
306
+ // Client needs to write as part of handshake
307
+ this . _writeWatcher . start ( ) ;
308
+ }
309
+ } else {
310
+ bytesRead = read ( self . fd ,
277
311
pool ,
278
312
pool . used ,
279
- pool . length - pool . used ) ;
313
+ pool . length - pool . used ) ;
314
+ }
280
315
} catch ( e ) {
281
- self . forceClose ( e ) ;
316
+ if ( this . forceClose ) this . forceClose ( e ) ;
282
317
return ;
283
318
}
284
319
285
320
//debug('bytesRead ' + bytesRead + '\n');
286
321
287
- if ( bytesRead === 0 ) {
322
+ if ( self . secure && bytesRead == 0 && secureBytesRead > 0 ) {
323
+ // Deal with SSL handshake
324
+ if ( self . server ) {
325
+ self . _checkForSecureHandshake ( ) ;
326
+ } else {
327
+ if ( self . secureEstablised ) self . flush ( ) ;
328
+ else self . _checkForSecureHandshake ( ) ;
329
+ }
330
+ } else if ( bytesRead === 0 ) {
288
331
self . readable = false ;
289
332
self . _readWatcher . stop ( ) ;
290
333
@@ -341,10 +384,36 @@ function initStream (self) {
341
384
self . writable = false ;
342
385
}
343
386
387
+ function Credentials ( method ) {
388
+ if ( ! crypto ) {
389
+ throw new Error ( 'node.js not compiled with openssl crypto support.' ) ;
390
+ }
391
+ this . context = new SecureContext ( ) ;
392
+ if ( method ) this . context . init ( method ) ;
393
+ else this . context . init ( ) ;
394
+ }
395
+
396
+ exports . createCredentials = function ( cred ) {
397
+ var c = new Credentials ( cred . method ) ;
398
+ if ( cred . key ) c . context . setKey ( cred . key ) ;
399
+ if ( cred . cert ) c . context . setCert ( cred . cert ) ;
400
+ if ( cred . ca ) {
401
+ if ( ( typeof ( cred . ca ) == 'object' ) && cred . ca . length ) {
402
+ for ( var i = 0 ; i < cred . ca . length ; i ++ )
403
+ c . context . addCACert ( cred . ca [ i ] ) ;
404
+ } else {
405
+ c . context . addCACert ( cred . ca ) ;
406
+ }
407
+ }
408
+ return c ;
409
+ }
410
+ exports . Credentials = Credentials ;
411
+
344
412
function Stream ( fd ) {
345
413
events . EventEmitter . call ( this ) ;
346
414
347
415
this . fd = null ;
416
+ this . secure = false ;
348
417
349
418
if ( parseInt ( fd ) >= 0 ) {
350
419
this . open ( fd ) ;
@@ -353,6 +422,55 @@ function Stream (fd) {
353
422
sys . inherits ( Stream , events . EventEmitter ) ;
354
423
exports . Stream = Stream ;
355
424
425
+ Stream . prototype . setSecure = function ( credentials ) {
426
+ if ( ! crypto ) {
427
+ throw new Error ( 'node.js not compiled with openssl crypto support.' ) ;
428
+ }
429
+ this . secure = true ;
430
+ this . secureEstablished = false ;
431
+ // If no credentials given, create a new one for just this Stream
432
+ if ( ! credentials ) {
433
+ this . credentials = new Credentials ( ) ;
434
+ } else {
435
+ this . credentials = credentials ;
436
+ }
437
+ this . secureStream = new SecureStream ( this . credentials . context , this . server ?1 :0 ) ;
438
+
439
+ if ( ! this . server ) {
440
+ // If client, trigger handshake
441
+ this . _checkForSecureHandshake ( ) ;
442
+ }
443
+
444
+
445
+ }
446
+
447
+ Stream . prototype . verifyPeer = function ( ) {
448
+ if ( ! this . secure ) {
449
+ throw new Error ( 'Stream is not a secure stream.' ) ;
450
+ }
451
+ return this . secureStream . verifyPeer ( this . credentials . context ) ;
452
+ }
453
+
454
+ Stream . prototype . _checkForSecureHandshake = function ( ) {
455
+ // Do an empty write to see if we need to write out as part of handshake
456
+ if ( ! emptyBuffer ) allocEmptyBuffer ( ) ;
457
+ this . write ( emptyBuffer ) ;
458
+ }
459
+
460
+ Stream . prototype . getPeerCertificate = function ( credentials ) {
461
+ if ( ! this . secure ) {
462
+ throw new Error ( 'Stream is not a secure stream.' ) ;
463
+ }
464
+ return this . secureStream . getPeerCertificate ( ) ;
465
+ }
466
+
467
+ Stream . prototype . getCipher = function ( ) {
468
+ if ( ! this . secure ) {
469
+ throw new Error ( 'Stream is not a secure stream.' ) ;
470
+ }
471
+ return this . secureStream . getCurrentCipher ( ) ;
472
+ }
473
+
356
474
357
475
Stream . prototype . open = function ( fd ) {
358
476
initStream ( this ) ;
@@ -411,6 +529,15 @@ Stream.prototype.write = function (data, encoding) {
411
529
} ;
412
530
413
531
532
+ Stream . prototype . _shutdownSecure = function ( ) {
533
+ this . secureStream . shutdown ( ) ;
534
+ if ( ! securePool ) allocNewSecurePool ( ) ;
535
+ var secureLen = this . secureStream . writeExtract ( securePool , 0 , securePool . length ) ;
536
+ try {
537
+ var secureBytesWritten = write ( this . fd , securePool , 0 , secureLen ) ;
538
+ } catch ( e ) { }
539
+ }
540
+
414
541
// Directly writes the data to socket.
415
542
//
416
543
// Steps:
@@ -420,14 +547,15 @@ Stream.prototype.write = function (data, encoding) {
420
547
// 3. Slice out remaining
421
548
// 4. Unshift remaining onto _writeQueue. Return false.
422
549
Stream . prototype . _writeOut = function ( data , encoding ) {
423
- if ( ! this . writable ) throw new Error ( 'Stream is not writable' ) ;
550
+ if ( ! this . writable ) {
551
+ if ( this . secure ) return false ;
552
+ else throw new Error ( 'Stream is not writable' ) ;
553
+ }
424
554
425
555
426
556
var buffer , off , len ;
427
557
var bytesWritten , charsWritten ;
428
-
429
558
var queuedData = false ;
430
-
431
559
if ( typeof data != 'string' ) {
432
560
// 'data' is a buffer, ignore 'encoding'
433
561
buffer = data ;
@@ -458,7 +586,7 @@ Stream.prototype._writeOut = function (data, encoding) {
458
586
assert ( charsWritten <= data . length ) ;
459
587
}
460
588
461
- assert ( bytesWritten > 0 ) ;
589
+ if ( encoding ) assert ( bytesWritten > 0 ) ;
462
590
463
591
buffer = pool ;
464
592
len = bytesWritten ;
@@ -478,11 +606,26 @@ Stream.prototype._writeOut = function (data, encoding) {
478
606
}
479
607
}
480
608
481
-
482
- // Send the buffer.
483
-
484
609
try {
485
- bytesWritten = write ( this . fd , buffer , off , len ) ;
610
+ if ( this . secure ) {
611
+ if ( ! buffer ) return false ;
612
+ bytesWritten = this . secureStream . writeInject ( buffer , off , len ) ;
613
+ if ( ! securePool ) allocNewSecurePool ( ) ;
614
+ var secureLen = this . secureStream . writeExtract ( securePool , 0 , securePool . length ) ;
615
+ if ( secureLen == - 1 ) {
616
+ // Check our read again for secure handshake
617
+ this . _readWatcher . callback ( ) ;
618
+ secureBytesWritten = 0 ;
619
+ } else {
620
+ var secureBytesWritten = write ( this . fd , securePool , 0 , secureLen ) ;
621
+ }
622
+ if ( ! this . secureEstablished && this . secureStream . isInitFinished ( ) ) {
623
+ this . secureEstablished = true ;
624
+ if ( this . _events && this . _events [ 'secure' ] ) this . emit ( 'secure' ) ;
625
+ }
626
+ } else {
627
+ bytesWritten = write ( this . fd , buffer , off , len ) ;
628
+ }
486
629
} catch ( e ) {
487
630
this . forceClose ( e ) ;
488
631
return false ;
@@ -675,6 +818,10 @@ Stream.prototype.forceClose = function (exception) {
675
818
676
819
timeout . unenroll ( this ) ;
677
820
821
+ if ( this . secure ) {
822
+ this . secureStream . close ( ) ;
823
+ }
824
+
678
825
// FIXME Bug when this.fd == 0
679
826
if ( typeof this . fd == 'number' ) {
680
827
close ( this . fd ) ;
@@ -691,6 +838,9 @@ Stream.prototype._shutdown = function () {
691
838
if ( this . writable ) {
692
839
this . writable = false ;
693
840
841
+ if ( this . secure ) {
842
+ this . _shutdownSecure ( ) ;
843
+ }
694
844
try {
695
845
shutdown ( this . fd , 'write' )
696
846
} catch ( e ) {
0 commit comments