code wiki / _hdl_build / nx_efivars_enrol.nx
nx_efivars_enrol.nx source
↩ module page · 460 lines · 21474 B
1// nx_efivars_enrol.nx -- F103e RUNG 11b: enrol OUR key into a UEFI variable store.
2//
3// The last software rung. Builds an EFI_SIGNATURE_LIST around our self-signed cert and writes PK,
4// KEK and db into a varstore derived from the EMPTY (setup-mode) OVMF varstore. Booting secboot
5// firmware against it should put the machine in USER MODE with OUR key as the authority -- so the
6// decisive test is a PAIR: our SIGNED image accepted, an UNSIGNED image refused. Either alone proves
7// nothing (a varstore that failed to load would accept both; a broken one would refuse both).
8//
9// ★★★★★★EVERY CONSTANT IS TAKEN FROM THE ARTIFACT, NOT FROM MEMORY. `OVMF_VARS_4M.ms.fd` has PK/KEK/db
10// already enrolled, so the vendor GUIDs, the attribute word, and even EFI_CERT_X509_GUID (which is
11// literally the first 16 bytes of the real `db` data) are READ OUT OF IT. Writing a UEFI GUID from
12// recall is a fabricated constant, and a wrong one here fails in a way that looks like "Secure Boot
13// just doesn't like us".
14//
15// EFI_SIGNATURE_LIST: SignatureType[16] | SignatureListSize[4] | SignatureHeaderSize[4] |
16// SignatureSize[4] | (header) | { SignatureOwner[16] | SignatureData[] }...
17//
18// Usage: nx_efivars_enrol build <empty_vars.fd> <ms_vars.fd> <out_vars.fd>
19// nx_efivars_enrol selftest <empty_vars.fd> <ms_vars.fd>
20// Exit: 0 GREEN | 1 RED | 3 UNPROVEN.
21// license_tier: ORIGINAL
22import "nx_syscalls.nx"
23import "nx_sha256.nx"
24import "nx_u2048.nx"
25import "nx_u2048_mul.nx"
26import "nx_rsa2048_mod.nx"
27import "nx_rsa2048_mod_exp.nx"
28import "nx_rsa2048_mont.nx"
29import "nx_rsa2048_mod_exp_big.nx"
30import "nx_asn1.nx"
31import "nx_x509.nx"
32import "nx_rsa_pkcs1_v1_5_sha256.nx"
33import "nx_u2048_millerrabin.nx"
34import "nx_u2048_smallops.nx"
35import "nx_rsa_keygen.nx"
36import "nx_rsa_pkcs1_sign.nx"
37import "nx_x509_emit.nx"
38import "nx_efivarstore.nx"
39import "nx_pe_authhash.nx"
40const EN_MAGIC_4096: i64 = 4096
41const EN_MAGIC_20260808: i64 = 20260808
42const EN_MAGIC_1024: i64 = 1024
43const EN_MAGIC_8192: i64 = 8192
44const EN_MAGIC_65537: i64 = 65537
45const EN_MAGIC_4097: i64 = 4097
46const EN_MAGIC_16384: i64 = 16384
47
48const EN_ATTRS: i64 = 39 // MEASURED from the MS varstore: NV|BS|RT|TIME_BASED_AUTH_WRITE
49
50func en_p(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 }
51func en_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 }
52func en_fn(fd: i64, v: i64) -> i64 {
53 let bb: *u8 = sys_mmap(28); var m: i64 = v
54 if m < 0 { m = 0 - m; bb[0] = 45 as u8; sys_write(fd, bb, 1) }
55 let t: *u8 = sys_mmap(28); var k: i64 = 0
56 if m == 0 { t[0] = 48 as u8; k = 1 }
57 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
58 var i: i64 = 0
59 while i < k { bb[i] = t[k - 1 - i]; i = i + 1 }
60 sys_write(fd, bb, k); return 0
61}
62func en_eq_str(a: *u8, b: *u8) -> i64 {
63 var i: i64 = 0
64 while a[i] != (0 as u8) { if a[i] != b[i] { return 0 } i = i + 1 }
65 if b[i] != (0 as u8) { return 0 }
66 return 1
67}
68func en_w32(b: *u8, o: i64, v: i64) -> i64 {
69 b[o] = (v & 0xff) as u8; b[o+1] = ((v >> 8) & 0xff) as u8
70 b[o+2] = ((v >> 16) & 0xff) as u8; b[o+3] = ((v >> 24) & 0xff) as u8
71 return 0
72}
73
74// Build an EFI_SIGNATURE_LIST holding one X.509 cert. `x509guid` is the 16-byte SignatureType read
75// out of the real MS db. Returns total length.
76func en_siglist(out: *u8, x509guid: *u8, cert: *u8, certlen: i64) -> i64 {
77 var i: i64 = 0
78 while i < 16 { out[i] = x509guid[i]; i = i + 1 }
79 let sigsize: i64 = 16 + certlen // SignatureOwner + the DER
80 let total: i64 = 28 + sigsize
81 en_w32(out, 16, total) // SignatureListSize
82 en_w32(out, 20, 0) // SignatureHeaderSize
83 en_w32(out, 24, sigsize) // SignatureSize
84 var j: i64 = 0
85 while j < 16 { out[28 + j] = 0 as u8; j = j + 1 } // SignatureOwner: all-zero is valid
86 var k: i64 = 0
87 while k < certlen { out[44 + k] = cert[k]; k = k + 1 }
88 return total
89}
90
91// Append one AUTHENTICATED_VARIABLE_HEADER + name + data at `off`. Returns the next offset.
92// Layout MEASURED from the MS varstore by nx_efivarstore.
93func en_put_var(b: *u8, off: i64, name: *u8, guid: *u8, data: *u8, dlen: i64) -> i64 {
94 var nl: i64 = 0
95 while name[nl] != (0 as u8) { nl = nl + 1 }
96 let namesize: i64 = nl * 2 + 2 // UCS-2 including the null terminator
97 b[off] = 0xAA as u8 // StartId 0x55AA, little-endian
98 b[off + 1] = 0x55 as u8
99 b[off + 2] = 0x3F as u8 // State = VAR_ADDED
100 b[off + 3] = 0x00 as u8
101 en_w32(b, off + 4, EN_ATTRS)
102 var z: i64 = 0
103 while z < 8 { b[off + 8 + z] = 0 as u8; z = z + 1 } // MonotonicCount
104 while z < 24 { b[off + 8 + z] = 0 as u8; z = z + 1 } // TimeStamp (EFI_TIME, 16 B)
105 en_w32(b, off + 32, 0) // PubKeyIndex
106 en_w32(b, off + 36, namesize)
107 en_w32(b, off + 40, dlen)
108 var g: i64 = 0
109 while g < 16 { b[off + 44 + g] = guid[g]; g = g + 1 }
110 var i: i64 = 0
111 while i < nl {
112 b[off + 60 + i * 2] = name[i]
113 b[off + 60 + i * 2 + 1] = 0 as u8
114 i = i + 1
115 }
116 b[off + 60 + nl * 2] = 0 as u8
117 b[off + 60 + nl * 2 + 1] = 0 as u8
118 let dataoff: i64 = off + 60 + namesize
119 var d: i64 = 0
120 while d < dlen { b[dataoff + d] = data[d]; d = d + 1 }
121 var adv: i64 = 60 + namesize + dlen
122 while (adv % 4) != 0 { adv = adv + 1 } // 4-byte alignment, as the walker assumes
123 return off + adv
124}
125
126// pull the 16-byte SignatureType GUID out of the real MS `db` variable's data
127func en_x509guid_from_ms(ms: *u8, mslen: i64, out16: *u8) -> i64 {
128 let sop: *i64 = sys_mmap(16) as *i64
129 let first: i64 = ev_first_var(ms, mslen, sop)
130 if first < 0 { return 0 - 1 }
131 let fo: *i64 = sys_mmap(16) as *i64
132 let fdz: *i64 = sys_mmap(16) as *i64
133 let dbn: *u8 = "db" as *u8
134 ev_walk(ms, mslen, first, sop[0], 0, dbn, 2, fo, fdz)
135 if fo[0] < 0 { return 0 - 2 }
136 let nsz: i64 = ev_r32(ms, fo[0] + 36)
137 let dataoff: i64 = fo[0] + 60 + nsz
138 var i: i64 = 0
139 while i < 16 { out16[i] = ms[dataoff + i]; i = i + 1 } // SignatureType of the first list
140 return 0
141}
142// and the vendor GUID of a named variable, likewise from the artifact
143func en_vendor_guid(ms: *u8, mslen: i64, name: *u8, nlen: i64, out16: *u8) -> i64 {
144 let sop: *i64 = sys_mmap(16) as *i64
145 let first: i64 = ev_first_var(ms, mslen, sop)
146 if first < 0 { return 0 - 1 }
147 let fo: *i64 = sys_mmap(16) as *i64
148 let fdz: *i64 = sys_mmap(16) as *i64
149 ev_walk(ms, mslen, first, sop[0], 0, name, nlen, fo, fdz)
150 if fo[0] < 0 { return 0 - 2 }
151 var i: i64 = 0
152 while i < 16 { out16[i] = ms[fo[0] + 44 + i]; i = i + 1 }
153 return 0
154}
155
156// ---- THE DISCRIMINATOR -------------------------------------------------------------------------
157// db can authorise a binary by its SHA-256 Authenticode hash instead of by certificate. If a
158// hash-authorised UNSIGNED image boots, then the varstore/db/enforcement path is proven end to end
159// and the earlier failure is isolated to the PKCS#7 ENCODING ALONE. If it does NOT boot, the fault
160// is upstream of the signature and I was chasing the wrong thing.
161// ★★★★★★ONE EXPERIMENT THAT SEPARATES TWO CAUSES IS WORTH MORE THAN ANY AMOUNT OF STARING AT THE
162// ENCODER -- AND IT COSTS 30 SECONDS.
163// EFI_CERT_SHA256_GUID is READ from the MS `dbx` (76 B = 28 header + 16 owner + 32 hash = exactly
164// one sha256 signature), never typed.
165func en_sha256guid_from_ms(ms: *u8, mslen: i64, out16: *u8) -> i64 {
166 let sop: *i64 = sys_mmap(16) as *i64
167 let first: i64 = ev_first_var(ms, mslen, sop)
168 if first < 0 { return 0 - 1 }
169 let fo: *i64 = sys_mmap(16) as *i64
170 let fdz: *i64 = sys_mmap(16) as *i64
171 let dbxn: *u8 = "dbx" as *u8
172 ev_walk(ms, mslen, first, sop[0], 0, dbxn, 3, fo, fdz)
173 if fo[0] < 0 { return 0 - 2 }
174 if fdz[0] != 76 { return 0 - 3 } // assert the shape before trusting the GUID
175 let nsz: i64 = ev_r32(ms, fo[0] + 36)
176 let dataoff: i64 = fo[0] + 60 + nsz
177 if ev_r32(ms, dataoff + 24) != 48 { return 0 - 4 } // SignatureSize must be 16+32
178 var i: i64 = 0
179 while i < 16 { out16[i] = ms[dataoff + i]; i = i + 1 }
180 return 0
181}
182
183func en_build_hashdb(emptyp: *u8, msp: *u8, imgp: *u8, outp: *u8) -> i64 {
184 let l1: *i64 = sys_mmap(16) as *i64
185 let base: *u8 = sys_read_file(emptyp, l1)
186 if l1[0] <= 0 { return 0 - 1 }
187 let l2: *i64 = sys_mmap(16) as *i64
188 let ms: *u8 = sys_read_file(msp, l2)
189 if l2[0] <= 0 { return 0 - 1 }
190 let l3: *i64 = sys_mmap(16) as *i64
191 let img: *u8 = sys_read_file(imgp, l3)
192 if l3[0] <= 0 { return 0 - 1 }
193
194 let h: *u8 = sys_mmap(64)
195 if pe_authhash(img, l3[0], h) != 0 { en_p("not a hashable PE\n" as *u8); return 0 - 2 }
196 let shag: *u8 = sys_mmap(32)
197 let rc: i64 = en_sha256guid_from_ms(ms, l2[0], shag)
198 if rc != 0 { en_p("cannot extract EFI_CERT_SHA256_GUID rc=" as *u8); en_fn(1, rc); en_p("\n" as *u8); return 0 - 3 }
199
200 // db = one sha256 signature list authorising exactly this image
201 let sl: *u8 = sys_mmap(EN_MAGIC_4096)
202 var i: i64 = 0
203 while i < 16 { sl[i] = shag[i]; i = i + 1 }
204 en_w32(sl, 16, 28 + 48) // SignatureListSize
205 en_w32(sl, 20, 0) // SignatureHeaderSize
206 en_w32(sl, 24, 48) // SignatureSize = owner + sha256
207 var z: i64 = 0
208 while z < 16 { sl[28 + z] = 0 as u8; z = z + 1 } // SignatureOwner
209 var k: i64 = 0
210 while k < 32 { sl[44 + k] = h[k]; k = k + 1 }
211 let sllen: i64 = 28 + 48
212
213 // PK/KEK still need a CERT (they authorise variable updates, not images)
214 let x509g: *u8 = sys_mmap(32)
215 if en_x509guid_from_ms(ms, l2[0], x509g) != 0 { return 0 - 4 }
216 let pp: *i64 = u2048_alloc(); let qq: *i64 = u2048_alloc()
217 let n: *i64 = u2048_alloc(); let d: *i64 = u2048_alloc()
218 let st: *i64 = sys_mmap(16) as *i64
219 st[0] = EN_MAGIC_20260808
220 if kg_keygen(EN_MAGIC_1024, pp, qq, n, d, st, 1) != 1 { return 0 - 5 }
221 let cert: *u8 = sys_mmap(EN_MAGIC_8192)
222 let toff: *i64 = sys_mmap(16) as *i64
223 let tlen: *i64 = sys_mmap(16) as *i64
224 let cn: *u8 = "Nishi Platform Key" as *u8
225 let certlen: i64 = x509_emit_selfsigned(cert, n, d, EN_MAGIC_65537, cn, EN_MAGIC_4097, toff, tlen)
226 let csl: *u8 = sys_mmap(EN_MAGIC_16384)
227 let csllen: i64 = en_siglist(csl, x509g, cert, certlen)
228
229 let dbg: *u8 = sys_mmap(32)
230 let globalg: *u8 = sys_mmap(32)
231 let dbn: *u8 = "db" as *u8
232 let pkn: *u8 = "PK" as *u8
233 let kekn: *u8 = "KEK" as *u8
234 if en_vendor_guid(ms, l2[0], dbn, 2, dbg) != 0 { return 0 - 6 }
235 if en_vendor_guid(ms, l2[0], pkn, 2, globalg) != 0 { return 0 - 6 }
236
237 let out: *u8 = sys_mmap(l1[0] + EN_MAGIC_4096)
238 var c: i64 = 0
239 while c < l1[0] { out[c] = base[c]; c = c + 1 }
240 let sop: *i64 = sys_mmap(16) as *i64
241 let first: i64 = ev_first_var(out, l1[0], sop)
242 if first < 0 { return 0 - 7 }
243 var off: i64 = first
244 off = en_put_var(out, off, dbn, dbg, sl, sllen) // db = HASH of the image
245 off = en_put_var(out, off, kekn, globalg, csl, csllen)
246 off = en_put_var(out, off, pkn, globalg, csl, csllen)
247 let fd: i64 = sys_openat_wr(outp, 0x1a4)
248 if fd < 0 { return 0 - 8 }
249 sys_write(fd, out, l1[0])
250 sys_close(fd)
251 en_p("hash-db varstore written; authorised sha256 of " as *u8); en_p(imgp); en_p("\n" as *u8)
252 return sllen
253}
254
255// =================================================================================================
256func en_build(emptyp: *u8, msp: *u8, outp: *u8, quiet: i64) -> i64 {
257 let l1: *i64 = sys_mmap(16) as *i64
258 let base: *u8 = sys_read_file(emptyp, l1)
259 if l1[0] <= 0 { en_p("cannot read empty varstore\n" as *u8); return 0 - 1 }
260 let l2: *i64 = sys_mmap(16) as *i64
261 let ms: *u8 = sys_read_file(msp, l2)
262 if l2[0] <= 0 { en_p("cannot read ms varstore\n" as *u8); return 0 - 1 }
263
264 let x509g: *u8 = sys_mmap(32)
265 if en_x509guid_from_ms(ms, l2[0], x509g) != 0 { en_p("cannot extract EFI_CERT_X509_GUID\n" as *u8); return 0 - 2 }
266 let dbg: *u8 = sys_mmap(32)
267 let globalg: *u8 = sys_mmap(32)
268 let dbn: *u8 = "db" as *u8
269 let pkn: *u8 = "PK" as *u8
270 if en_vendor_guid(ms, l2[0], dbn, 2, dbg) != 0 { return 0 - 3 }
271 if en_vendor_guid(ms, l2[0], pkn, 2, globalg) != 0 { return 0 - 3 }
272
273 // our key + cert
274 let pp: *i64 = u2048_alloc(); let qq: *i64 = u2048_alloc()
275 let n: *i64 = u2048_alloc(); let d: *i64 = u2048_alloc()
276 let st: *i64 = sys_mmap(16) as *i64
277 st[0] = EN_MAGIC_20260808
278 if quiet == 0 { en_p("TEST-KEY-DO-NOT-USE: generating the deterministic platform key...\n" as *u8) }
279 if kg_keygen(EN_MAGIC_1024, pp, qq, n, d, st, 1) != 1 { en_p("keygen failed\n" as *u8); return 0 - 4 }
280 let cert: *u8 = sys_mmap(EN_MAGIC_8192)
281 let toff: *i64 = sys_mmap(16) as *i64
282 let tlen: *i64 = sys_mmap(16) as *i64
283 let cn: *u8 = "Nishi Platform Key" as *u8
284 let certlen: i64 = x509_emit_selfsigned(cert, n, d, EN_MAGIC_65537, cn, EN_MAGIC_4097, toff, tlen)
285 if certlen <= 0 { en_p("cert emit failed\n" as *u8); return 0 - 5 }
286
287 let sl: *u8 = sys_mmap(EN_MAGIC_16384)
288 let sllen: i64 = en_siglist(sl, x509g, cert, certlen)
289
290 // copy the empty store and append our three variables
291 let out: *u8 = sys_mmap(l1[0] + EN_MAGIC_4096)
292 var i: i64 = 0
293 while i < l1[0] { out[i] = base[i]; i = i + 1 }
294 let sop: *i64 = sys_mmap(16) as *i64
295 let first: i64 = ev_first_var(out, l1[0], sop)
296 if first < 0 { en_p("empty store not parseable\n" as *u8); return 0 - 6 }
297 var off: i64 = first
298 let kekn: *u8 = "KEK" as *u8
299 off = en_put_var(out, off, dbn, dbg, sl, sllen)
300 off = en_put_var(out, off, kekn, globalg, sl, sllen)
301 off = en_put_var(out, off, pkn, globalg, sl, sllen) // PK last: it is what leaves SETUP mode
302
303 let fd: i64 = sys_openat_wr(outp, 0x1a4)
304 if fd < 0 { en_p("cannot write output\n" as *u8); return 0 - 7 }
305 sys_write(fd, out, l1[0])
306 sys_close(fd)
307 if quiet == 0 {
308 en_p("wrote " as *u8); en_p(outp); en_p(" siglist=" as *u8); en_fn(1, sllen)
309 en_p(" cert=" as *u8); en_fn(1, certlen); en_p(" end_off=" as *u8); en_fn(1, off); en_p("\n" as *u8)
310 }
311 return sllen
312}
313
314func en_selftest(emptyp: *u8, msp: *u8) -> i64 {
315 var pass: i64 = 0
316 var teeth: i64 = 0
317 let outp: *u8 = "/tmp/nishi_vars.fd" as *u8
318
319 // T1 EFI_CERT_X509_GUID must come OUT OF the MS db, and must not be all-zero or all-FF.
320 teeth = teeth + 1
321 let l2: *i64 = sys_mmap(16) as *i64
322 let ms: *u8 = sys_read_file(msp, l2)
323 let g: *u8 = sys_mmap(32)
324 var t1: i64 = 0
325 if l2[0] > 0 { if en_x509guid_from_ms(ms, l2[0], g) == 0 {
326 var nz: i64 = 0
327 var nf: i64 = 0
328 var i: i64 = 0
329 while i < 16 { if (g[i] as i64) != 0 { nz = 1 } if (g[i] as i64) != 0xFF { nf = 1 } i = i + 1 }
330 if nz == 1 { if nf == 1 { t1 = 1 } }
331 } }
332 if t1 == 1 { pass = pass + 1; en_p("EN-T1 EFI_CERT_X509_GUID extracted from the real MS db GREEN\n" as *u8) }
333 else { en_p("EN-T1 RED\n" as *u8) }
334
335 // T2 build the store
336 teeth = teeth + 1
337 let sllen: i64 = en_build(emptyp, msp, outp, 0)
338 if sllen > 0 { pass = pass + 1; en_p("EN-T2 varstore built GREEN\n" as *u8) }
339 else { en_p("EN-T2 RED rc=" as *u8); en_fn(1, sllen); en_p("\n" as *u8) }
340
341 // T3 OUR OWN PARSER MUST READ BACK EXACTLY THREE VARIABLES, BY NAME. Writing a structure and not
342 // re-reading it is how a varstore that firmware silently ignores looks like success.
343 teeth = teeth + 1
344 let l3: *i64 = sys_mmap(16) as *i64
345 let nv: *u8 = sys_read_file(outp, l3)
346 var got: i64 = 0
347 var total: i64 = 0
348 if l3[0] > 0 {
349 let sop: *i64 = sys_mmap(16) as *i64
350 let first: i64 = ev_first_var(nv, l3[0], sop)
351 if first > 0 {
352 let fo: *i64 = sys_mmap(16) as *i64
353 let fdz: *i64 = sys_mmap(16) as *i64
354 let empty: *u8 = "" as *u8
355 total = ev_walk(nv, l3[0], first, sop[0], 0, empty, 0, fo, fdz)
356 let dbn: *u8 = "db" as *u8
357 let kekn: *u8 = "KEK" as *u8
358 let pkn: *u8 = "PK" as *u8
359 ev_walk(nv, l3[0], first, sop[0], 0, dbn, 2, fo, fdz); if fo[0] >= 0 { got = got + 1 }
360 ev_walk(nv, l3[0], first, sop[0], 0, kekn, 3, fo, fdz); if fo[0] >= 0 { got = got + 1 }
361 ev_walk(nv, l3[0], first, sop[0], 0, pkn, 2, fo, fdz); if fo[0] >= 0 { got = got + 1 }
362 }
363 }
364 if got == 3 { if total == 3 { pass = pass + 1
365 en_p("EN-T3 read back PK+KEK+db, total=3 GREEN\n" as *u8) }
366 else { en_p("EN-T3 RED total=" as *u8); en_fn(1, total); en_p("\n" as *u8) } }
367 else { en_p("EN-T3 RED got=" as *u8); en_fn(1, got); en_p("\n" as *u8) }
368
369 // T4 the db data must be a well-formed EFI_SIGNATURE_LIST whose sizes are self-consistent --
370 // a length field that disagrees with the payload is exactly what firmware rejects silently.
371 teeth = teeth + 1
372 var t4: i64 = 0
373 if l3[0] > 0 {
374 let sop: *i64 = sys_mmap(16) as *i64
375 let first: i64 = ev_first_var(nv, l3[0], sop)
376 let fo: *i64 = sys_mmap(16) as *i64
377 let fdz: *i64 = sys_mmap(16) as *i64
378 let dbn: *u8 = "db" as *u8
379 ev_walk(nv, l3[0], first, sop[0], 0, dbn, 2, fo, fdz)
380 if fo[0] >= 0 {
381 let nsz: i64 = ev_r32(nv, fo[0] + 36)
382 let dof: i64 = fo[0] + 60 + nsz
383 let listsize: i64 = ev_r32(nv, dof + 16)
384 let hdrsize: i64 = ev_r32(nv, dof + 20)
385 let sigsize: i64 = ev_r32(nv, dof + 24)
386 if listsize == fdz[0] { if hdrsize == 0 { if (28 + sigsize) == listsize { t4 = 1 } } }
387 }
388 }
389 if t4 == 1 { pass = pass + 1; en_p("EN-T4 db signature-list sizes self-consistent GREEN\n" as *u8) }
390 else { en_p("EN-T4 RED\n" as *u8) }
391
392 // T5 the embedded cert must still parse -- proving we wrote the DER, not a mangled copy
393 teeth = teeth + 1
394 var t5: i64 = 0
395 if l3[0] > 0 {
396 let sop: *i64 = sys_mmap(16) as *i64
397 let first: i64 = ev_first_var(nv, l3[0], sop)
398 let fo: *i64 = sys_mmap(16) as *i64
399 let fdz: *i64 = sys_mmap(16) as *i64
400 let dbn: *u8 = "db" as *u8
401 ev_walk(nv, l3[0], first, sop[0], 0, dbn, 2, fo, fdz)
402 if fo[0] >= 0 {
403 let nsz: i64 = ev_r32(nv, fo[0] + 36)
404 let dof: i64 = fo[0] + 60 + nsz
405 let sigsize: i64 = ev_r32(nv, dof + 24)
406 let certoff: i64 = dof + 28 + 16
407 let certlen: i64 = sigsize - 16
408 let xc: *X509Cert = sys_mmap(512) as *X509Cert
409 if x509_parse((nv + certoff) as *u8, certlen, xc) >= 0 { t5 = 1 }
410 }
411 }
412 if t5 == 1 { pass = pass + 1; en_p("EN-T5 the enrolled cert parses out of the varstore GREEN\n" as *u8) }
413 else { en_p("EN-T5 RED\n" as *u8) }
414
415 // T6 NEGATIVE CONTROL: the SOURCE empty store must still contain ZERO variables, proving T3
416 // measured OUR writes and not something that was already there.
417 teeth = teeth + 1
418 let l4: *i64 = sys_mmap(16) as *i64
419 let eb: *u8 = sys_read_file(emptyp, l4)
420 var zero: i64 = 0 - 1
421 if l4[0] > 0 {
422 let sop: *i64 = sys_mmap(16) as *i64
423 let first: i64 = ev_first_var(eb, l4[0], sop)
424 let fo: *i64 = sys_mmap(16) as *i64
425 let fdz: *i64 = sys_mmap(16) as *i64
426 let empty: *u8 = "" as *u8
427 zero = ev_walk(eb, l4[0], first, sop[0], 0, empty, 0, fo, fdz)
428 }
429 if zero == 0 { pass = pass + 1; en_p("EN-T6 neg-control-source-store-was-empty GREEN\n" as *u8) }
430 else { en_p("EN-T6 RED source had " as *u8); en_fn(1, zero); en_p("\n" as *u8) }
431
432 en_p("EN-SELFTEST " as *u8); en_fn(1, pass); en_p("/" as *u8); en_fn(1, teeth); en_p("\n" as *u8)
433 let lf: i64 = sys_openat_append("knowledge/status/nishi_os.log" as *u8, 0x1a4)
434 if lf >= 0 {
435 en_fp(lf, "EFIVARSENROL selftest teeth=" as *u8); en_fn(lf, pass)
436 en_fp(lf, "of" as *u8); en_fn(lf, teeth)
437 en_fp(lf, " scope=structural-NOT-yet-firmware-accepted verdict=" as *u8)
438 if pass == teeth { en_fp(lf, "GREEN\n" as *u8) } else { en_fp(lf, "RED\n" as *u8) }
439 sys_close(lf)
440 }
441 if pass == teeth { sys_exit(0); return 0 }
442 sys_exit(1); return 1
443}
444
445func main(argc: i64, argv: *i64) -> i64 {
446 if argc >= 4 { if en_eq_str(argv[1] as *u8, "selftest" as *u8) == 1 {
447 return en_selftest(argv[2] as *u8, argv[3] as *u8) } }
448 if argc >= 5 { if en_eq_str(argv[1] as *u8, "build" as *u8) == 1 {
449 let r: i64 = en_build(argv[2] as *u8, argv[3] as *u8, argv[4] as *u8, 0)
450 if r > 0 { sys_exit(0); return 0 }
451 sys_exit(1); return 1 } }
452 if argc >= 6 { if en_eq_str(argv[1] as *u8, "hashdb" as *u8) == 1 {
453 let r: i64 = en_build_hashdb(argv[2] as *u8, argv[3] as *u8, argv[4] as *u8, argv[5] as *u8)
454 if r > 0 { sys_exit(0); return 0 }
455 en_p("hashdb failed rc=" as *u8); en_fn(1, r); en_p("\n" as *u8)
456 sys_exit(1); return 1 } }
457 en_p("usage: nx_efivars_enrol build <empty.fd> <ms.fd> <out.fd> | selftest <empty.fd> <ms.fd>\n" as *u8)
458 en_p(" nx_efivars_enrol hashdb <empty.fd> <ms.fd> <image.efi> <out.fd>\n" as *u8)
459 sys_exit(2); return 2
460}