diff --git a/libs/auth/src/common/services/login-strategies/login-strategy.service.spec.ts b/libs/auth/src/common/services/login-strategies/login-strategy.service.spec.ts index 8647260ce5a..b0d9228f446 100644 --- a/libs/auth/src/common/services/login-strategies/login-strategy.service.spec.ts +++ b/libs/auth/src/common/services/login-strategies/login-strategy.service.spec.ts @@ -295,7 +295,7 @@ describe("LoginStrategyService", () => { new IdentityTokenResponse({ ForcePasswordReset: false, Kdf: KdfType.PBKDF2_SHA256, - KdfIterations: PBKDF2KdfConfig.PRELOGIN_ITERATIONS.min - 1, + KdfIterations: PBKDF2KdfConfig.PRELOGIN_ITERATIONS_MIN - 1, Key: "KEY", PrivateKey: "PRIVATE_KEY", ResetMasterPassword: false, @@ -309,7 +309,7 @@ describe("LoginStrategyService", () => { apiService.postPrelogin.mockResolvedValue( new PreloginResponse({ Kdf: KdfType.PBKDF2_SHA256, - KdfIterations: PBKDF2KdfConfig.PRELOGIN_ITERATIONS.min - 1, + KdfIterations: PBKDF2KdfConfig.PRELOGIN_ITERATIONS_MIN - 1, }), ); @@ -321,7 +321,7 @@ describe("LoginStrategyService", () => { }); await expect(sut.logIn(credentials)).rejects.toThrow( - `PBKDF2 iterations must be between ${PBKDF2KdfConfig.PRELOGIN_ITERATIONS.min} and ${PBKDF2KdfConfig.PRELOGIN_ITERATIONS.max}`, + `PBKDF2 iterations must be at least ${PBKDF2KdfConfig.PRELOGIN_ITERATIONS_MIN}, but was ${PBKDF2KdfConfig.PRELOGIN_ITERATIONS_MIN - 1}; possible pre-login downgrade attack detected.`, ); }); }); diff --git a/libs/common/src/auth/models/domain/kdf-config.ts b/libs/common/src/auth/models/domain/kdf-config.ts index 908b187e30c..1909aa875e5 100644 --- a/libs/common/src/auth/models/domain/kdf-config.ts +++ b/libs/common/src/auth/models/domain/kdf-config.ts @@ -13,7 +13,7 @@ export type KdfConfig = PBKDF2KdfConfig | Argon2KdfConfig; */ export class PBKDF2KdfConfig { static ITERATIONS = new RangeWithDefault(600_000, 2_000_000, 600_000); - static PRELOGIN_ITERATIONS = new RangeWithDefault(5000, 2_000_000, 600_000); + static PRELOGIN_ITERATIONS_MIN = 5000; kdfType: KdfType.PBKDF2_SHA256 = KdfType.PBKDF2_SHA256; iterations: number; @@ -38,9 +38,9 @@ export class PBKDF2KdfConfig { * A Valid PBKDF2 KDF configuration has KDF iterations between the 5000 and 2_000_000. */ validateKdfConfigForPrelogin(): void { - if (!PBKDF2KdfConfig.PRELOGIN_ITERATIONS.inRange(this.iterations)) { + if (PBKDF2KdfConfig.PRELOGIN_ITERATIONS_MIN > this.iterations) { throw new Error( - `PBKDF2 iterations must be between ${PBKDF2KdfConfig.PRELOGIN_ITERATIONS.min} and ${PBKDF2KdfConfig.PRELOGIN_ITERATIONS.max}`, + `PBKDF2 iterations must be at least ${PBKDF2KdfConfig.PRELOGIN_ITERATIONS_MIN}, but was ${this.iterations}; possible pre-login downgrade attack detected.`, ); } } @@ -58,9 +58,9 @@ export class Argon2KdfConfig { static PARALLELISM = new RangeWithDefault(1, 16, 4); static ITERATIONS = new RangeWithDefault(2, 10, 3); - static PRELOGIN_MEMORY = Argon2KdfConfig.MEMORY; - static PRELOGIN_PARALLELISM = Argon2KdfConfig.PARALLELISM; - static PRELOGIN_ITERATIONS = Argon2KdfConfig.ITERATIONS; + static PRELOGIN_MEMORY_MIN = 16; + static PRELOGIN_PARALLELISM_MIN = 1; + static PRELOGIN_ITERATIONS_MIN = 2; kdfType: KdfType.Argon2id = KdfType.Argon2id; iterations: number; @@ -86,7 +86,7 @@ export class Argon2KdfConfig { if (!Argon2KdfConfig.MEMORY.inRange(this.memory)) { throw new Error( - `Argon2 memory must be between ${Argon2KdfConfig.MEMORY.min}mb and ${Argon2KdfConfig.MEMORY.max}mb`, + `Argon2 memory must be between ${Argon2KdfConfig.MEMORY.min} MiB and ${Argon2KdfConfig.MEMORY.max} MiB`, ); } @@ -101,21 +101,21 @@ export class Argon2KdfConfig { * Validates the Argon2 KDF configuration for pre-login. */ validateKdfConfigForPrelogin(): void { - if (!Argon2KdfConfig.PRELOGIN_ITERATIONS.inRange(this.iterations)) { + if (Argon2KdfConfig.PRELOGIN_ITERATIONS_MIN > this.iterations) { throw new Error( - `Argon2 iterations must be between ${Argon2KdfConfig.PRELOGIN_ITERATIONS.min} and ${Argon2KdfConfig.PRELOGIN_ITERATIONS.max}`, + `Argon2 iterations must be at least ${Argon2KdfConfig.PRELOGIN_ITERATIONS_MIN}, but was ${this.iterations}; possible pre-login downgrade attack detected.`, ); } - if (!Argon2KdfConfig.PRELOGIN_MEMORY.inRange(this.memory)) { + if (Argon2KdfConfig.PRELOGIN_MEMORY_MIN > this.memory) { throw new Error( - `Argon2 memory must be between ${Argon2KdfConfig.PRELOGIN_MEMORY.min}mb and ${Argon2KdfConfig.PRELOGIN_MEMORY.max}mb`, + `Argon2 memory must be at least ${Argon2KdfConfig.PRELOGIN_MEMORY_MIN} MiB, but was ${this.memory} MiB; possible pre-login downgrade attack detected.`, ); } - if (!Argon2KdfConfig.PRELOGIN_PARALLELISM.inRange(this.parallelism)) { + if (Argon2KdfConfig.PRELOGIN_PARALLELISM_MIN > this.parallelism) { throw new Error( - `Argon2 parallelism must be between ${Argon2KdfConfig.PRELOGIN_PARALLELISM.min} and ${Argon2KdfConfig.PRELOGIN_PARALLELISM.max}.`, + `Argon2 parallelism must be at least ${Argon2KdfConfig.PRELOGIN_PARALLELISM_MIN}, but was ${this.parallelism}; possible pre-login downgrade attack detected.`, ); } } diff --git a/libs/common/src/auth/services/kdf-config.service.spec.ts b/libs/common/src/auth/services/kdf-config.service.spec.ts index 968b0cbd8ff..7f3613294e7 100644 --- a/libs/common/src/auth/services/kdf-config.service.spec.ts +++ b/libs/common/src/auth/services/kdf-config.service.spec.ts @@ -82,13 +82,6 @@ describe("KdfConfigService", () => { ); }); - it("validateKdfConfigForSetting(): should throw an error for invalid Argon2 memory", () => { - const kdfConfig: Argon2KdfConfig = new Argon2KdfConfig(3, 1025, 4); - expect(() => kdfConfig.validateKdfConfigForSetting()).toThrow( - `Argon2 memory must be between ${Argon2KdfConfig.MEMORY.min}mb and ${Argon2KdfConfig.MEMORY.max}mb`, - ); - }); - it("validateKdfConfigForSetting(): should throw an error for invalid Argon2 parallelism", () => { const kdfConfig: Argon2KdfConfig = new Argon2KdfConfig(3, 64, 17); expect(() => kdfConfig.validateKdfConfigForSetting()).toThrow( @@ -108,70 +101,32 @@ describe("KdfConfigService", () => { it("validateKdfConfigForPrelogin(): should throw an error for too low PBKDF2 iterations", () => { const kdfConfig: PBKDF2KdfConfig = new PBKDF2KdfConfig( - PBKDF2KdfConfig.PRELOGIN_ITERATIONS.min - 1, + PBKDF2KdfConfig.PRELOGIN_ITERATIONS_MIN - 1, ); expect(() => kdfConfig.validateKdfConfigForPrelogin()).toThrow( - `PBKDF2 iterations must be between ${PBKDF2KdfConfig.PRELOGIN_ITERATIONS.min} and ${PBKDF2KdfConfig.PRELOGIN_ITERATIONS.max}`, - ); - }); - - it("validateKdfConfigForPrelogin(): should throw an error for too high PBKDF2 iterations", () => { - const kdfConfig: PBKDF2KdfConfig = new PBKDF2KdfConfig( - PBKDF2KdfConfig.PRELOGIN_ITERATIONS.max + 1, - ); - expect(() => kdfConfig.validateKdfConfigForPrelogin()).toThrow( - `PBKDF2 iterations must be between ${PBKDF2KdfConfig.PRELOGIN_ITERATIONS.min} and ${PBKDF2KdfConfig.PRELOGIN_ITERATIONS.max}`, + `PBKDF2 iterations must be at least ${PBKDF2KdfConfig.PRELOGIN_ITERATIONS_MIN}, but was ${kdfConfig.iterations}; possible pre-login downgrade attack detected.`, ); }); it("validateKdfConfigForPrelogin(): should throw an error for too low Argon2 iterations", () => { const kdfConfig: Argon2KdfConfig = new Argon2KdfConfig( - Argon2KdfConfig.ITERATIONS.min - 1, + Argon2KdfConfig.PRELOGIN_ITERATIONS_MIN - 1, 64, 4, ); expect(() => kdfConfig.validateKdfConfigForPrelogin()).toThrow( - `Argon2 iterations must be between ${Argon2KdfConfig.ITERATIONS.min} and ${Argon2KdfConfig.ITERATIONS.max}`, - ); - }); - - it("validateKdfConfigForPrelogin(): should throw an error for too high Argon2 iterations", () => { - const kdfConfig: Argon2KdfConfig = new Argon2KdfConfig( - Argon2KdfConfig.PRELOGIN_ITERATIONS.max + 1, - 64, - 4, - ); - expect(() => kdfConfig.validateKdfConfigForPrelogin()).toThrow( - `Argon2 iterations must be between ${Argon2KdfConfig.ITERATIONS.min} and ${Argon2KdfConfig.ITERATIONS.max}`, + `Argon2 iterations must be at least ${Argon2KdfConfig.PRELOGIN_ITERATIONS_MIN}, but was ${kdfConfig.iterations}; possible pre-login downgrade attack detected.`, ); }); it("validateKdfConfigForPrelogin(): should throw an error for too low Argon2 memory", () => { const kdfConfig: Argon2KdfConfig = new Argon2KdfConfig( 3, - Argon2KdfConfig.PRELOGIN_MEMORY.min - 1, - 4, - ); - expect(() => kdfConfig.validateKdfConfigForPrelogin()).toThrow( - `Argon2 memory must be between ${Argon2KdfConfig.PRELOGIN_MEMORY.min}mb and ${Argon2KdfConfig.PRELOGIN_MEMORY.max}mb`, - ); - }); - - it("validateKdfConfigForPrelogin(): should throw an error for too high Argon2 memory", () => { - const kdfConfig: Argon2KdfConfig = new Argon2KdfConfig( - 3, - Argon2KdfConfig.PRELOGIN_MEMORY.max + 1, + Argon2KdfConfig.PRELOGIN_MEMORY_MIN - 1, 4, ); expect(() => kdfConfig.validateKdfConfigForPrelogin()).toThrow( - `Argon2 memory must be between ${Argon2KdfConfig.PRELOGIN_MEMORY.min}mb and ${Argon2KdfConfig.PRELOGIN_MEMORY.max}mb`, - ); - }); - - it("validateKdfConfigForPrelogin(): should throw an error for too high Argon2 parallelism", () => { - const kdfConfig: Argon2KdfConfig = new Argon2KdfConfig(3, 64, 17); - expect(() => kdfConfig.validateKdfConfigForPrelogin()).toThrow( - `Argon2 parallelism must be between ${Argon2KdfConfig.PRELOGIN_PARALLELISM.min} and ${Argon2KdfConfig.PRELOGIN_PARALLELISM.max}`, + `Argon2 memory must be at least ${Argon2KdfConfig.PRELOGIN_MEMORY_MIN} MiB, but was ${kdfConfig.memory} MiB; possible pre-login downgrade attack detected.`, ); }); });