diff --git a/lib/client.js b/lib/client.js index 3f84625d..731daae6 100644 --- a/lib/client.js +++ b/lib/client.js @@ -1191,7 +1191,12 @@ module.exports = (issuer, aadIssValidation = false) => class Client extends Base return instance(this).get(cacheKey); } - const derivedBuffer = crypto.createHash('sha256') + const hash = len <= 256 ? 'sha256' : len <= 384 ? 'sha384' : len <= 512 ? 'sha512' : false; // eslint-disable-line no-nested-ternary + if (!hash) { + throw new Error('unsupported symmetric encryption key derivation'); + } + + const derivedBuffer = crypto.createHash(hash) .update(this.client_secret) .digest() .slice(0, len / 8); diff --git a/test/client/client_instance.test.js b/test/client/client_instance.test.js index db7f0c56..7fe913df 100644 --- a/test/client/client_instance.test.js +++ b/test/client/client_instance.test.js @@ -1017,16 +1017,25 @@ describe('Client', () => { }); }); - it('#derivedKey', function () { + it('#derivedKey', async function () { const issuer = new Issuer(); const client = new issuer.Client({ client_id: 'identifier', client_secret: 'rj_JR' }); - return client.derivedKey('128') - .then((key) => { - expect(key).to.have.property('kty', 'oct'); - return client.derivedKey('128').then((cached) => { - expect(key).to.equal(cached); + for (const len of [120, 128, 184, 192, 248, 256]) { // eslint-disable-line no-restricted-syntax + await client.derivedKey(String(len)) // eslint-disable-line no-await-in-loop + .then((key) => { + expect(key).to.have.property('kty', 'oct'); + expect(key).to.have.property('length', len); + return client.derivedKey(String(len)).then((cached) => { + expect(key).to.equal(cached); + }); }); + } + + await client.derivedKey('1024') // eslint-disable-line no-await-in-loop + .then(fail, (err) => { + expect(err).to.be.instanceof(Error); + expect(err.message).to.eql('unsupported symmetric encryption key derivation'); }); }); @@ -3767,6 +3776,36 @@ describe('Client', () => { }); }); + it('encrypts for issuer using pre-shared client_secret (dir + A192CBC-HS384)', function () { + const client = new this.issuer.Client({ + client_id: 'identifier', + client_secret: 'GfsT479VMy5ZZZPquadPbN3wKzaFGYo1CTkb0IFFzDNODLEAuC2GUV3QsTye3xNQ', + request_object_encryption_alg: 'dir', + request_object_encryption_enc: 'A192CBC-HS384', + }); + + return client.requestObject({ state: 'foobar' }) + .then((encrypted) => { + const parts = encrypted.split('.'); + expect(JSON.parse(base64url.decode(parts[0]))).to.contain({ alg: 'dir', enc: 'A192CBC-HS384', cty: 'JWT' }).and.not.have.property('kid'); + }); + }); + + it('encrypts for issuer using pre-shared client_secret (dir + A256CBC-HS512)', function () { + const client = new this.issuer.Client({ + client_id: 'identifier', + client_secret: 'GfsT479VMy5ZZZPquadPbN3wKzaFGYo1CTkb0IFFzDNODLEAuC2GUV3QsTye3xNQ', + request_object_encryption_alg: 'dir', + request_object_encryption_enc: 'A256CBC-HS512', + }); + + return client.requestObject({ state: 'foobar' }) + .then((encrypted) => { + const parts = encrypted.split('.'); + expect(JSON.parse(base64url.decode(parts[0]))).to.contain({ alg: 'dir', enc: 'A256CBC-HS512', cty: 'JWT' }).and.not.have.property('kid'); + }); + }); + it('encrypts for issuer using pre-shared client_secret (dir + defaulted to A128CBC-HS256)', function () { const client = new this.issuer.Client({ client_id: 'identifier',