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}