code wiki / _hdl_build / nx_email_send_gate.nx
nx_email_send_gate.nx source
↩ module page · 95 lines · 4188 B
1// nx_email_send_gate.nx -- GATE for outbound DKIM send (nx_email_send).
2//
3// COMPLETENESS : compose a message, DKIM ed25519-sha256 sign it, and
4// verify the signature validates against the public key.
5// TAMPER : flip a BODY byte -> verify fails (bh mismatch); flip a
6// signed HEADER byte -> verify fails (sig mismatch).
7// NEG-CONTROL : verify under a DIFFERENT public key -> fails (it truly
8// checks the signature, not just structure).
9//
10// Evidence -> knowledge/status/email_send.log (SENDGATE ... verdict=GREEN)
11// license_tier: ORIGINAL
12import "nx_email_send.nx"
13import "nx_csprng.nx"
14import "nx_syscalls.nx"
15
16const SEND_LOG: *u8 = "knowledge/status/email_send.log"
17
18func ew(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 }
19func epf(fd: i64, label: *u8, pass: i64) -> i64 { ew(fd, label); if pass == 1 { ew(fd, "PASS" as *u8) } else { ew(fd, "FAIL" as *u8) } return 0 }
20func slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
21func cp(dst: *u8, src: *u8, n: i64) -> i64 { var i: i64 = 0; while i < n { dst[i] = src[i]; i = i + 1 } return 0 }
22func g_find(hay: *u8, hlen: i64, needle: *u8) -> i64 {
23 let nl: i64 = slen(needle); var i: i64 = 0
24 while i + nl <= hlen {
25 var k: i64 = 0; var hit: i64 = 1
26 while k < nl { if (hay[i + k] & 0xff) != (needle[k] & 0xff) { hit = 0; k = nl } else { k = k + 1 } }
27 if hit == 1 { return i }
28 i = i + 1
29 }
30 return 0 - 1
31}
32func contains(hay: *u8, hlen: i64, needle: *u8) -> i64 { if g_find(hay, hlen, needle) >= 0 { return 1 } return 0 }
33
34func main() -> i64 {
35 var ok: i64 = 1
36
37 // keypair
38 let priv: *u8 = sys_mmap(32)
39 nx_csprng_fill(priv, 32)
40 let pub: *u8 = sys_mmap(32)
41 ed25519_pub_from_priv(priv, pub)
42
43 // compose + sign
44 let msg: *u8 = sys_mmap(4096)
45 let mlen: i64 = nx_email_compose("self@jasonewest.com" as *u8, "bob@remote.test" as *u8, "Hello from self" as *u8, "This is a DKIM-signed message from the sovereign stack.\r\n" as *u8, msg, 4096)
46 let signed: *u8 = sys_mmap(8192)
47 let sln: i64 = nx_email_dkim_sign_message(msg, mlen, priv, "nishi1" as *u8, "jasonewest.com" as *u8, signed, 8192)
48
49 var header_present: i64 = contains(signed, sln, "DKIM-Signature: v=1; a=ed25519-sha256" as *u8)
50 if header_present != 1 { ok = 0 }
51
52 var verify_self: i64 = 0
53 if nx_email_dkim_verify_message(signed, sln, pub) == 1 { verify_self = 1 } else { ok = 0 }
54
55 // tamper body (flip a byte near the end = in the body)
56 let t1: *u8 = sys_mmap(8192)
57 cp(t1, signed, sln)
58 t1[sln - 3] = (t1[sln - 3] + 1) as u8
59 var tamper_body: i64 = 0
60 if nx_email_dkim_verify_message(t1, sln, pub) == 0 { tamper_body = 1 } else { ok = 0 }
61
62 // tamper a signed header (flip a byte in the Subject value)
63 let t2: *u8 = sys_mmap(8192)
64 cp(t2, signed, sln)
65 let sp: i64 = g_find(t2, sln, "Hello from self" as *u8)
66 if sp >= 0 { t2[sp] = (t2[sp] + 1) as u8 }
67 var tamper_header: i64 = 0
68 if nx_email_dkim_verify_message(t2, sln, pub) == 0 { tamper_header = 1 } else { ok = 0 }
69
70 // wrong key
71 let priv2: *u8 = sys_mmap(32)
72 nx_csprng_fill(priv2, 32)
73 let pub2: *u8 = sys_mmap(32)
74 ed25519_pub_from_priv(priv2, pub2)
75 var wrongkey: i64 = 0
76 if nx_email_dkim_verify_message(signed, sln, pub2) == 0 { wrongkey = 1 } else { ok = 0 }
77
78 var fd: i64 = 1
79 while fd >= 1 {
80 ew(fd, "SENDGATE authored=organ dkim=ed25519-sha256 domain=jasonewest.com " as *u8)
81 epf(fd, "header_present=" as *u8, header_present)
82 epf(fd, " verify_self=" as *u8, verify_self)
83 epf(fd, " tamper_body=" as *u8, tamper_body)
84 epf(fd, " tamper_header=" as *u8, tamper_header)
85 epf(fd, " wrongkey_negctrl=" as *u8, wrongkey)
86 if ok == 1 { ew(fd, " verdict=GREEN\n" as *u8) } else { ew(fd, " verdict=RED\n" as *u8) }
87 if fd == 1 {
88 let lf: i64 = sys_openat_append(SEND_LOG, 420)
89 if lf >= 1 { fd = lf } else { fd = 0 }
90 } else { sys_close(fd); fd = 0 }
91 }
92
93 if ok == 1 { return 0 }
94 return 1
95}