code wiki / _hdl_build / nx_cms_mfa_gate.nx

nx_cms_mfa_gate.nx source

↩ module page · 45 lines · 2548 B

1// nx_cms_mfa_gate.nx -- INTEGRATION gate for the #12 MFA wiring in nx_cms_admin. Drives the REAL ca_mfa_ok 2// (the function the /admin/login handler calls after the argon2id password check) over a constructed POST 3// body + base32 secret: not-enrolled=pass-through, enrolled+valid=accept, enrolled+wrong/missing=reject, 4// enrolled+adjacent-step=accept (skew). exit 0 = pass, N = assertion N failed. 5import "nx_cms_admin.nx" // ca_mfa_ok, ca_cat + (transitively) nx_mfa: base32_encode/hotp_sha1_value/totp_sha1_render 6import "nx_assert.nx" 7 8// build "code=<6 ascii digits>" into buf -> returns length. 9func g_codebody(buf: *u8, code6: *u8) -> i64 { 10 var n: i64 = ca_cat(buf, 0, "code=" as *u8) 11 var i: i64 = 0; while i < 6 { buf[n] = code6[i]; n = n + 1; i = i + 1 } 12 return n 13} 14 15func main() -> i64 { 16 let seed: *u8 = "12345678901234567890" as *u8 17 let b32: *u8 = sys_mmap(64); let b32len: i64 = base32_encode(seed, 20, b32) 18 let now: i64 = 1111111111 19 let step: i64 = now / 30 20 21 let cur: *u8 = sys_mmap(16); totp_sha1_render(hotp_sha1_value(seed, 20, step, 6), 6, cur) 22 let m1: *u8 = sys_mmap(16); totp_sha1_render(hotp_sha1_value(seed, 20, step - 1, 6), 6, m1) 23 24 let okbody: *u8 = sys_mmap(64); let okn: i64 = g_codebody(okbody, cur) 25 let m1body: *u8 = sys_mmap(64); let m1n: i64 = g_codebody(m1body, m1) 26 let badbody: *u8 = sys_mmap(64); let badn: i64 = ca_cat(badbody, 0, "code=000000" as *u8) 27 let nobody: *u8 = sys_mmap(64); let non: i64 = ca_cat(nobody, 0, "other=x" as *u8) 28 29 nx_puts_err("login code="); sys_write(2, cur, 6); nx_puts_err("\n" as *u8) 30 31 // not enrolled (seclen 0) -> pass-through regardless of body (password-only, graceful) 32 if ca_mfa_ok(okbody, okn, b32, 0, now) != 1 { return 1 } 33 // enrolled + valid current code -> accept 34 if ca_mfa_ok(okbody, okn, b32, b32len, now) != 1 { return 2 } 35 // enrolled + adjacent-step code -> accept (clock skew) 36 if ca_mfa_ok(m1body, m1n, b32, b32len, now) != 1 { return 3 } 37 // enrolled + wrong code -> reject 38 if ca_mfa_ok(badbody, badn, b32, b32len, now) != 0 { return 4 } 39 // enrolled + NO code field -> reject (password alone is not enough) 40 if ca_mfa_ok(nobody, non, b32, b32len, now) != 0 { return 5 } 41 42 nx_puts_err("MFA wiring: not-enrolled=pass, valid=accept, skew=accept, wrong=reject, missing=reject\n" as *u8) 43 nx_puts_err("nx_cms_mfa_gate verdict=GREEN pass=5 (TOTP second factor LIVE in /admin/login; password alone insufficient when enrolled)\n" as *u8) 44 return 0 45}