Index: build/chrome/cackey-chrome-pkcs11.c ================================================================== --- build/chrome/cackey-chrome-pkcs11.c +++ build/chrome/cackey-chrome-pkcs11.c @@ -1,9 +1,10 @@ #ifdef __cplusplus extern "C" { #endif +#include #include #include #include #include @@ -324,10 +325,77 @@ } } free(certificates); + return; +} + +int cackey_chrome_listReaders(struct cackey_reader **readers) { + CK_RV chk_rv; + CK_ULONG numSlots, currSlot; + CK_SLOT_ID_PTR slots; + CK_SLOT_INFO slotInfo; + + chk_rv = cackey_chrome_init(); + if (chk_rv != CKR_OK) { + return(0); + } + + chk_rv = moduleFunctionList->C_GetSlotList(FALSE, NULL, &numSlots); + if (chk_rv != CKR_OK) { + return(0); + } + + slots = malloc(sizeof(*slots) * numSlots); + + chk_rv = moduleFunctionList->C_GetSlotList(FALSE, slots, &numSlots); + if (chk_rv != CKR_OK) { + free(slots); + + return(0); + } + + *readers = malloc(sizeof(**readers) * numSlots); + + for (currSlot = 0; currSlot < numSlots; currSlot++) { + chk_rv = moduleFunctionList->C_GetSlotInfo(slots[currSlot], &slotInfo); + if (chk_rv != CKR_OK) { + continue; + } + + (*readers)[currSlot].reader = malloc(sizeof(slotInfo.slotDescription) + 1); + memcpy((*readers)[currSlot].reader, slotInfo.slotDescription, sizeof(slotInfo.slotDescription)); + (*readers)[currSlot].reader[sizeof(slotInfo.slotDescription)] = '\0'; + + if ((slotInfo.flags & CKF_TOKEN_PRESENT) != CKF_TOKEN_PRESENT) { + (*readers)[currSlot].cardInserted = false; + } else { + (*readers)[currSlot].cardInserted = true; + } + } + + free(slots); + + return(numSlots); +} + +void cackey_chrome_freeReaders(struct cackey_reader *readers, int readersCount) { + int idx; + + if (readers == NULL) { + return; + } + + for (idx = 0; idx < readersCount; idx++) { + if (readers[idx].reader) { + free(readers[idx].reader); + } + } + + free(readers); + return; } cackey_chrome_returnType cackey_chrome_signMessage(struct cackey_certificate *certificate, void *data, unsigned long dataLength, void *destination, unsigned long *destinationLength, char **pinPrompt, const char *pin) { CK_RV chk_rv; Index: build/chrome/cackey-chrome-plugin.cc ================================================================== --- build/chrome/cackey-chrome-plugin.cc +++ build/chrome/cackey-chrome-plugin.cc @@ -35,15 +35,16 @@ char *pinPrompt = NULL; const char *pin; const char *smartcardManagerAppId = NULL; unsigned char buffer[8192]; struct cackey_certificate *certificates, incomingCertificateCACKey; - pp::VarDictionary *reply; - pp::VarArray certificatesPPArray; + struct cackey_reader *readers; + pp::VarDictionary *reply, *readerInfo; + pp::VarArray certificatesPPArray, readersPPArray; pp::VarArrayBuffer *certificateContents, *incomingCertificateContents, *incomingData, *outgoingData; pp::Var command; - int numCertificates, i; + int numCertificates, numReaders, i; unsigned long outgoingDataLength; /* * Extract the command */ @@ -85,10 +86,30 @@ cackey_chrome_freeCertificates(certificates, numCertificates); reply->Set("status", "success"); reply->Set("certificates", certificatesPPArray); + } else if (command.AsString() == "listreaders") { + numReaders = cackey_chrome_listReaders(&readers); + + readersPPArray.SetLength(numReaders); + + for (i = 0; i < numReaders; i++) { + readerInfo = new pp::VarDictionary; + + readerInfo->Set("readerName", readers[i].reader); + readerInfo->Set("cardInserted", readers[i].cardInserted); + + readersPPArray.Set(i, *readerInfo); + + delete readerInfo; + } + + cackey_chrome_freeReaders(readers, numReaders); + + reply->Set("status", "success"); + reply->Set("readers", readersPPArray); } else if (command.AsString() == "sign") { if (!message->HasKey("certificate")) { reply->Set("status", "error"); reply->Set("error", "Certificate not supplied"); } else if (!message->HasKey("data")) { Index: build/chrome/cackey-chrome.h ================================================================== --- build/chrome/cackey-chrome.h +++ build/chrome/cackey-chrome.h @@ -9,10 +9,15 @@ struct cackey_certificate { size_t certificate_len; void *certificate; }; + +struct cackey_reader { + char *reader; + bool cardInserted; +}; typedef enum { CACKEY_CHROME_OK, CACKEY_CHROME_ERROR, CACKEY_CHROME_NEEDLOGIN, @@ -20,14 +25,17 @@ } cackey_chrome_returnType; int cackey_chrome_listCertificates(struct cackey_certificate **certificates); void cackey_chrome_freeCertificates(struct cackey_certificate *certificates, int certificatesCount); +int cackey_chrome_listReaders(struct cackey_reader **readers); +void cackey_chrome_freeReaders(struct cackey_reader *readers, int readersCount); + cackey_chrome_returnType cackey_chrome_signMessage(struct cackey_certificate *certificate, void *data, unsigned long dataLength, void *destination, unsigned long *destinationLength, char **pinPrompt, const char *pin); void cackey_chrome_terminate(void); # ifdef __cplusplus } # endif #endif Index: build/chrome/cackey.js ================================================================== --- build/chrome/cackey.js +++ build/chrome/cackey.js @@ -69,10 +69,14 @@ * Handle a response from the NaCl side regarding certificates available */ function cackeyMessageIncomingListCertificates(message, chromeCallback) { var idx; var certificates = []; + + if (!chromeCallback) { + return; + } for (idx = 0; idx < message.certificates.length; idx++) { certificates.push( { certificate: message.certificates[idx], @@ -95,16 +99,33 @@ } ); return; } + +/* + * Handle a response from the NaCl side regarding a list of readers + */ +function cackeyMessageIncomingListReaders(message, chromeCallback) { + if (!chromeCallback) { + return; + } + + chromeCallback(message.readers); + + return; +} /* * Handle a response from the NaCl side regarding signing a message */ function cackeyMessageIncomingSignMessage(message, chromeCallback) { var payload; + + if (!chromeCallback) { + return; + } payload = message.signedData; chromeCallback(payload); @@ -355,10 +376,14 @@ case "success": switch (messageEvent.data.command) { case "listcertificates": nextFunction = cackeyMessageIncomingListCertificates; + break; + case "listreaders": + nextFunction = cackeyMessageIncomingListReaders; + break; case "sign": nextFunction = cackeyMessageIncomingSignMessage; break; @@ -394,10 +419,42 @@ 'target': "cackey", 'command': "listcertificates", 'id': callbackId } ); + + cackeyOutstandingCallbackCounter = callbackId; + cackeyOutstandingCallbacks[callbackId] = chromeCallback; + + if (GoogleSmartCard.IS_DEBUG_BUILD) { + console.log("[cackey] Thrown."); + } + }, chromeCallback); + + return; +} + +/* + * Handler for messages from Chrome related to listing readers + */ +function cackeyListReaders(chromeCallback) { + var callbackId; + + if (GoogleSmartCard.IS_DEBUG_BUILD) { + console.log("[cackey] Asked to provide a list of readers -- throwing that request over to the NaCl side... "); + } + + callbackId = cackeyOutstandingCallbackCounter + 1; + + cackeyInitPCSC(function() { + cackeyHandle.postMessage( + { + 'target': "cackey", + 'command': "listreaders", + 'id': callbackId + } + ); cackeyOutstandingCallbackCounter = callbackId; cackeyOutstandingCallbacks[callbackId] = chromeCallback; if (GoogleSmartCard.IS_DEBUG_BUILD) {