@@ -108,9 +108,18 @@ function SSLObservatory() {
108108
109109 this . compatJSON = Cc [ "@mozilla.org/dom/json;1" ] . createInstance ( Ci . nsIJSON ) ;
110110
111+ // XXX: We shouldn't register any observers or listeners unless the enabled
112+ // pref is set. This goes for the cookie-changed observer above, too..
113+ // (But for this, we need a pref-changed observer)
114+ //
111115 // Register observer
112116 OS . addObserver ( this , "http-on-examine-response" , false ) ;
113117
118+ var dls = CC [ '@mozilla.org/docloaderservice;1' ]
119+ . getService ( CI . nsIWebProgress ) ;
120+ dls . addProgressListener ( this ,
121+ Ci . nsIWebProgress . NOTIFY_STATE_REQUEST ) ;
122+
114123 // Register protocolproxyfilter
115124 this . pps = CC [ "@mozilla.org/network/protocol-proxy-service;1" ]
116125 . getService ( CI . nsIProtocolProxyService ) ;
@@ -139,7 +148,9 @@ SSLObservatory.prototype = {
139148 [ CI . nsIObserver ,
140149 CI . nsIProtocolProxyFilter ,
141150 //CI.nsIWifiListener,
142- CI . nsIBadCertListener2 ] ) ,
151+ CI . nsIWebProgressListener ,
152+ CI . nsISupportsWeakReference ,
153+ CI . nsIInterfaceRequestor ] ) ,
143154
144155 wrappedJSObject : null , // Initialized by constructor
145156
@@ -149,7 +160,7 @@ SSLObservatory.prototype = {
149160 contractID : SERVICE_CTRID ,
150161
151162 // https://developer.mozilla.org/En/How_to_check_the_security_state_of_an_XMLHTTPRequest_over_SSL
152- getSSLCert : function ( channel ) {
163+ getSSLCertChain : function ( channel ) {
153164 try {
154165 // Do we have a valid channel argument?
155166 if ( ! channel instanceof Ci . nsIChannel ) {
@@ -299,6 +310,49 @@ SSLObservatory.prototype = {
299310 return ( cert . md5Fingerprint + cert . sha1Fingerprint ) . replace ( ":" , "" , "g" ) ;
300311 } ,
301312
313+ // onSecurity is used to listen for bad cert warnings
314+ onStateChange : function ( aProgress , aRequest , aState , aStatus ) {
315+ if ( ! aRequest ) return ;
316+ var chan = null ;
317+ try {
318+ chan = aRequest . QueryInterface ( Ci . nsIHttpChannel ) ;
319+ } catch ( e ) {
320+ return ;
321+ }
322+ if ( chan ) {
323+ if ( ! this . observatoryActive ( chan ) ) return ;
324+ var certchain = this . getSSLCertChain ( chan ) ;
325+ if ( certchain ) {
326+ this . log ( INFO , "Got state cert chain for "
327+ + chan . originalURI . spec + "->" + chan . URI . spec + ", state: " + aState ) ;
328+ this . submitCertChainForChannel ( certchain , chan ) ;
329+ }
330+ }
331+ } ,
332+
333+ // onSecurityStateChange is used to listen for bad cert warnings
334+ // XXX: This is disabled. It does not handle subdocuments, but onStateChange does.
335+ onSecurityChange : function ( aProgress , aRequest , aState ) {
336+ if ( ! aRequest ) return ;
337+ var chan = null ;
338+ try {
339+ chan = aRequest . QueryInterface ( Ci . nsIHttpChannel ) ;
340+ } catch ( e ) {
341+ return ;
342+ }
343+ if ( chan ) {
344+ if ( ! this . observatoryActive ( chan ) ) return ;
345+ this . log ( INFO , "Got security state change for "
346+ + chan . originalURI . spec + "->" + chan . URI . spec + ", state: " + aState ) ;
347+ var certchain = this . getSSLCertChain ( chan ) ;
348+ if ( certchain ) {
349+ this . log ( INFO , "Got cert chain for "
350+ + chan . originalURI . spec + "->" + chan . URI . spec + ", state: " + aState ) ;
351+ this . submitCertChainForChannel ( certchain , chan ) ;
352+ }
353+ }
354+ } ,
355+
302356 observe : function ( subject , topic , data ) {
303357 if ( topic == "cookie-changed" && data == "cleared" ) {
304358 this . already_submitted = { } ;
@@ -330,46 +384,51 @@ SSLObservatory.prototype = {
330384 var channel = subject ;
331385 if ( ! this . observatoryActive ( channel ) ) return ;
332386
387+ var certchain = this . getSSLCertChain ( subject ) ;
388+ this . submitCertChainForChannel ( certchain , channel ) ;
389+ }
390+ } ,
391+
392+ submitCertChainForChannel : function ( certchain , channel ) {
393+ if ( certchain ) {
333394 var host_ip = "-1" ;
334- var httpchannelinternal = subject . QueryInterface ( Ci . nsIHttpChannelInternal ) ;
395+ var httpchannelinternal = channel . QueryInterface ( Ci . nsIHttpChannelInternal ) ;
335396 try {
336397 host_ip = httpchannelinternal . remoteAddress ;
337398 } catch ( e ) {
338399 this . log ( INFO , "Could not get server IP address." ) ;
339400 }
340- subject . QueryInterface ( Ci . nsIHttpChannel ) ;
341- var certchain = this . getSSLCert ( subject ) ;
342- if ( certchain ) {
343- var chainEnum = certchain . getChain ( ) ;
344- var chainArray = [ ] ;
345- var chainArrayFpStr = '' ;
346- var fps = [ ] ;
347- for ( var i = 0 ; i < chainEnum . length ; i ++ ) {
348- var cert = chainEnum . queryElementAt ( i , Ci . nsIX509Cert ) ;
349- chainArray . push ( cert ) ;
350- var fp = this . ourFingerprint ( cert ) ;
351- fps . push ( fp ) ;
352- chainArrayFpStr = chainArrayFpStr + fp ;
353- }
354- var chain_hash = sha256_digest ( chainArrayFpStr ) . toUpperCase ( ) ;
355- this . log ( INFO , "SHA-256 hash of cert chain for " + new String ( subject . URI . host ) + " is " + chain_hash ) ;
356401
357- if ( ! this . myGetBoolPref ( "use_whitelist" ) ) {
358- this . log ( WARN , "Not using whitelist to filter cert chains." ) ;
359- }
360- else if ( this . isChainWhitelisted ( chain_hash ) ) {
361- this . log ( INFO , "This cert chain is whitelisted. Not submitting." ) ;
362- return ;
363- }
364- else {
365- this . log ( INFO , "Cert chain is NOT whitelisted. Proceeding with submission." ) ;
366- }
402+ channel . QueryInterface ( Ci . nsIHttpChannel ) ;
403+ var chainEnum = certchain . getChain ( ) ;
404+ var chainArray = [ ] ;
405+ var chainArrayFpStr = '' ;
406+ var fps = [ ] ;
407+ for ( var i = 0 ; i < chainEnum . length ; i ++ ) {
408+ var cert = chainEnum . queryElementAt ( i , Ci . nsIX509Cert ) ;
409+ chainArray . push ( cert ) ;
410+ var fp = this . ourFingerprint ( cert ) ;
411+ fps . push ( fp ) ;
412+ chainArrayFpStr = chainArrayFpStr + fp ;
413+ }
414+ var chain_hash = sha256_digest ( chainArrayFpStr ) . toUpperCase ( ) ;
415+ this . log ( INFO , "SHA-256 hash of cert chain for " + new String ( channel . URI . host ) + " is " + chain_hash ) ;
367416
368- if ( subject . URI . port == - 1 ) {
369- this . submitChain ( chainArray , fps , new String ( subject . URI . host ) , subject , host_ip , false ) ;
370- } else {
371- this . submitChain ( chainArray , fps , subject . URI . host + ":" + subject . URI . port , subject , host_ip , false ) ;
372- }
417+ if ( ! this . myGetBoolPref ( "use_whitelist" ) ) {
418+ this . log ( WARN , "Not using whitelist to filter cert chains." ) ;
419+ }
420+ else if ( this . isChainWhitelisted ( chain_hash ) ) {
421+ this . log ( INFO , "This cert chain is whitelisted. Not submitting." ) ;
422+ return ;
423+ }
424+ else {
425+ this . log ( INFO , "Cert chain is NOT whitelisted. Proceeding with submission." ) ;
426+ }
427+
428+ if ( channel . URI . port == - 1 ) {
429+ this . submitChainArray ( chainArray , fps , new String ( channel . URI . host ) , channel , host_ip , false ) ;
430+ } else {
431+ this . submitChainArray ( chainArray , fps , channel . URI . host + ":" + channel . URI . port , channel , host_ip , false ) ;
373432 }
374433 }
375434 } ,
@@ -575,7 +634,7 @@ SSLObservatory.prototype = {
575634 return true ;
576635 } ,
577636
578- submitChain : function ( certArray , fps , domain , channel , host_ip , resubmitting ) {
637+ submitChainArray : function ( certArray , fps , domain , channel , host_ip , resubmitting ) {
579638 var base64Certs = [ ] ;
580639 // Put all this chain data in one object so that it can be modified by
581640 // subroutines if required
@@ -592,7 +651,7 @@ SSLObservatory.prototype = {
592651 if ( Object . keys ( this . delayed_submissions ) . length < MAX_DELAYED )
593652 if ( ! ( c . fps [ 0 ] in this . delayed_submissions ) ) {
594653 this . log ( WARN , "Planning to retry submission..." ) ;
595- let retry = function ( ) { this . submitChain ( certArray , fps , domain , channel , host_ip , true ) ; } ;
654+ let retry = function ( ) { this . submitChainArray ( certArray , fps , domain , channel , host_ip , true ) ; } ;
596655 this . delayed_submissions [ c . fps [ 0 ] ] = retry ;
597656 }
598657 return ;
@@ -694,7 +753,7 @@ SSLObservatory.prototype = {
694753 if ( Object . keys ( that . delayed_submissions ) . length < MAX_DELAYED )
695754 if ( ! ( c . fps [ 0 ] in that . delayed_submissions ) ) {
696755 that . log ( WARN , "Planning to retry submission..." ) ;
697- let retry = function ( ) { that . submitChain ( certArray , fps , domain , channel , host_ip , true ) ; } ;
756+ let retry = function ( ) { that . submitChainArray ( certArray , fps , domain , channel , host_ip , true ) ; } ;
698757 that . delayed_submissions [ c . fps [ 0 ] ] = retry ;
699758 }
700759
0 commit comments