code wiki / _hdl_build / nx_apistack_oidc.nx

nx_apistack_oidc.nx source

↩ module page · 64 lines · 3452 B

1// nx_apistack_oidc.nx -- CAP-API-OIDC: OAuth2/OIDC bridge for /api -- parse a JWT (header.payload.signature), 2// base64url-decode the payload, and extract a claim (sub / level / ...), so an external OIDC token can be mapped to 3// a Nishi level. (The primary auth stays OPAQUE aPAKE -- no secret ever sent -- which already exceeds bearer OAuth; 4// this is the interop bridge.) Pure base64url + claim scan, deterministic. license_tier: ORIGINAL 5import "nx_syscalls.nx" 6const K_MAGIC_8192: i64 = 8192 7 8// valid JWT shape = exactly 3 dot-separated parts (2 dots). 9func oidc_valid_structure(jwt: *u8, jwt_n: i64) -> i64 { 10 var dots: i64 = 0; var i: i64 = 0 11 while i < jwt_n { if jwt[i] == (46 as u8) { dots = dots + 1 } i = i + 1 } 12 if dots == 2 { return 1 } 13 return 0 14} 15func oidc_b64val(c: i64) -> i64 { 16 if c >= 65 { if c <= 90 { return c - 65 } } 17 if c >= 97 { if c <= 122 { return c - 97 + 26 } } 18 if c >= 48 { if c <= 57 { return c - 48 + 52 } } 19 if c == 45 { return 62 } 20 if c == 95 { return 63 } 21 return 0 - 1 22} 23func oidc_b64char(v: i64) -> i64 { 24 if v < 26 { return 65 + v } 25 if v < 52 { return 97 + v - 26 } 26 if v < 62 { return 48 + v - 52 } 27 if v == 62 { return 45 } 28 return 95 29} 30func oidc_b64url_decode(src: *u8, src_n: i64, out: *u8) -> i64 { 31 var o: i64 = 0; var acc: i64 = 0; var bits: i64 = 0; var i: i64 = 0 32 while i < src_n { 33 let v: i64 = oidc_b64val((src[i] as i64) & 0xff) 34 if v >= 0 { acc = (acc << 6) | v; bits = bits + 6; if bits >= 8 { bits = bits - 8; out[o] = ((acc >> bits) & 0xff) as u8; o = o + 1 } } 35 i = i + 1 36 } 37 return o 38} 39func oidc_b64url_encode(src: *u8, src_n: i64, out: *u8) -> i64 { 40 var o: i64 = 0; var acc: i64 = 0; var bits: i64 = 0; var i: i64 = 0 41 while i < src_n { acc = (acc << 8) | ((src[i] as i64) & 0xff); bits = bits + 8; while bits >= 6 { bits = bits - 6; out[o] = oidc_b64char((acc >> bits) & 0x3f) as u8; o = o + 1 } i = i + 1 } 42 if bits > 0 { out[o] = oidc_b64char((acc << (6 - bits)) & 0x3f) as u8; o = o + 1 } 43 return o 44} 45// extract a string claim from the JWT payload: decodes the 2nd part, finds "claim":"<value>". Returns value len (0=none). 46func oidc_extract_claim(jwt: *u8, jwt_n: i64, claim: *u8, claim_n: i64, out: *u8, cap: i64) -> i64 { 47 var d1: i64 = 0 - 1; var d2: i64 = 0 - 1; var i: i64 = 0 48 while i < jwt_n { if jwt[i] == (46 as u8) { if d1 < 0 { d1 = i } else { if d2 < 0 { d2 = i } } } i = i + 1 } 49 if d1 < 0 { out[0] = 0 as u8; return 0 } 50 if d2 < 0 { out[0] = 0 as u8; return 0 } 51 let dec: *u8 = sys_mmap(K_MAGIC_8192) 52 let dn: i64 = oidc_b64url_decode((jwt as i64 + d1 + 1) as *u8, d2 - d1 - 1, dec) 53 let needle: *u8 = sys_mmap(128); var nn: i64 = 0 54 needle[nn] = 34 as u8; nn = nn + 1 55 var k: i64 = 0; while k < claim_n { needle[nn] = claim[k]; nn = nn + 1; k = k + 1 } 56 needle[nn] = 34 as u8; nn = nn + 1; needle[nn] = 58 as u8; nn = nn + 1; needle[nn] = 34 as u8; nn = nn + 1 57 var p: i64 = 0; var found: i64 = 0 - 1 58 while p + nn <= dn { var m: i64 = 1; var j: i64 = 0; while j < nn { if dec[p + j] != needle[j] { m = 0; j = nn } else { j = j + 1 } } if m == 1 { found = p + nn; p = dn } else { p = p + 1 } } 59 if found < 0 { out[0] = 0 as u8; return 0 } 60 var o: i64 = 0; var q: i64 = found 61 while q < dn { if dec[q] == (34 as u8) { q = dn } else { if o < cap - 1 { out[o] = dec[q]; o = o + 1 } q = q + 1 } } 62 out[o] = 0 as u8 63 return o 64}