diff --git a/javascript/src/iframe/viamapi-iframe.js b/javascript/src/iframe/viamapi-iframe.js index ba3b561ad082517a325cee6c3d5fabd837b4038e..d7c90e2bf9fc405a16d7cb37252b44b869192be0 100644 --- a/javascript/src/iframe/viamapi-iframe.js +++ b/javascript/src/iframe/viamapi-iframe.js @@ -47,6 +47,7 @@ import { checkRecoveryKeyCombine, encryptShare } from "../utilities/secrets"; +import {generateNonce, signRSA} from "../utilities/cryptoUtils"; const penpalMethods = require("../../temp/penpal-methods").default; const WopiAPI = require("./wopiapi-iframe"); @@ -129,6 +130,22 @@ function setIdentityInLocalStorage(identityToStore, extendKey = true) { ); } +async function setCurrentlyLoadedIdentity(identity) { + window.currentlyLoadedIdentity = identity; + + if (identity) { + let nonce = window.viamApi.getNonce(); + + if (!nonce) { + nonce = generateNonce(); + const privateKey = window.currentlyLoadedIdentity.authentication.privateKey; + const nonceSignature = await signRSA(privateKey, nonce); + window.viamApi.setNonce(Buffer.from(nonce).toString("base64")); + window.viamApi.setNonceSignature(Buffer.from(nonceSignature).toString("base64")); + } + } +} + function getProfileData(identity) { return new Penpal.Promise(executeResultUpper => { executeRestfulFunction( @@ -260,7 +277,7 @@ const destroyIdentity = () => { const { publicKey } = window.currentlyLoadedIdentity.authentication; delete window.loadedIdentities[publicKey]; - window.currentlyLoadedIdentity = null; + setCurrentlyLoadedIdentity(null); destroyIdentityFromLocalStorage(publicKey); } }; @@ -393,7 +410,7 @@ function loadIdentityInternal(identityKey, pinCode) { localStorage.removeItem("attempt"); window.loadedIdentities[identityKey] = loadedIdentity; - window.currentlyLoadedIdentity = loadedIdentity; + await setCurrentlyLoadedIdentity(loadedIdentity) if (identityKey === localStorage.getItem("authenticatedIdentity")) { window.currentlyAuthenticatedIdentity = loadedIdentity; @@ -479,10 +496,10 @@ function getCertificateForPassport(passportUUID, internal) { getProfileData(passportIdentity).then(executeResult1 => { setIdentityInLocalStorage(passportIdentity) - .then(() => { + .then(async () => { window.currentlyAuthenticatedIdentity = passportIdentity; window.lastTimeGetProfile = 0; - window.currentlyLoadedIdentity = passportIdentity; + await setCurrentlyLoadedIdentity(passportIdentity) const copyOfCryptoData = JSON.parse( JSON.stringify(cryptoData) ); @@ -559,7 +576,7 @@ const connection = Penpal.connectToParent({ ...penpalMethods, createIdentity(pinCode) { return new Penpal.Promise(result => { - createPassportCertificate(makeid()).then(function (keys) { + createPassportCertificate(makeid()).then(async function (keys) { const newIdentity = new Identity(); const cryptoData = new CryptoData(); cryptoData.setPublicKey(keys["publicKeyPEM"]); @@ -568,7 +585,7 @@ const connection = Penpal.connectToParent({ newIdentity.setAuthentication(cryptoData); newIdentity.setPinCode(pinCode); - window.currentlyLoadedIdentity = newIdentity; + await setCurrentlyLoadedIdentity(newIdentity) localStorage.setItem( "currentlyLoadedIdentity", JSON.stringify(newIdentity) @@ -629,7 +646,7 @@ const connection = Penpal.connectToParent({ identity.pinCode = newPinCode; await setIdentityInLocalStorage(identity); window.currentlyAuthenticatedIdentity = identity; - window.currentlyLoadedIdentity = identity; + await setCurrentlyLoadedIdentity(identity); return encodeResponse("200", null, "Successfully changed pincode"); } else { @@ -758,7 +775,7 @@ const connection = Penpal.connectToParent({ let sequence = Promise.resolve(); if (executeResult.code === "200") { sequence = sequence.then(() => { - setIdentityInLocalStorage(registerIdentity); + setIdentityInLocalStorage(window.currentlyLoadedIdentity); }); } sequence @@ -995,7 +1012,7 @@ const connection = Penpal.connectToParent({ "currentlyLoadedIdentity" ); const identity = new Identity(currentlyLoadedIdentity); - window.currentlyLoadedIdentity = identity; + await setCurrentlyLoadedIdentity(identity); const { publicKey } = identity.authentication; window.loadedIdentities[publicKey] = identity; window.viamAnonymousApi.setIdentity(publicKey); @@ -2489,7 +2506,7 @@ connection.promise.then(parent => { if (event.key === "authenticatedIdentity" && event.newValue === null) { const publicKey = window.currentlyAuthenticatedIdentity.authentication.publicKey; - window.currentlyLoadedIdentity = null; + setCurrentlyLoadedIdentity(null); window.currentlyAuthenticatedIdentity = null; const event = createEvent("LogoutFromAnotherTab", "Logout", [publicKey]); parent.onEvent(event); @@ -2572,7 +2589,7 @@ connection.promise.then(parent => { false ); - window.currentlyLoadedIdentity = identity; + await setCurrentlyLoadedIdentity(identity); if (!identityAuthenticatedEvent && identity) { const event = createEvent("IdentityAuthenticated", "Authenticated", [ @@ -2604,7 +2621,7 @@ connection.promise.then(parent => { } identityAuthenticatedEvent = false; - window.currentlyLoadedIdentity = null; + setCurrentlyLoadedIdentity(null); } localStorage.removeItem("currentlyLoadedIdentity"); @@ -2711,7 +2728,7 @@ connection.promise.then(parent => { localStorage.removeItem("token"); localStorage.removeItem("authenticatedIdentity"); delete window.loadedIdentities[authenticationPublicKey]; - window.currentlyLoadedIdentity = null; + setCurrentlyLoadedIdentity(null); window.currentlyAuthenticatedIdentity = null; window.lastTimeGetProfile = 0; diff --git a/javascript/src/utilities/cryptoUtils.js b/javascript/src/utilities/cryptoUtils.js new file mode 100644 index 0000000000000000000000000000000000000000..cee822966828071966dd6a7c5c66f2acb17b8561 --- /dev/null +++ b/javascript/src/utilities/cryptoUtils.js @@ -0,0 +1,45 @@ +const webcryptoLiner = require("webcrypto-liner/build/index"); + +export const generateNonce = () => { + return webcryptoLiner.crypto.getRandomValues(new Buffer(12)); +} + +const convertPemToBinary = (pem) => { + const lines = pem.split("\n"); + let encoded = ""; + for (let i = 0; i < lines.length; i++) { + if ( + lines[i].trim().length > 0 && + lines[i].indexOf("-BEGIN PRIVATE KEY-") < 0 && + lines[i].indexOf("-BEGIN PUBLIC KEY-") < 0 && + lines[i].indexOf("-END PRIVATE KEY-") < 0 && + lines[i].indexOf("-END PUBLIC KEY-") < 0 + ) { + encoded += lines[i].trim(); + } + } + return Buffer.from(encoded, "base64") +}; + +export const signRSA = async (privateKeyPEM, data) => { + const privateKey = await webcryptoLiner.crypto.subtle.importKey( + "pkcs8", + convertPemToBinary(privateKeyPEM), + { + name: "RSA-PSS", + hash: "SHA-256" + }, + true, + ["sign"] + ); + + return await webcryptoLiner.crypto.subtle.sign( + { + name: "RSA-PSS", + // hash: "SHA-256", + saltLength: 32 + }, + privateKey, + data + ); +}; diff --git a/main.go b/main.go index 99092e735d966c3b44d5a61a7456f08e47a97fac..02d1edeeb142b34615ec7e87ab52faf06809e5a8 100644 --- a/main.go +++ b/main.go @@ -82,7 +82,9 @@ func buildViamAPI() string { " 'publicKey': '',\n" + " 'uuid': '',\n" + " 'deviceHash': '',\n" + - " 'token': ''\n" + + " 'token': '',\n" + + " 'nonce': '',\n" + + " 'nonceSignature': ''\n" + " }\n" + " }\n" + "}\n\n" @@ -100,19 +102,20 @@ func buildViamAPI() string { " this.config.headers.publicKey = window.btoa(authenticationPublicKey);\n" + "};\n\n" - result += "ViamAPI.prototype.setPrivateKey = function(privateKey) {\n" + - " this.privateKey = privateKey;\n" + + result += "ViamAPI.prototype.setNonceSignature = function(nonceSignature) {\n" + + " this.config.headers.nonceSignature = nonceSignature;\n" + "};\n\n" + result += "ViamAPI.prototype.setNonce = function(nonce) {\n" + + " this.config.headers.nonce = nonce;\n" + + "};\n\n" + result += "ViamAPI.prototype.getNonce = function() {\n" + + " return this.config.headers.nonce;\n" + + "};\n\n" result += "ViamAPI.prototype.setPrivateKey = function(privateKey) {\n" + " this.privateKey = privateKey;\n" + "};\n\n" - result += "this.generateNonce = function() {\n" + - " var privateKey = config.privateKey;\n" + - " return this.config;\n" + - "};\n\n" - for i := 0; i < keysLen; i++ { url := keys[i] if endPoints[url].Form != nil {