nx_h2_test_leaf.nx source
↩ module page · 160 lines · 7715 B
1// nx_h2_test_leaf.nx -- TUTOR-BOOTSTRAP SCAFFOLD (Claude, B1 rung(6) R4-H2-009),
2// NOT credited as team self-authoring (EoE back-fill owed).
3//
4// SHARED self-signed Ed25519 X.509 LEAF (SAN=localhost) minter + PEM exporter for
5// the h2 INTEROP TEST harnesses. Rule 15 (DRY through shared libraries): the
6// identical self-signed-leaf + PEM-export + civil-date code was COPY-PASTED into
7// _h2_serve_loopback_gate.nx (hsl_*), _h2_serve_curl_daemon.nx (hcd_*) AND
8// _h2_multistream_curl_daemon.nx (mcd_*) -- 3 copies = the rule-15 "extract"
9// trigger. This organ is that extraction; new harnesses COMPOSE it instead of a
10// 4th copy. (The 3 existing copies stay BYTE-UNTOUCHED for now -- migrating them
11// is an additive follow-on so the proven daemons are not disturbed this rung.)
12//
13// CONTRACT:
14// h2tl_make_cert(out_cert_der: *u8, out_cert_len: *i64, out_priv: *u8) -> i64
15// mint an Ed25519 keypair + self-signed leaf (CN/SAN=localhost, notBefore
16// now-1d, notAfter now+365d). out_cert_der must be >=8192 bytes, out_priv 32.
17// Returns 0 ok; -1 keygen, -2 pubkey, -3 inputs, -4 build.
18// h2tl_write_pem(cert_der: *u8, der_len: i64, path_z: *u8) -> i64
19// write the DER as a PEM file an external curl can trust via --cacert
20// (BEGIN/END CERTIFICATE armor + base64 re-wrapped at 64 cols, composing the
21// canonical nx_base64 b64_encode -- nx_pem.nx only DECODES). Returns 0 ok,
22// <0 on open/write failure.
23//
24// COMPOSES (each imported once): nx_csprng (csprng_fill), nx_ed25519_signature
25// (ed25519_pub_from_priv), hub/nx_x509_build + nx_x509 + nx_x509_trust_store
26// (self-signed leaf builder), nx_base64 (b64_encode), nx_syscalls (mmap/file I/O +
27// nx_str_cpy + sys_now_realtime_sec).
28//
29// license_tier: INDEPENDENT_REDERIVE
30// genealogy_id: international-research-sources/ietf/rfc_5280 + rfc_4648 + rfc_8032
31// lineage_id: nishi_h2_test_leaf_b1r6
32
33import "nx_syscalls.nx"
34import "nx_str.nx"
35import "nx_csprng.nx"
36import "nx_ed25519_signature.nx"
37import "hub/nx_x509_build.nx"
38import "nx_x509.nx"
39import "nx_x509_trust_store.nx"
40import "nx_base64.nx"
41const K_MAGIC_719468: i64 = 719468
42const K_MAGIC_146097: i64 = 146097
43const K_MAGIC_146096: i64 = 146096
44const K_MAGIC_1460: i64 = 1460
45const K_MAGIC_36524: i64 = 36524
46const K_MAGIC_86400: i64 = 86400
47const K_MAGIC_3600: i64 = 3600
48const K_MAGIC_8192: i64 = 8192
49
50// ---- public-domain civil-date math (Howard Hinnant) ----
51func h2tl_civil_from_days(days: i64, out_y: *i64, out_m: *i64, out_d: *i64) -> i64 {
52 let z: i64 = days + K_MAGIC_719468
53 let era: i64 = if z >= 0 then z / K_MAGIC_146097 else (z - K_MAGIC_146096) / K_MAGIC_146097
54 let doe: i64 = z - era * K_MAGIC_146097
55 let yoe: i64 = (doe - doe / K_MAGIC_1460 + doe / K_MAGIC_36524 - doe / K_MAGIC_146096) / 365
56 let y: i64 = yoe + era * 400
57 let doy: i64 = doe - (365 * yoe + yoe / 4 - yoe / 100)
58 let mp: i64 = (5 * doy + 2) / 153
59 let d: i64 = doy - (153 * mp + 2) / 5 + 1
60 var m: i64 = mp + 3
61 if mp < 10 { m = mp + 3 } else { m = mp - 9 }
62 var yy: i64 = y
63 if m <= 2 { yy = y + 1 }
64 out_y[0] = yy; out_m[0] = m; out_d[0] = d
65 return 0
66}
67func h2tl_format_generalized_time(unix_sec: i64, out_15: *u8) -> i64 {
68 let days: i64 = unix_sec / K_MAGIC_86400
69 let sod: i64 = unix_sec - days * K_MAGIC_86400
70 let hh: i64 = sod / K_MAGIC_3600
71 let mm: i64 = (sod - hh * K_MAGIC_3600) / 60
72 let ss: i64 = sod - hh * K_MAGIC_3600 - mm * 60
73 let yp: *i64 = sys_mmap(8) as *i64
74 let mp: *i64 = sys_mmap(8) as *i64
75 let dp: *i64 = sys_mmap(8) as *i64
76 h2tl_civil_from_days(days, yp, mp, dp)
77 let y: i64 = yp[0]; let mo: i64 = mp[0]; let d: i64 = dp[0]
78 out_15[0] = ((0x30 + ((y / 1000) % 10)) & 0xff) as u8
79 out_15[1] = ((0x30 + ((y / 100) % 10)) & 0xff) as u8
80 out_15[2] = ((0x30 + ((y / 10) % 10)) & 0xff) as u8
81 out_15[3] = ((0x30 + ( y % 10)) & 0xff) as u8
82 out_15[4] = ((0x30 + (mo / 10)) & 0xff) as u8
83 out_15[5] = ((0x30 + (mo % 10)) & 0xff) as u8
84 out_15[6] = ((0x30 + (d / 10)) & 0xff) as u8
85 out_15[7] = ((0x30 + (d % 10)) & 0xff) as u8
86 out_15[8] = ((0x30 + (hh / 10)) & 0xff) as u8
87 out_15[9] = ((0x30 + (hh % 10)) & 0xff) as u8
88 out_15[10] = ((0x30 + (mm / 10)) & 0xff) as u8
89 out_15[11] = ((0x30 + (mm % 10)) & 0xff) as u8
90 out_15[12] = ((0x30 + (ss / 10)) & 0xff) as u8
91 out_15[13] = ((0x30 + (ss % 10)) & 0xff) as u8
92 out_15[14] = 0x5A as u8 // 'Z'
93 return 0
94}
95
96// ---- mint the self-signed Ed25519 leaf (SAN=localhost) ----
97func h2tl_make_cert(out_cert_der: *u8, out_cert_len: *i64, out_priv: *u8) -> i64 {
98 if nx_csprng_fill(out_priv, 32) != 0 { return 0 - 1 }
99 let pub32: *u8 = sys_mmap(32)
100 if ed25519_pub_from_priv(out_priv, pub32) != 0 { return 0 - 2 }
101 let now: i64 = sys_now_realtime_sec()
102 let nb: *u8 = sys_mmap(16)
103 let na: *u8 = sys_mmap(16)
104 h2tl_format_generalized_time(now - K_MAGIC_86400, nb)
105 h2tl_format_generalized_time(now + 365 * K_MAGIC_86400, na)
106 let san_name: *u8 = sys_mmap(16); nx_str_cpy(san_name, "localhost" as *u8)
107 let san_ptrs: *i64 = sys_mmap(8) as *i64; san_ptrs[0] = san_name as i64
108 let san_lens: *i64 = sys_mmap(8) as *i64; san_lens[0] = 9
109 let domain: *u8 = sys_mmap(16); nx_str_cpy(domain, "localhost" as *u8)
110 let inp: *NxX509BuildInputs = sys_mmap(256) as *NxX509BuildInputs
111 let in_rc: i64 = nx_x509_inputs_init(inp, domain, 9, san_ptrs, san_lens, 1,
112 out_priv, pub32, nb, na, now)
113 if in_rc != NX_X509_OK { return 0 - 3 }
114 let cdn: *i64 = sys_mmap(8) as *i64; cdn[0] = 0
115 let brc: i64 = nx_x509_build_self_signed(inp, out_cert_der, K_MAGIC_8192, cdn)
116 if brc != NX_X509_OK { return 0 - 4 }
117 out_cert_len[0] = cdn[0]
118 return 0
119}
120
121// ---- PEM export (composes nx_base64 b64_encode, re-wrapped at 64 cols) ----
122func h2tl_write_pem(cert_der: *u8, der_len: i64, path_z: *u8) -> i64 {
123 let b64cap: i64 = 4 * ((der_len + 2) / 3) + 8
124 let b64buf: *u8 = sys_mmap(b64cap)
125 let b64n: i64 = b64_encode(cert_der, der_len, b64buf)
126 if b64n <= 0 { return 0 - 1 }
127 let fd: i64 = sys_openat_wr(path_z, 0x1a4)
128 if fd < 0 { return 0 - 2 }
129 if sys_write(fd, "-----BEGIN CERTIFICATE-----\n" as *u8, 28) != 28 { sys_close(fd); return 0 - 3 }
130 var off: i64 = 0
131 while off < b64n {
132 var line: i64 = 64
133 if b64n - off < 64 { line = b64n - off }
134 let w: i64 = sys_write(fd, ((b64buf as i64) + off) as *u8, line)
135 if w != line { sys_close(fd); return 0 - 4 }
136 if sys_write(fd, "\n" as *u8, 1) != 1 { sys_close(fd); return 0 - 5 }
137 off = off + line
138 }
139 if sys_write(fd, "-----END CERTIFICATE-----\n" as *u8, 26) != 26 { sys_close(fd); return 0 - 6 }
140 sys_close(fd)
141 return 0
142}
143
144// ---- self-gate main(): LIBRARY organ -- mint a cert + write a PEM to /tmp and
145// print its DER length so it BUILDS + smoke-tests standalone. ----
146func main() -> i64 {
147 sys_write(1, "nx_h2_test_leaf: shared self-signed Ed25519 SAN=localhost leaf + PEM (B1 rung 6 R4-H2-009)\n" as *u8, 90)
148 let der: *u8 = sys_mmap(K_MAGIC_8192)
149 let dlen: *i64 = sys_mmap(8) as *i64
150 let priv: *u8 = sys_mmap(32)
151 if h2tl_make_cert(der, dlen, priv) < 0 {
152 sys_write(1, " SMOKE FAIL: cert mint\n" as *u8, 23); sys_exit(1); return 1
153 }
154 let pp: *u8 = sys_mmap(64); nx_str_cpy(pp, "/tmp/nx_h2_test_leaf_smoke.pem" as *u8)
155 if h2tl_write_pem(der, dlen[0], pp) < 0 {
156 sys_write(1, " SMOKE FAIL: pem write\n" as *u8, 24); sys_exit(2); return 2
157 }
158 sys_write(1, " SMOKE OK: minted leaf + wrote /tmp/nx_h2_test_leaf_smoke.pem (DER bytes below)\n" as *u8, 79)
159 sys_exit(0); return 0
160}