Check-in [455296a053]
Overview
SHA1:455296a053b280807ba1149ffe231e21371e5589
Date: 2016-02-28 21:18:17
User: rkeene
Comment:ChromeOS: Made JavaScript talking to PCSC more robust
Timelines: family | ancestors | descendants | both | trunk
Downloads: Tarball | ZIP archive
Other Links: files | file ages | folders | manifest
Tags And Properties
Context
2016-02-28
21:22
[789f3b2324] ChromeOS: Improved cleanup after crash (user: rkeene, tags: trunk)
21:18
[455296a053] ChromeOS: Made JavaScript talking to PCSC more robust (user: rkeene, tags: trunk)
2016-02-26
21:40
[f631a1ccb2] ChromeOS: Deal with CACKey crashing by restarting (user: rkeene, tags: trunk)
Changes

Modified build/chrome/cackey.js from [fda208ef5f] to [84d3b8d4ee].

     9      9   }
    10     10   
    11     11   /*
    12     12    * Handle for the CACKey NaCl Target
    13     13    */
    14     14   var cackeyHandle = null;
    15     15   var cackeyPCSCHandle = null;
           16  +var cackeyPCSCHandleUsable = false;
    16     17   
    17     18   /*
    18     19    * Handle and ID for outstanding callbacks
    19     20    */
    20     21   var cackeyOutstandingCallbacks = {}
    21     22   var cackeyOutstandingCallbackCounter = -1;
    22     23   
................................................................................
    32     33   var cackeyMessagesToRetry = [];
    33     34   
    34     35   /*
    35     36    * Stored PIN for a given certificate
    36     37    */
    37     38   var cackeyCertificateToPINMap = {};
    38     39   
           40  +/*
           41  + * Callbacks to perform after PCSC comes online
           42  + */
           43  +cackeyCallbackAfterInit = []
           44  +
    39     45   /*
    40     46    * Compute a text-based handle for a certificate to be hashed by
    41     47    */
    42     48   function cackeyCertificateToPINID(certificate) {
    43     49   	var id;
    44     50   	var certificateArray;
    45     51   
................................................................................
    65     71   	var idx;
    66     72   	var certificates = [];
    67     73   
    68     74   	for (idx = 0; idx < message.certificates.length; idx++) {
    69     75   		certificates.push(
    70     76   			{
    71     77   				certificate: message.certificates[idx],
    72         -				supportedHashes: ['SHA1', 'SHA256']
           78  +				supportedHashes: ['SHA1', 'SHA256', 'MD5_SHA1']
    73     79   			}
    74     80   		);
    75     81   	}
    76     82   
    77     83   	chromeCallback(certificates,
    78     84   		function(rejectedCerts) {
    79     85   			if (chrome.runtime.lastError) {
................................................................................
    83     89   			if (rejectedCerts.length !== 0) {
    84     90   				onCertificatesRejected(rejectedCerts);
    85     91   			}
    86     92   
    87     93   			return;
    88     94   		}
    89     95   	);
           96  +
           97  +	return;
    90     98   }
    91     99   
    92    100   /*
    93    101    * Handle a response from the NaCl side regarding signing a message
    94    102    */
    95    103   function cackeyMessageIncomingSignMessage(message, chromeCallback) {
    96    104   	var payload;
    97    105   
    98    106   	payload = message.signedData;
    99    107   
   100    108   	chromeCallback(payload);
          109  +
          110  +	return;
   101    111   }
   102    112   
   103    113   /*
   104    114    * Handle an incoming message from the NaCl side and pass it off to
   105    115    * one of the handlers above for actual formatting and passing to
   106    116    * the callback
   107    117    *
................................................................................
   227    237   
   228    238   							cackeyMessageIncoming(tmpMessageEvent);
   229    239   						} else {
   230    240   							tmpMessageEvent.data.originalrequest.pin = pinWindowPINValue;
   231    241   
   232    242   							cackeyCertificateToPINMap[cackeyCertificateToPINID(tmpMessageEvent.data.originalrequest.certificate)] = pinWindowPINValue;
   233    243   
   234         -							cackeyHandle.postMessage(tmpMessageEvent.data.originalrequest);
          244  +							cackeyInitPCSC(function() {
          245  +								cackeyHandle.postMessage(tmpMessageEvent.data.originalrequest);
          246  +							});
   235    247   						}
   236    248   					}
   237    249   
   238    250   
   239    251   					/*
   240    252   					 * Delete the existing handle and create a new one
   241    253   					 */
................................................................................
   297    309   
   298    310   	if (GoogleSmartCard.IS_DEBUG_BUILD) {
   299    311   		console.log("[cackey] Asked to provide a list of certificates -- throwing that request over to the NaCl side... ");
   300    312   	}
   301    313   
   302    314   	callbackId = cackeyOutstandingCallbackCounter + 1;
   303    315   
   304         -	cackeyHandle.postMessage(
   305         -		{
   306         -			'target': "cackey",
   307         -			'command': "listcertificates",
   308         -			'id': callbackId
          316  +	cackeyInitPCSC(function() {
          317  +		cackeyHandle.postMessage(
          318  +			{
          319  +				'target': "cackey",
          320  +				'command': "listcertificates",
          321  +				'id': callbackId
          322  +			}
          323  +		);
          324  +
          325  +		cackeyOutstandingCallbackCounter = callbackId;
          326  +		cackeyOutstandingCallbacks[callbackId] = chromeCallback;
          327  +
          328  +		if (GoogleSmartCard.IS_DEBUG_BUILD) {
          329  +			console.log("[cackey] Thrown.");
   309    330   		}
   310         -	);
   311         -
   312         -	cackeyOutstandingCallbackCounter = callbackId;
   313         -	cackeyOutstandingCallbacks[callbackId] = chromeCallback;
   314         -
   315         -	if (GoogleSmartCard.IS_DEBUG_BUILD) {
   316         -		console.log("[cackey] Thrown.");
   317         -	}
          331  +	});
   318    332   
   319    333   	return;
   320    334   }
   321    335   
   322    336   /*
   323    337    * Handler for messages from Chrome related to signing a hash of some sort
   324    338    */
................................................................................
   371    385   
   372    386   	certificateId = cackeyCertificateToPINID(command.certificate);
   373    387   
   374    388   	if (cackeyCertificateToPINMap[certificateId]) {
   375    389   		command.pin = cackeyCertificateToPINMap[certificateId];
   376    390   	}
   377    391   
   378         -	cackeyHandle.postMessage(command);
          392  +	cackeyInitPCSC(function() {
          393  +		cackeyHandle.postMessage(command);
   379    394   
   380         -	cackeyOutstandingCallbackCounter = callbackId;
   381         -	cackeyOutstandingCallbacks[callbackId] = chromeCallback;
          395  +		cackeyOutstandingCallbackCounter = callbackId;
          396  +		cackeyOutstandingCallbacks[callbackId] = chromeCallback;
   382    397   
   383         -	if (GoogleSmartCard.IS_DEBUG_BUILD) {
   384         -		console.log("[cackey] Thrown.");
          398  +		if (GoogleSmartCard.IS_DEBUG_BUILD) {
          399  +			console.log("[cackey] Thrown.");
          400  +		}
          401  +	});
          402  +
          403  +	return;
          404  +}
          405  +
          406  +/*
          407  + * Unititalizes the CACKey PCSC connection
          408  + */
          409  +function cackeyUninitPCSC() {
          410  +	console.log("[cackey] cackeyUninitPCSC() called");
          411  +
          412  +	if (cackeyPCSCHandle != null) {
          413  +		console.log("[cackey] Deleting PCSC handle");
          414  +
          415  +		delete cackeyPCSCHandle;
          416  +
          417  +		cackeyPCSCHandle = null;
   385    418   	}
   386    419   
          420  +	cackeyPCSCHandleUsable = false;
          421  +
          422  +	console.log("[cackey] cackeyUninitPCSC() returning");
          423  +
   387    424   	return;
   388    425   }
   389    426   
   390    427   /*
   391    428    * Uninitializes CACKey (probably due to a crash)
   392    429    */
   393    430   function cackeyUninit() {
          431  +	console.log("[cackey] cackeyUninit() called");
          432  +
   394    433   	if (chrome.certificateProvider) {
          434  +		console.log("[cackey] Unregistered Chrome certificate handlers");
          435  +
   395    436   		chrome.certificateProvider.onCertificatesRequested.removeListener(cackeyListCertificates);
   396    437   		chrome.certificateProvider.onSignDigestRequested.removeListener(cackeySignMessage);
   397    438   	}
   398    439   
   399         -	if (cackeyPCSCHandle != null) {
   400         -		delete cackeyPCSCHandle;
   401         -
   402         -		cackeyPCSCHandle = null;
   403         -	}
          440  +	cackeyUninitPCSC();
   404    441   
   405    442   	if (cackeyHandle != null) {
          443  +		console.log("[cackey] Deleting PNaCl module");
          444  +
   406    445   		try {
   407    446   			document.body.removeChild(cackeyHandle);
   408    447   		} catch (e) { }
   409    448   
   410    449   		delete cackeyHandle;
   411    450   
   412    451   		cackeyHandle = null;
   413    452   	}
          453  +
          454  +	console.log("[cackey] cackeyUninit() complete");
          455  +
          456  +	return;
   414    457   }
   415    458   
   416    459   /*
   417    460    * Restarts CACKey
   418    461    */
   419    462   function cackeyRestart() {
   420    463   	cackeyUninit();
   421    464   	cackeyInit();
          465  +
          466  +	return;
   422    467   }
   423    468   
   424    469   /*
   425    470    * Handle a CACKey crash (probably due to loss of connectivity to the PCSC daemon)
   426    471    */
   427    472   function cackeyCrash() {
   428    473   	/*
   429    474   	 * Schedule the restart to occur in 30 seconds in case we really are
   430    475   	 * not working.
   431    476   	 */
   432    477   	setTimeout(cackeyRestart, 30000);
          478  +
          479  +	return;
          480  +}
          481  +
          482  +function cackeyInitPCSCCompleted() {
          483  +	var idx;
          484  +
          485  +	cackeyPCSCHandleUsable = true;
          486  +
          487  +	for (idx = 0; idx < cackeyCallbackAfterInit.length; idx++) {
          488  +		if (!cackeyCallbackAfterInit[idx]) {
          489  +			continue;
          490  +		}
          491  +
          492  +		cackeyCallbackAfterInit[idx]();
          493  +	}
          494  +
          495  +	delete cackeyCallbackAfterInit;
          496  +
          497  +	cackeyCallbackAfterInit = [];
          498  +
          499  +	return;
   433    500   }
   434    501   
   435    502   /*
   436         - * Finish performing initialization that must wait until we have loaded the CACKey module
          503  + * Initialize the PCSC connection
   437    504    */
   438         -function cackeyInitLoaded(messageEvent) {
   439         -	console.log("[cackey] Loaded CACKey PNaCl Module");
          505  +function cackeyInitPCSC(callbackAfterInit) {
          506  +	/*
          507  +	 * Start the Google PCSC Interface
          508  +	 */
   440    509   
   441         -	/* Register listeners with Chrome */
   442         -	if (chrome.certificateProvider) {
   443         -		chrome.certificateProvider.onCertificatesRequested.addListener(cackeyListCertificates);
   444         -		chrome.certificateProvider.onSignDigestRequested.addListener(cackeySignMessage);
          510  +	console.log("[cackey] cackeyInitPCSC() called");
          511  +
          512  +	/*
          513  +	 * Queue this callback to be completed when initialization is complete
          514  +	 */
          515  +	if (callbackAfterInit) {
          516  +		cackeyCallbackAfterInit.push(callbackAfterInit);
          517  +	}
          518  +
          519  +	/*
          520  +	 * No additional work is required
          521  +	 */
          522  +
          523  +	if (cackeyPCSCHandle) {
          524  +		console.log("[cackey] PCSC handle is already valid, nothing to do.");
          525  +
          526  +		if (cackeyPCSCHandleUsable) {
          527  +			cackeyInitPCSCCompleted();
          528  +		}
          529  +
          530  +		return;
          531  +	}
          532  +
          533  +	/*
          534  +	 * Sanely initialize this
          535  +	 */
          536  +	cackeyPCSCHandleUsable = false;
          537  +
          538  +	/*
          539  +	 * Initialize the CACKey PNaCl module if needed
          540  +	 */
          541  +	if (cackeyHandle == null) {
          542  +		cackeyInit();
   445    543   	}
   446    544   
   447    545   	/*
   448    546   	 * Initialize CACKey with the correct handle to talk to the Google Smartcard Manager App
   449    547   	 */
   450    548   	cackeyHandle.postMessage(
   451    549   		{
................................................................................
   452    550   			"target": "cackey",
   453    551   			"command": "init",
   454    552   			"smartcardManagerAppId": "khpfeaanjngmcnplbdlpegiifgpfgdco"
   455    553   		}
   456    554   	);
   457    555   
   458    556   	/*
   459         -	 * Start the Google PCSC Interface
          557  +	 * Initialize the PCSC NaCl interface
   460    558   	 */
   461    559   	cackeyPCSCHandle = new GoogleSmartCard.PcscNacl(cackeyHandle);
          560  +
          561  +	console.log("[cackey] cackeyInitPCSC() complete");
          562  +
          563  +	return;
          564  +}
          565  +
          566  +/*
          567  + * Finish performing initialization that must wait until we have loaded the CACKey module
          568  + */
          569  +function cackeyInitLoaded(messageEvent) {
          570  +	console.log("[cackey] Loaded CACKey PNaCl Module");
          571  +
          572  +	/* Register listeners with Chrome */
          573  +	if (chrome.certificateProvider) {
          574  +		console.log("[cackey] Registered Certificate handlers with Chrome");
          575  +
          576  +		chrome.certificateProvider.onCertificatesRequested.addListener(cackeyListCertificates);
          577  +		chrome.certificateProvider.onSignDigestRequested.addListener(cackeySignMessage);
          578  +	}
   462    579   
   463    580   	return;
   464    581   }
   465    582   
   466    583   /*
   467    584    * Initialize CACKey and the PCSC library from Google
   468    585    */
................................................................................
   511    628   	/*
   512    629   	 * Force the browser to load the element
   513    630   	 * by requesting its position
   514    631   	 */
   515    632   	forceLoadElement = cackeyHandle.offsetTop;
   516    633   
   517    634   	console.log("[cackey] cackeyInit(): Completed.  Returning.");
          635  +
          636  +	return;
   518    637   }
   519    638   
   520    639   /*
   521    640    * Initialize the CACKey Chrome Application
   522    641    */
   523    642   function cackeyAppInit() {
          643  +	var oldOnPortDisconnectedFunction;
          644  +	var oldPCSCInitializationCallback;
          645  +
   524    646   	/*
   525    647   	 * Create a handler for starting the application UI
   526    648   	 */
   527    649   	chrome.app.runtime.onLaunched.addListener(function() {
   528    650   		chrome.app.window.create('ui.html', {
   529    651   			"id": "cackeyUI",
   530    652   			"focused": true,
................................................................................
   532    654   				"width": 350,
   533    655   				"minWidth": 350,
   534    656   				"height": 135,
   535    657   				"minHeight": 135
   536    658   			}
   537    659   		});
   538    660   	});
          661  +
          662  +	/*
          663  +	 * Register a handler for dealing with the PCSC port being disconnected
          664  +	 */
          665  +	oldOnPortDisconnectedFunction = GoogleSmartCard.Pcsc.prototype.onPortDisconnected_;
          666  +	GoogleSmartCard.Pcsc.prototype.onPortDisconnected_ = function() {
          667  +		oldOnPortDisconnectedFunction.apply(this);
          668  +
          669  +		cackeyRestart();
          670  +
          671  +		return;
          672  +	};
          673  +
          674  +	/*
          675  +	 * Register a handler for dealing with the PCSC port being available
          676  +	 */
          677  +	oldPCSCInitializationCallback = GoogleSmartCard.PcscNacl.prototype.pcscInitializationCallback_;
          678  +	GoogleSmartCard.PcscNacl.prototype.pcscInitializationCallback_ = function(requestId, instanceId, instance, error) {
          679  +		oldPCSCInitializationCallback.apply(this, [requestId, instanceId, instance, error]);
          680  +
          681  +		cackeyInitPCSCCompleted();
          682  +
          683  +		return;
          684  +	};
          685  +
          686  +	return;
   539    687   }
   540    688   
   541    689   /* Initialize CACKey */
   542    690   cackeyAppInit();
   543    691   cackeyInit();