code wiki / _hdl_build / _drv_f1_gate.nx

_drv_f1_gate.nx source

↩ module page · 176 lines · 9328 B

1// _drv_f1_gate.nx -- gate for CONSENT-GATED DEVICE TELEMETRY (X-DRV-F1). NO mocks. 2// 3// Drives the REAL nx_telemetry through the full consent lifecycle and asserts the privacy contract: 4// (1) NO-SHARE-BY-DEFAULT -- with a consent file carrying NO opt-in rows, the shared outbox stays 5// EMPTY and the local store is populated. Nothing leaves the device by default. 6// (2) OPT-IN -- a consent row "2 SHARED" makes deviceid=2's record appear in the shared outbox, 7// carrying a signature + the node public key (provenance). 8// (3) SIGNED-VERIFIES -- the shared record's ed25519 signature genuinely verifies over its payload 9// with the published pubkey (ed25519_verify_full == SIG_OK); a TAMPER (flip a payload byte) 10// makes verification FAIL -> the signature really binds the payload, not a decorative tag. 11// (4) REVOKE -- flipping the consent back to "2 LOCAL" makes the next run share NOTHING new. 12// 13// Evidence -> knowledge/status/telemetry.log (DRVF1GATE row). Sovereign. license_tier: ORIGINAL 14import "nx_syscalls.nx" 15import "nx_ed25519_signature.nx" 16 17const F_TELE: *u8 = "_offc/nx_telemetry.elf" 18const F_DEVMAP: *u8 = "knowledge/registry/emu_devmap.tsv" 19const F_SHARED: *u8 = "knowledge/status/telemetry_shared.log" 20const F_LOCAL: *u8 = "knowledge/status/telemetry_local.log" 21 22func g_p(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 23func g_fp(fd: i64, s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(fd,s,n); return 0 } 24func g_fn(fd: i64, v: i64) -> i64 { let bb: *u8=sys_mmap(28); var m: i64=v; if m<0{m=0-m}; let t: *u8=sys_mmap(28); var k: i64=0; if m==0{t[0]=48;k=1}; while m>0{t[k]=(48+(m%10)) as u8;m=m/10;k=k+1}; var i: i64=0; while i<k{bb[i]=t[k-1-i];i=i+1}; sys_write(fd,bb,k); return 0 } 25 26func g_run(prog: *u8, a1: *u8, a2: *u8) -> i64 { 27 let pid: i64 = sys_fork() 28 if pid == 0 { 29 let dn: i64 = sys_openat_wr("/tmp/_f1_run.out" as *u8, 0x1a4); if dn >= 0 { sys_dup3(dn, 1, 0); sys_dup3(dn, 2, 0) } 30 let argv: *i64 = sys_mmap(32) as *i64 31 argv[0] = prog as i64 32 var k: i64 = 1 33 if a1 != (0 as *u8) { argv[k] = a1 as i64; k = k + 1 } 34 if a2 != (0 as *u8) { argv[k] = a2 as i64; k = k + 1 } 35 argv[k] = 0 36 let envp: *i64 = sys_mmap(16) as *i64 37 envp[0] = "PATH=/usr/bin:/bin" as *u8 as i64; envp[1] = 0 38 sys_execve(prog, argv, envp) 39 sys_exit(127) 40 } 41 let st: *i64 = sys_mmap(16) as *i64 42 sys_wait4(pid, st, 0) 43 let sig: i64 = st[0] & 0x7f 44 if sig != 0 { return 128 + sig } 45 return (st[0] >> 8) & 0xff 46} 47 48func g_read(path: *u8, buf: *u8, cap: i64) -> i64 { 49 let fd: i64 = sys_openat_rd(path) 50 if fd < 0 { return 0 } 51 var n: i64 = 0 52 var go: i64 = 1 53 while go == 1 { let r: i64 = sys_read(fd, (buf as i64 + n) as *u8, cap - 1 - n); if r <= 0 { go = 0 } else { n = n + r } if n >= cap - 1 { go = 0 } } 54 sys_close(fd) 55 return n 56} 57 58func g_write_file(path: *u8, s: *u8) -> i64 { 59 let fd: i64 = sys_openat_wr(path, 0x1a4) 60 if fd < 0 { return 0 - 1 } 61 var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } 62 sys_write(fd, s, n); sys_close(fd) 63 return 0 64} 65func g_truncate(path: *u8) -> i64 { let fd: i64 = sys_openat_wr(path, 0x1a4); if fd >= 0 { sys_close(fd) } return 0 } 66 67func g_strlen(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n } 68 69// count occurrences of pat in buf[0,n). 70func g_count(buf: *u8, n: i64, pat: *u8) -> i64 { 71 let pl: i64 = g_strlen(pat) 72 if pl <= 0 { return 0 } 73 var c: i64 = 0; var i: i64 = 0 74 while i + pl <= n { var k: i64=0; var hit: i64=1; while k<pl { if buf[i+k]!=pat[k] { hit=0; k=pl } else { k=k+1 } } if hit==1 { c=c+1; i=i+pl } else { i=i+1 } } 75 return c 76} 77 78// find first index of pat in buf[from,n); -1 if absent. 79func g_find(buf: *u8, n: i64, from: i64, pat: *u8) -> i64 { 80 let pl: i64 = g_strlen(pat) 81 if pl <= 0 { return 0 - 1 } 82 var i: i64 = from 83 while i + pl <= n { var k: i64=0; var hit: i64=1; while k<pl { if buf[i+k]!=pat[k] { hit=0; k=pl } else { k=k+1 } } if hit==1 { return i } i=i+1 } 84 return 0 - 1 85} 86 87// hex-decode 2*m chars at src into out (m bytes); return m (or -1 on bad char). 88func g_hexdec(src: *u8, hexlen: i64, out: *u8) -> i64 { 89 if (hexlen % 2) != 0 { return 0 - 1 } 90 var i: i64 = 0 91 while i < hexlen / 2 { 92 let c0: i64 = src[i*2] as i64 93 let c1: i64 = src[i*2+1] as i64 94 var h0: i64 = 0 - 1; var h1: i64 = 0 - 1 95 if c0>=48 { if c0<=57 { h0=c0-48 } } if c0>=97 { if c0<=102 { h0=c0-87 } } if c0>=65 { if c0<=70 { h0=c0-55 } } 96 if c1>=48 { if c1<=57 { h1=c1-48 } } if c1>=97 { if c1<=102 { h1=c1-87 } } if c1>=65 { if c1<=70 { h1=c1-55 } } 97 if h0<0 { return 0-1 } if h1<0 { return 0-1 } 98 out[i] = ((h0<<4)|h1) as u8 99 i = i + 1 100 } 101 return hexlen / 2 102} 103 104func main() -> i64 { 105 g_p("=== consent-gated telemetry gate (X-DRV-F1: no-share-by-default + opt-in + signed + revoke) ===\n" as *u8) 106 let lfd: i64 = sys_openat_append("knowledge/status/telemetry.log" as *u8, 0x1a4) 107 108 // (1) NO-SHARE-BY-DEFAULT 109 g_write_file("/tmp/_f1_default.tsv" as *u8, "# no opt-in rows -> all LOCAL\n" as *u8) 110 g_truncate(F_SHARED); g_truncate(F_LOCAL) 111 g_run(F_TELE, "/tmp/_f1_default.tsv" as *u8, F_DEVMAP) 112 let sb1: *u8 = sys_mmap(65536); let sn1: i64 = g_read(F_SHARED, sb1, 65536) 113 let lb1: *u8 = sys_mmap(65536); let ln1: i64 = g_read(F_LOCAL, lb1, 65536) 114 var no_share_default: i64 = 0 115 if g_count(sb1, sn1, "SHARED " as *u8) == 0 { if g_count(lb1, ln1, "LOCAL " as *u8) >= 1 { no_share_default = 1 } } 116 117 // (2) OPT-IN: deviceid 2 -> SHARED 118 g_write_file("/tmp/_f1_optin.tsv" as *u8, "2\tSHARED\n" as *u8) 119 g_truncate(F_SHARED) 120 g_run(F_TELE, "/tmp/_f1_optin.tsv" as *u8, F_DEVMAP) 121 let sb2: *u8 = sys_mmap(65536); let sn2: i64 = g_read(F_SHARED, sb2, 65536) 122 let shared_n: i64 = g_count(sb2, sn2, "SHARED " as *u8) 123 var opt_in: i64 = 0 124 if shared_n == 1 { if g_find(sb2, sn2, 0, "sig=" as *u8) >= 0 { if g_find(sb2, sn2, 0, "pub=" as *u8) >= 0 { opt_in = 1 } } } 125 126 // (3) SIGNED-VERIFIES + TAMPER: extract payload / sig / pub from the shared line, ed25519-verify. 127 var verifies: i64 = 0 128 var tamper_fails: i64 = 0 129 let ps: i64 = g_find(sb2, sn2, 0, "SHARED " as *u8) 130 let sigpos: i64 = g_find(sb2, sn2, 0, " sig=" as *u8) 131 let pubpos: i64 = g_find(sb2, sn2, 0, " pub=" as *u8) 132 if ps >= 0 { if sigpos >= 0 { if pubpos >= 0 { 133 let pstart: i64 = ps + 7 // after "SHARED " 134 let plen: i64 = sigpos - pstart // payload bytes (exactly what was signed) 135 let msg: *u8 = sys_mmap(2048) 136 var i: i64 = 0 137 while i < plen { msg[i] = sb2[pstart + i]; i = i + 1 } 138 let sighex: i64 = sigpos + 5 // after " sig=" 139 let sig: *u8 = sys_mmap(64) 140 g_hexdec((sb2 as i64 + sighex) as *u8, 128, sig) 141 let pubhex: i64 = pubpos + 5 // after " pub=" 142 let pub: *u8 = sys_mmap(32) 143 g_hexdec((sb2 as i64 + pubhex) as *u8, 64, pub) 144 if ed25519_verify_full(pub, msg, plen, sig) == NX_ED25519_SIG_OK { verifies = 1 } 145 // tamper: flip a payload byte -> verification must FAIL (signature binds the payload) 146 msg[0] = (msg[0] + 1) as u8 147 if ed25519_verify_full(pub, msg, plen, sig) != NX_ED25519_SIG_OK { tamper_fails = 1 } 148 } } } 149 150 // (4) REVOKE: deviceid 2 -> LOCAL again -> shares nothing new 151 g_write_file("/tmp/_f1_revoke.tsv" as *u8, "2\tLOCAL\n" as *u8) 152 g_truncate(F_SHARED) 153 g_run(F_TELE, "/tmp/_f1_revoke.tsv" as *u8, F_DEVMAP) 154 let sb3: *u8 = sys_mmap(65536); let sn3: i64 = g_read(F_SHARED, sb3, 65536) 155 var revoke_ok: i64 = 0 156 if g_count(sb3, sn3, "SHARED " as *u8) == 0 { revoke_ok = 1 } 157 158 g_p(" no_share_default=" as *u8); g_fn(1, no_share_default) 159 g_p(" opt_in=" as *u8); g_fn(1, opt_in) 160 g_p(" signed_verifies=" as *u8); g_fn(1, verifies) 161 g_p(" tamper_fails=" as *u8); g_fn(1, tamper_fails) 162 g_p(" revoke=" as *u8); g_fn(1, revoke_ok); g_p("\n" as *u8) 163 164 var pass: i64 = 0 165 if no_share_default == 1 { if opt_in == 1 { if verifies == 1 { if tamper_fails == 1 { if revoke_ok == 1 { pass = 1 } } } } } 166 167 if pass == 1 { 168 g_p("DRVF1GATE verdict=GREEN (consent-gated telemetry: DEFAULT LOCAL-ONLY [shared outbox empty], opt-in SHARES a record carrying a GENUINE ed25519 signature [verifies with the node pubkey; a payload tamper makes it FAIL], and REVOKE stops sharing -- privacy-first, no-share-by-default, sovereign)\n" as *u8) 169 if lfd >= 0 { g_fp(lfd, "DRVF1GATE verdict=GREEN keystone=consent-gated-telemetry no-share-by-default=yes opt-in=yes ed25519-signed=verified tamper=rejected revoke=yes epoch=" as *u8); g_fn(lfd, sys_now_realtime_sec()); g_fp(lfd, "\n" as *u8); sys_close(lfd) } 170 sys_exit(0); return 0 171 } 172 g_p("DRVF1GATE verdict=RED (not all green)\n" as *u8) 173 if lfd >= 0 { g_fp(lfd, "DRVF1GATE verdict=RED nsd=" as *u8); g_fn(lfd, no_share_default); g_fp(lfd, " optin=" as *u8); g_fn(lfd, opt_in); g_fp(lfd, " verify=" as *u8); g_fn(lfd, verifies); g_fp(lfd, " tamper=" as *u8); g_fn(lfd, tamper_fails); g_fp(lfd, " revoke=" as *u8); g_fn(lfd, revoke_ok); g_fp(lfd, "\n" as *u8); sys_close(lfd) } 174 sys_exit(1) 175 return 1 176}