Index: build/chrome/cackey-chrome-init.cc ================================================================== --- build/chrome/cackey-chrome-init.cc +++ build/chrome/cackey-chrome-init.cc @@ -28,16 +28,22 @@ } virtual ~CACKeyInstance() {} virtual void HandleMessageThread(pp::VarDictionary *message) { - int numCertificates, i; - struct cackey_certificate *certificates; + cackey_chrome_returnType signRet; + char *pinPrompt; + const char *pin; + unsigned char buffer[8192]; + struct cackey_certificate *certificates, incomingCertificateCACKey; pp::VarDictionary *reply; pp::VarArray certificatesPPArray; - pp::VarArrayBuffer *certificateContents; - pp::Var command, incomingCertificateContents; + pp::VarArrayBuffer *certificateContents, *incomingCertificateContents, *incomingData, *outgoingData; + pp::Var command; + const pp::Var *messageAsVar = NULL, *outgoingDataAsVar = NULL; + int numCertificates, i; + unsigned long outgoingDataLength; /* * Extract the command */ command = message->Get("command"); @@ -70,15 +76,73 @@ reply->Set("certificates", certificatesPPArray); } else if (command.AsString() == "sign") { if (!message->HasKey("certificate")) { reply->Set("status", "error"); reply->Set("error", "Certificate not supplied"); - } else { - incomingCertificateContents = message->Get("certificate"); - + } else if (!message->HasKey("data")) { reply->Set("status", "error"); - reply->Set("error", "This function is not yet implemented"); + reply->Set("error", "Data not supplied"); + } else { + incomingCertificateContents = new pp::VarArrayBuffer(message->Get("certificate")); + incomingData = new pp::VarArrayBuffer(message->Get("data")); + + if (message->HasKey("pin")) { + pin = message->Get("pin").AsString().c_str(); + } else { + pin = NULL; + } + + incomingCertificateCACKey.certificate = incomingCertificateContents->Map(); + incomingCertificateCACKey.certificate_len = incomingCertificateContents->ByteLength(); + + outgoingDataLength = sizeof(buffer); + + signRet = cackey_chrome_signMessage(&incomingCertificateCACKey, + incomingData->Map(), incomingData->ByteLength(), + buffer, &outgoingDataLength, + &pinPrompt, pin + ); + + incomingCertificateContents->Unmap(); + incomingData->Unmap(); + + delete incomingCertificateContents; + delete incomingData; + + switch (signRet) { + case CACKEY_CHROME_OK: + outgoingData = new pp::VarArrayBuffer(outgoingDataLength); + + memcpy(outgoingData->Map(), buffer, outgoingDataLength); + + outgoingData->Unmap(); + + outgoingDataAsVar = new pp::Var(outgoingData->pp_var()); + + delete outgoingData; + + reply->Set("status", "success"); + reply->Set("signedData", outgoingDataAsVar); + + delete outgoingDataAsVar; + + break; + case CACKEY_CHROME_ERROR: + reply->Set("status", "error"); + reply->Set("error", "Unable to sign data"); + break; + case CACKEY_CHROME_NEEDLOGIN: + case CACKEY_CHROME_NEEDPROTECTEDLOGIN: + messageAsVar = new pp::Var(message->pp_var()); + + reply->Set("status", "retry"); + reply->Set("originalrequest", messageAsVar); + + delete messageAsVar; + + break; + } } } else { reply->Set("status", "error"); reply->Set("error", "Invalid command"); } Index: build/chrome/cackey-chrome.c ================================================================== --- build/chrome/cackey-chrome.c +++ build/chrome/cackey-chrome.c @@ -327,11 +327,11 @@ free(certificates); return; } -cackey_chrome_returnType cackey_chrome_signMessage(struct cackey_certificate *certificate, void *data, unsigned long dataLength, unsigned char *destination, unsigned long *destinationLength, char **pinPrompt, char *pin) { +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; CK_ULONG numSlots, currSlot; CK_SLOT_ID_PTR slots; CK_SLOT_INFO slotInfo; CK_SESSION_HANDLE hSession; Index: build/chrome/cackey-chrome.h ================================================================== --- build/chrome/cackey-chrome.h +++ build/chrome/cackey-chrome.h @@ -7,11 +7,11 @@ #include struct cackey_certificate { size_t certificate_len; - unsigned char *certificate; + void *certificate; }; typedef enum { CACKEY_CHROME_OK, CACKEY_CHROME_ERROR, @@ -20,14 +20,14 @@ } cackey_chrome_returnType; int cackey_chrome_listCertificates(struct cackey_certificate **certificates); void cackey_chrome_freeCertificates(struct cackey_certificate *certificates, int certificatesCount); -cackey_chrome_returnType cackey_chrome_signMessage(struct cackey_certificate *certificate, void *data, unsigned long dataLength, unsigned char *destination, unsigned long *destinationLength, char **pinPrompt, char *pin); +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 @@ -23,10 +23,15 @@ * Communication with the PIN entry window */ var pinWindowPINValue = ""; var pinWindowPreviousHandle = null; +/* + * Messages that may need to be retried after getting a PIN + */ +var cackeyMessagesToRetry = []; + /* * Handle a response from the NaCl side regarding certificates available */ function cackeyMessageIncomingListCertificates(message, chromeCallback) { var idx; @@ -100,21 +105,31 @@ chromeCallback(); break; case "retry": - pinWindowPINValue = ""; + /* + * Add the new request to the queue of events to process when the PIN + * prompt is terminated. + */ + cackeyMessagesToRetry.push(messageEvent); if (pinWindowPreviousHandle) { /* * An existing PIN entry is in progress - * Wait for it to complete and tie this request to that one. + * Just add the request to the queue (above) and wait */ - /* XXX:TODO */ + return; } + /* + * Set the handle to an invalid (but non-null) value until the window + * is created in case we are invoked again soon. + */ + pinWindowPreviousHandle = "invalid"; + chrome.app.window.create("pin.html", { "id": "cackeyPINEntry", "resizable": false, "alwaysOnTop": true, "focused": true, @@ -124,10 +139,15 @@ "minWidth": 350, "height": 135, "minHeight": 135 } }, function(pinWindow) { + /* + * Set the PIN value to blank + */ + pinWindowPINValue = ""; + if (!pinWindow) { console.log("[cackey] No window was provided for PIN entry, this will not go well."); return; } @@ -140,19 +160,31 @@ /* * Register a handler to handle the window being closed without * having sent anything */ pinWindow.onClosed.addListener(function() { + var messageIdx; + pinWindowPreviousHandle = null; - if (pinWindowPINValue == "") { - console.log("[cackey] The PIN dialog was closed without resubmitting the request, treating it as a failure"); + for (messageIdx = 0; messageIdx < cackeyMessagesToRetry.length; messageIdx++) { + var tmpMessageEvent; + + tmpMessageEvent = cackeyMessagesToRetry[messageIdx]; + + if (pinWindowPINValue == "") { + console.log("[cackey] The PIN dialog was closed without gathering a PIN, treating it as a failure."); + + tmpMessageEvent.data.status = "error"; + tmpMessageEvent.data.error = "PIN window closed without a PIN being provided"; - messageEvent.data.status = "error"; - messageEvent.data.error = "PIN window closed without a PIN being provided"; + cackeyMessageIncoming(tmpMessageEvent); + } else { + cackeyHandle.postMessage(tmpMessageEvent.data.originalrequest); + } - cackeyMessageIncoming(messageEvent); + delete cackeyMessagesToRetry[messageIdx]; } return; })