chrome token signing Extension

1.8k views Asked by At

I am trying to make an extension that will communicate with a native messaging host chrome-token-signing. I use gemalto smart card reader . I installed extension , it return an cmd window when I exit or put any string . I have message log TEST: ERROR {"message":"Error when communicating with the native messaging host."} Do I need to do Something I have installed the host in the registry like HKEY_LOCAL_MACHINE\software\Google\Chrome\NativeMessagingHosts\ee.ria.esteid and value C:\Users\dev\Desktop\chrome-token-signing\host-windows\ee.ria.esteid.json

The native application manifest.json:

{
 "name": "ee.ria.esteid",
 "description": "Give signatures with your eID on the web",
 "path": "chrome-token-signing.exe",
 "type": "stdio",
 "allowed_origins": [
"chrome-extension://ckjefchnfjhjfedoccjbhjpbncimppeg/"
]
 }   

manifest.json of extension {

  "name": "Token signing",
  "version": "0.0.24",
  "minimum_chrome_version": "40.0",
  "manifest_version": 2,
  "description": "Use your eID smart card on the web",
  "icons": {
  "48": "icon48.png",
  "128": "icon128.png"
  },
  "content_scripts": [{
  "matches": ["*://*/*", "file:///*"],
  "exclude_matches": ["*://www.overdrive.com/*"],
  "js": ["content.js"],
  "run_at": "document_end",
  "all_frames": true
  }],
  "background": {
  "scripts": ["background.js"]
  },
  "permissions": ["nativeMessaging"],
  "applications": {
  "gecko": {
    "id": "{443830f0-1fff-4f9a-aa1e-444bafbc7319}"
    }
    }
     }

background.js

  var NO_NATIVE_URL = "https://open-eid.github.io/chrome-token-  signing/missing.html";

 var HELLO_URL = "https://open-eid.github.io/chrome-token-signing/hello.html";

  var DEVELOPER_URL = "https://github.com/open-eid/chrome-token-  signing/wiki/DeveloperTips";

  var NATIVE_HOST = "ee.ria.esteid";

  var K_SRC = "src";
  var K_ORIGIN = "origin";
  var K_NONCE = "nonce";
  var K_RESULT = "result";
  var K_TAB = "tab";
  var K_EXTENSION = "extension";

  // Stores the longrunning ports per tab
  // Used to route all request from a tab to the same host instance
  var ports = {};

  // Probed to false if host component is OK.
   var missing = true;

  console.log("Background page activated");

    // XXX: probe test, because connectNative() does not allow to check the presence
   // of native component for some reason
      typeof chrome.runtime.onStartup !== 'undefined' &&       chrome.runtime.onStartup.addListener(function() {
   // Also probed for in onInstalled()
  _testNativeComponent().then(function(result) {
if (result === "ok") {
    missing = false;
}
  });
     });
  // Force kill of native process
  // Becasue Port.disconnect() does not work
   function _killPort(tab) {
  if (tab in ports) {
   console.log("KILL " + tab);
    // Force killing with an empty message
    ports[tab].postMessage({});
 }
 }

   // Check if native implementation is OK resolves with "ok", "missing" or "forbidden"
  function _testNativeComponent() {
    return new Promise(function(resolve, reject) {
chrome.runtime.sendNativeMessage(NATIVE_HOST, {}, function(response) {
    if (!response) {
        console.log("TEST: ERROR " + JSON.stringify(chrome.runtime.lastError));
        // Try to be smart and do some string matching
        var permissions = "Access to the specified native messaging host is forbidden.";
        var missing = "Specified native messaging host not found.";
        if (chrome.runtime.lastError.message === permissions) {
            resolve("forbidden")
        } else if (chrome.runtime.lastError.message === missing) {
            resolve("missing");
        } else {
            resolve("missing");
        }
    } else {
        console.log("TEST: " + JSON.stringify(response));
        if (response["result"] === "invalid_argument") {
            resolve("ok");
        } else {
            resolve("missing"); // TODO: something better here
        }
    }
      });
       });
       }

    // When extension is installed, check for native component or direct to helping page
  typeof chrome.runtime.onInstalled !== 'undefined' &&  chrome.runtime.onInstalled.addListener(function(details) {
  if (details.reason === "install" || details.reason === "update") {
_testNativeComponent().then(function(result) {
        var url = null;
        if (result === "ok" && details.reason === "install") {
            // Also set the flag, onStartup() shall be called only
            // on next startup
            missing = false;
            // TODO: Add back HELLO page on install
            // once there is a nice tutorial
             url = HELLO_URL;
        } else if (result === "forbidden") {
            url = DEVELOPER_URL;
        } else if (result === "missing"){
            url = NO_NATIVE_URL;
        }
        if (url) {
            chrome.tabs.create({'url': url + "?" + details.reason});
        }
         });
           }
             });
   // When message is received from page send it to native
   chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
 if(sender.id !== chrome.runtime.id && sender.extensionId !==   chrome.runtime.id) {
console.log('WARNING: Ignoring message not from our extension');
// Not our extension, do nothing
return;
}
 if (sender.tab) {
// Check if page is DONE and close the native component without doing anything else
if (request["type"] === "DONE") {
    console.log("DONE " + sender.tab.id);
    if (sender.tab.id in ports) {
        // FIXME: would want to use Port.disconnect() here
        _killPort(sender.tab.id);
    } 
} else {
    request[K_TAB] = sender.tab.id;
    if (missing) {
        _testNativeComponent().then(function(result) {
            if (result === "ok") {
                missing = false;
                _forward(request);
            } else {
                return _fail_with (request, "no_implementation");
            }
        });
    } else {
        // TODO: Check if the URL is in allowed list or not
        // Either way forward to native currently
        _forward(request);
    }
}
}
    });

// Send the message back to the originating tab
function _reply(tab, msg) {
msg[K_SRC] = "background.js";
msg[K_EXTENSION] = chrome.runtime.getManifest().version;
chrome.tabs.sendMessage(tab, msg);
 }

 // Fail an incoming message if the underlying implementation is not
  // present
  function _fail_with(msg, result) {
 var resp = {};
 resp[K_NONCE] = msg[K_NONCE];
 resp[K_RESULT] = result;
_reply(msg[K_TAB], resp);
  }
 // Forward a message to the native component
 function _forward(message) {
   var tabid = message[K_TAB];
 console.log("SEND " + tabid + ": " + JSON.stringify(message));
 // Open a port if necessary
    if(!ports[tabid]) {
 // For some reason there does not seem to be a way to detect missing components from longrunning ports
 // So we probe before opening a new port.
console.log("OPEN " + tabid + ": " + NATIVE_HOST);
 // create a new port
var port = chrome.runtime.connectNative(NATIVE_HOST);
// XXX: does not indicate anything for some reason.
if (!port) {
    console.log("OPEN ERROR: " + JSON.stringify(chrome.runtime.lastError));
}
port.onMessage.addListener(function(response) {
    if (response) {
        console.log("RECV "+tabid+": " + JSON.stringify(response));
        _reply(tabid, response);
    } else {
        console.log("ERROR "+tabid+": " + JSON.stringify(chrome.runtime.lastError));
        _fail_with(message, "technical_error");
    }
});
port.onDisconnect.addListener(function() {
    console.log("QUIT " + tabid);
    delete ports[tabid];
    // TODO: reject all pending promises for tab, if any
});
ports[tabid] = port;
ports[tabid].postMessage(message);
} else {
// Port already open
ports[tabid].postMessage(message);
 }
     }

content.js

  /*
 * Chrome token signing extension
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */
 var inuse = false;
  // Forward the message from page.js to background.js
   window.addEventListener("message", function(event) {
// We only accept messages from ourselves
if (event.source !== window)
    return;

// and forward to extension
if (event.data.src && (event.data.src === "page.js")) {
    event.data["origin"] = location.origin;
    chrome.runtime.sendMessage(event.data, function(response) {});

    // Only add unload handler if extension has been used
    if (!inuse) {
        // close the native component if page unloads
        window.addEventListener("beforeunload", function(event) {
            chrome.runtime.sendMessage({src: 'page.js', type: 'DONE'});
        }, false);
        inuse = true;
    }
}
  }, false);

// post messages from extension to page
  chrome.runtime.onMessage.addListener(function(request, sender,  sendResponse) {
window.postMessage(request, '*');
});

// inject content of page.js to the DOM of every page
// FIXME: maybe not ?
var s = document.createElement('script');
s.type = 'text/javascript';
s.innerHTML='// Promises \n\
var _eid_promises = {}; \n\
// Turn the incoming message from extension \n\
// into pending Promise resolving \n\
 window.addEventListener("message", function(event) { \n\
if(event.source !== window) return; \n\
if(event.data.src && (event.data.src === "background.js")) { \n\
    console.log("Page received: "); \n\
    console.log(event.data); \n\
    // Get the promise \n\
    if(event.data.nonce) { \n\
        var p = _eid_promises[event.data.nonce]; \n\
        // resolve \n\
        if(event.data.result === "ok") { \n\
            if(event.data.signature !== undefined) { \n\
                p.resolve({hex: event.data.signature}); \n\
            } else if(event.data.version !== undefined) { \n\
                p.resolve(event.data.extension + "/" + event.data.version); \n\
            } else if(event.data.cert !== undefined) { \n\
                p.resolve({hex: event.data.cert}); \n\
            } else { \n\
                console.log("No idea how to handle message"); \n\
                console.log(event.data); \n\
            } \n\
        } else { \n\
            // reject \n\
            p.reject(new Error(event.data.result)); \n\
        } \n\
        delete _eid_promises[event.data.nonce]; \n\
    } else { \n\
        console.log("No nonce in event msg"); \n\
    } \n\
} \n\
}, false); \n\
\n\
\n\
function TokenSigning() { \n\
function nonce() { \n\
    var val = ""; \n\
    var hex = "abcdefghijklmnopqrstuvwxyz0123456789"; \n\
    for(var i = 0; i < 16; i++) val += hex.charAt(Math.floor(Math.random() * hex.length)); \n\
    return val; \n\
} \n\
 \n\
function messagePromise(msg) { \n\
    return new Promise(function(resolve, reject) { \n\
        // amend with necessary metadata \n\
        msg["nonce"] = nonce(); \n\
        msg["src"] = "page.js"; \n\
        // send message \n\
        window.postMessage(msg, "*"); \n\
        // and store promise callbacks \n\
        _eid_promises[msg.nonce] = { \n\
            resolve: resolve, \n\
            reject: reject \n\
        }; \n\
    }); \n\
     } \n\
this.getCertificate = function(options) { \n\
    var msg = {type: "CERT", lang: options.lang}; \n\
    console.log("getCertificate()"); \n\
    return messagePromise(msg); \n\
}; \n\
this.sign = function(cert, hash, options) { \n\
    var msg = {type: "SIGN", cert: cert.hex, hash: hash.hex, hashtype: hash.type, lang: options.lang}; \n\
    console.log("sign()"); \n\
    return messagePromise(msg); \n\
}; \n\
this.getVersion = function() { \n\
    console.log("getVersion()"); \n\
    return messagePromise({ \n\
        type: "VERSION" \n\
    }); \n\
}; \n\
}';
     (document.head || document.documentElement).appendChild(s);

page.js

 /*
  * Chrome token signing extension
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  * License as published by the Free Software Foundation; either
  * version 2.1 of the License, or (at your option) any later version.
  *
  * This library is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  */
  // Promises
  var _eid_promises = {};
  // Turn the incoming message from extension
  // into pending Promise resolving
  window.addEventListener("message", function(event) {
if(event.source !== window) return;
if(event.data.src && (event.data.src === "background.js")) {
    console.log("Page received: ");
    console.log(event.data);
    // Get the promise
    if(event.data.nonce) {
        var p = _eid_promises[event.data.nonce];
        // resolve
        if(event.data.result === "ok") {
            if(event.data.signature !== undefined) {
                p.resolve({hex: event.data.signature});
            } else if(event.data.version !== undefined) {
                p.resolve(event.data.extension + "/" + event.data.version);
            } else if(event.data.cert !== undefined) {
                p.resolve({hex: event.data.cert});
            } else {
                console.log("No idea how to handle message");
                console.log(event.data);
            }
        } else {
            // reject
            p.reject(new Error(event.data.result));
        }
        delete _eid_promises[event.data.nonce];
    } else {
        console.log("No nonce in event msg");
    }
}
  }, false);
function TokenSigning() {
function nonce() {
    var val = "";
    var hex = "abcdefghijklmnopqrstuvwxyz0123456789";
    for(var i = 0; i < 16; i++) val += hex.charAt(Math.floor(Math.random() * hex.length));
    return val;
}

function messagePromise(msg) {
    return new Promise(function(resolve, reject) {
        // amend with necessary metadata
        msg["nonce"] = nonce();
        msg["src"] = "page.js";
        // send message
        window.postMessage(msg, "*");
        // and store promise callbacks
        _eid_promises[msg.nonce] = {
            resolve: resolve,
            reject: reject
        };
    });
}
this.getCertificate = function(options) {
    var msg = {type: "CERT", lang: options.lang};
    console.log("getCertificate()");
    return messagePromise(msg);
};
this.sign = function(cert, hash, options) {
    var msg = {type: "SIGN", cert: cert.hex, hash: hash.hex, hashtype: hash.type, lang: options.lang};
    console.log("sign()");
    return messagePromise(msg);
};
this.getVersion = function() {
    console.log("getVersion()");
    return messagePromise({
        type: "VERSION"
    });
};
  }

when I run the extension I have: enter image description here

And when I whrite somethig or click 2 times at Enter touch or close the cmd I have this:enter image description here

1

There are 1 answers

0
guesmi hela On

I have this one enter image description here

and when I click invoke sign I have sign() clicked on Signing SHA-256: 413140d54372f9baf481d4c54e2d5c7bcf28fd6087000280e07976121dd54af2 and the cmd window appear like this enter image description here

when I close the cmd I have this one

enter image description here and when i put anything in the cmd I have like this one enter image description here