changed the API for most of the crypto functions
thus far I don't think anyone uses those functions so this should be safe
This commit is contained in:
parent
28dbf9ab23
commit
5a5488f504
|
@ -207,12 +207,12 @@
|
|||
}
|
||||
, jwt: {
|
||||
// decode only (no verification)
|
||||
decode: function (str) {
|
||||
decode: function (token, opts) {
|
||||
|
||||
// 'abc.qrs.xyz'
|
||||
// [ 'abc', 'qrs', 'xyz' ]
|
||||
// {}
|
||||
var parts = str.split(/\./g);
|
||||
var parts = token.split(/\./g);
|
||||
var err;
|
||||
if (parts.length !== 3) {
|
||||
err = new Error("Invalid JWT: required 3 '.' separated components not "+parts.length);
|
||||
|
@ -220,14 +220,55 @@
|
|||
throw err;
|
||||
}
|
||||
|
||||
if (!opts || !opts.complete) {
|
||||
return JSON.parse(OAUTH3._base64.decodeUrlSafe(parts[1]));
|
||||
}
|
||||
, verify: function (jwk, token) {
|
||||
return {
|
||||
header: JSON.parse(OAUTH3._base64.decodeUrlSafe(parts[0]))
|
||||
, payload: JSON.parse(OAUTH3._base64.decodeUrlSafe(parts[1]))
|
||||
};
|
||||
}
|
||||
, verify: function (token, jwk) {
|
||||
if (!OAUTH3.crypto) {
|
||||
return OAUTH3.PromiseA.reject(new Error("OAuth3 crypto library unavailable"));
|
||||
}
|
||||
jwk = jwk.publicKey || jwk;
|
||||
|
||||
var parts = token.split(/\./g);
|
||||
var data = OAUTH3._binStr.binStrToBuffer(parts.slice(0, 2).join('.'));
|
||||
var signature = OAUTH3._base64.urlSafeToBuffer(parts[2]);
|
||||
|
||||
return OAUTH3.crypto.core.verify(jwk, data, signature);
|
||||
return OAUTH3.crypto.core.verify(jwk, data, signature).then(function () {
|
||||
return OAUTH3.jwt.decode(token);
|
||||
});
|
||||
}
|
||||
, sign: function (payload, jwk) {
|
||||
if (!OAUTH3.crypto) {
|
||||
return OAUTH3.PromiseA.reject(new Error("OAuth3 crypto library unavailable"));
|
||||
}
|
||||
jwk = jwk.privateKey || jwk;
|
||||
|
||||
var prom;
|
||||
if (jwk.kid) {
|
||||
prom = OAUTH3.PromiseA.resolve(jwk.kid);
|
||||
} else {
|
||||
prom = OAUTH3.crypto.thumbprintJwk(jwk);
|
||||
}
|
||||
|
||||
return prom.then(function (kid) {
|
||||
// Currently the crypto part of the OAuth3 library only supports ES256
|
||||
var header = {type: 'JWT', alg: 'ES256', kid: kid};
|
||||
var input = [
|
||||
OAUTH3._base64.encodeUrlSafe(JSON.stringify(header, null))
|
||||
, OAUTH3._base64.encodeUrlSafe(JSON.stringify(payload, null))
|
||||
].join('.');
|
||||
|
||||
return OAUTH3.crypto.core.sign(jwk, OAUTH3._binStr.binStrToBuffer(input))
|
||||
.then(OAUTH3._base64.bufferToUrlSafe)
|
||||
.then(function (signature) {
|
||||
return input + '.' + signature;
|
||||
});
|
||||
});
|
||||
}
|
||||
, freshness: function (tokenMeta, staletime, now) {
|
||||
// If the token doesn't expire then it's always fresh.
|
||||
|
|
|
@ -82,6 +82,7 @@
|
|||
};
|
||||
|
||||
function checkWebCrypto() {
|
||||
/* global OAUTH3_crypto_fallback */
|
||||
var loadFallback = function() {
|
||||
var prom;
|
||||
loadFallback = function () { return prom; };
|
||||
|
@ -102,11 +103,10 @@
|
|||
return prom;
|
||||
};
|
||||
function checkException(name, func) {
|
||||
new OAUTH3.PromiseA(function (resolve) { resolve(func()); })
|
||||
OAUTH3.PromiseA.resolve().then(func)
|
||||
.then(function () {
|
||||
OAUTH3.crypto.core[name] = webCrypto[name];
|
||||
})
|
||||
.catch(function (err) {
|
||||
}, function (err) {
|
||||
console.warn('error with WebCrypto', name, '- using fallback', err);
|
||||
loadFallback().then(function () {
|
||||
OAUTH3.crypto.core[name] = OAUTH3_crypto_fallback[name];
|
||||
|
@ -195,100 +195,60 @@
|
|||
.then(OAUTH3._base64.bufferToUrlSafe);
|
||||
};
|
||||
|
||||
OAUTH3.crypto._createKey = function (ppid) {
|
||||
var saltProm = OAUTH3.crypto.core.randomBytes(16);
|
||||
var kekProm = saltProm.then(function (salt) {
|
||||
return OAUTH3.crypto.core.pbkdf2(ppid, salt);
|
||||
});
|
||||
|
||||
var ecdsaProm = OAUTH3.crypto.core.genEcdsaKeyPair()
|
||||
.then(function (keyPair) {
|
||||
OAUTH3.crypto.createKeyPair = function () {
|
||||
// TODO: maybe support other types of key pairs, not just ECDSA P-256
|
||||
return OAUTH3.crypto.core.genEcdsaKeyPair().then(function (keyPair) {
|
||||
return OAUTH3.crypto.thumbprintJwk(keyPair.publicKey).then(function (kid) {
|
||||
keyPair.privateKey.alg = keyPair.publicKey.alg = 'ES256';
|
||||
keyPair.privateKey.kid = keyPair.publicKey.kid = kid;
|
||||
return keyPair;
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
OAUTH3.crypto.encryptKeyPair = function (keyPair, password) {
|
||||
var saltProm = OAUTH3.crypto.core.randomBytes(16);
|
||||
var kekProm = saltProm.then(function (salt) {
|
||||
return OAUTH3.crypto.core.pbkdf2(password, salt);
|
||||
});
|
||||
|
||||
return OAUTH3.PromiseA.all([
|
||||
kekProm
|
||||
, ecdsaProm
|
||||
, saltProm
|
||||
, OAUTH3.crypto.core.randomBytes(16)
|
||||
, OAUTH3.crypto.core.randomBytes(12)
|
||||
, OAUTH3.crypto.core.randomBytes(12)
|
||||
]).then(function (results) {
|
||||
, ]).then(function (results) {
|
||||
var kek = results[0];
|
||||
var keyPair = results[1];
|
||||
var salt = results[2];
|
||||
var userSecret = results[3];
|
||||
var ecdsaIv = results[4];
|
||||
var secretIv = results[5];
|
||||
var salt = results[1];
|
||||
var ecdsaIv = results[2];
|
||||
|
||||
return OAUTH3.PromiseA.all([
|
||||
OAUTH3.crypto.core.encrypt(kek, ecdsaIv, OAUTH3._binStr.binStrToBuffer(JSON.stringify(keyPair.privateKey)))
|
||||
, OAUTH3.crypto.core.encrypt(kek, secretIv, userSecret)
|
||||
])
|
||||
.then(function (encrypted) {
|
||||
var privKeyBuf = OAUTH3._binStr.binStrToBuffer(JSON.stringify(keyPair.privateKey));
|
||||
return OAUTH3.crypto.core.encrypt(kek, ecdsaIv, privKeyBuf).then(function (encrypted) {
|
||||
return {
|
||||
publicKey: keyPair.publicKey
|
||||
, privateKey: OAUTH3._base64.bufferToUrlSafe(encrypted[0])
|
||||
, userSecret: OAUTH3._base64.bufferToUrlSafe(encrypted[1])
|
||||
, privateKey: OAUTH3._base64.bufferToUrlSafe(encrypted)
|
||||
, salt: OAUTH3._base64.bufferToUrlSafe(salt)
|
||||
, ecdsaIv: OAUTH3._base64.bufferToUrlSafe(ecdsaIv)
|
||||
, secretIv: OAUTH3._base64.bufferToUrlSafe(secretIv)
|
||||
};
|
||||
, };
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
OAUTH3.crypto._decryptKey = function (ppid, storedObj) {
|
||||
OAUTH3.crypto.decryptKeyPair = function (storedObj, password) {
|
||||
var salt = OAUTH3._base64.urlSafeToBuffer(storedObj.salt);
|
||||
var encJwk = OAUTH3._base64.urlSafeToBuffer(storedObj.privateKey);
|
||||
var iv = OAUTH3._base64.urlSafeToBuffer(storedObj.ecdsaIv);
|
||||
|
||||
return OAUTH3.crypto.core.pbkdf2(ppid, salt)
|
||||
return OAUTH3.crypto.core.pbkdf2(password, salt)
|
||||
.then(function (key) {
|
||||
return OAUTH3.crypto.core.decrypt(key, iv, encJwk);
|
||||
})
|
||||
.then(OAUTH3._binStr.bufferToBinStr)
|
||||
.then(JSON.parse);
|
||||
};
|
||||
|
||||
OAUTH3.crypto._getKey = function (ppid) {
|
||||
return OAUTH3.crypto.core.sha256(OAUTH3._binStr.binStrToBuffer(ppid))
|
||||
.then(function (hash) {
|
||||
var name = 'kek-' + OAUTH3._base64.bufferToUrlSafe(hash);
|
||||
var promise;
|
||||
|
||||
if (window.localStorage.getItem(name) === null) {
|
||||
promise = OAUTH3.crypto._createKey(ppid).then(function (key) {
|
||||
window.localStorage.setItem(name, JSON.stringify(key));
|
||||
return key;
|
||||
});
|
||||
} else {
|
||||
promise = OAUTH3.PromiseA.resolve(JSON.parse(window.localStorage.getItem(name)));
|
||||
}
|
||||
|
||||
return promise.then(function (storedObj) {
|
||||
return OAUTH3.crypto._decryptKey(ppid, storedObj);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
OAUTH3.crypto._signPayload = function (payload) {
|
||||
return OAUTH3.crypto._getKey('some PPID').then(function (key) {
|
||||
var header = {type: 'JWT', alg: key.alg, kid: key.kid};
|
||||
var input = [
|
||||
OAUTH3._base64.encodeUrlSafe(JSON.stringify(header, null))
|
||||
, OAUTH3._base64.encodeUrlSafe(JSON.stringify(payload, null))
|
||||
].join('.');
|
||||
|
||||
return OAUTH3.crypto.core.sign(key, OAUTH3._binStr.binStrToBuffer(input))
|
||||
.then(OAUTH3._base64.bufferToUrlSafe)
|
||||
.then(function (signature) {
|
||||
return input + '.' + signature;
|
||||
});
|
||||
.then(JSON.parse)
|
||||
.then(function (privateKey) {
|
||||
return {
|
||||
privateKey: privateKey
|
||||
, publicKey: storedObj.publicKey
|
||||
, };
|
||||
});
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue