code wiki / (root) / nx_esign_eidas_gate.nx

nx_esign_eidas_gate.nx source

↩ module page · 123 lines · 6079 B

1// nx_esign_eidas_gate.nx -- INDEPENDENT GATE: the eIDAS SES/AES/QES ladder + the Certificate of Completion. 2// THE TOOTH THIS EXISTS FOR: Art 25(1) makes every real tier ADMISSIBLE, but Art 25(2) grants 3// equivalence to a HANDWRITTEN signature to QES alone. Widening that to AES is the most expensive 4// mistake in e-signature deployments, so the two predicates are proven separate at every rung. 5// Also: dropping either the QSCD or the qualified certificate demotes QES back to AES. 6// 7// WRITE BUDGET (debt 1785519597): reg_put costs ~678ms and reg_get ~70us, so this gate upgrades ONE 8// signature a property at a time -- 13 writes total, with unlimited free assertions between them. 9// license_tier: ORIGINAL No hw writes (Rule 26). expect_exit: 0 10 11import "nx_esign_lib.nx" 12 13func zz_puts(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 } 14func zz_putn(v: i64) -> i64 { 15 let t: *u8 = sys_mmap(32) 16 var o: i64 = 0 17 var m: i64 = v 18 if m < 0 { t[o] = 45 as u8; o = o + 1; m = 0 - m } 19 let d: *u8 = sys_mmap(32) 20 var k: i64 = 0 21 if m == 0 { d[0] = 48 as u8; k = 1 } 22 while m > 0 { d[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 } 23 var i: i64 = 0 24 while i < k { t[o] = d[k - 1 - i]; o = o + 1; i = i + 1 } 25 sys_write(1, t, o) 26 return 0 27} 28func zz_ck(cnt: *i64, name: *u8, got: i64, want: i64) -> i64 { 29 if got == want { 30 cnt[0] = cnt[0] + 1 31 zz_puts(" PASS " as *u8); zz_puts(name); zz_puts(" = " as *u8); zz_putn(got); zz_puts("\n" as *u8) 32 return 1 33 } 34 cnt[1] = cnt[1] + 1 35 zz_puts(" FAIL " as *u8); zz_puts(name); zz_puts(" got " as *u8); zz_putn(got) 36 zz_puts(" want " as *u8); zz_putn(want); zz_puts("\n" as *u8) 37 return 0 38} 39func zz_cks(cnt: *i64, name: *u8, got: *u8, want: *u8) -> i64 { 40 if mt_streq(got, want) == 1 { 41 cnt[0] = cnt[0] + 1 42 zz_puts(" PASS " as *u8); zz_puts(name); zz_puts(" = " as *u8); zz_puts(got); zz_puts("\n" as *u8) 43 return 1 44 } 45 cnt[1] = cnt[1] + 1 46 zz_puts(" FAIL " as *u8); zz_puts(name); zz_puts(" got " as *u8); zz_puts(got) 47 zz_puts(" want " as *u8); zz_puts(want); zz_puts("\n" as *u8) 48 return 0 49} 50func zz_pfx(tag: *u8, nonce: i64, out: *u8) -> i64 { 51 var o: i64 = mt_catcopy(out, 0, "knowledge/store/" as *u8) 52 o = mt_catcopy(out, o, tag) 53 o = mt_catn(out, o, nonce) 54 out[o] = 45 as u8 55 o = o + 1 56 out[o] = 0 as u8 57 return o 58} 59 60func main(argc: i64, argv: *i64) -> i64 { 61 let nonce: i64 = sys_now_us() 62 let cnt: *i64 = sys_mmap(16) as *i64 63 cnt[0] = 0 64 cnt[1] = 0 65 let sig: *u8 = "S" as *u8 66 let p: *u8 = sys_mmap(256) 67 let e: *u8 = sys_mmap(256) 68 zz_pfx("eidA" as *u8, nonce, p) 69 zz_pfx("eidB" as *u8, nonce, e) 70 let lbl: *u8 = sys_mmap(32) 71 72 zz_puts("NISHI-ESIGN-EIDAS-GATE (SES/AES/QES ladder; admissible vs wet-ink-equivalent kept separate)\n" as *u8) 73 74 zz_ck(cnt, "Z1 nothing recorded -> ES_NONE" as *u8, es_eidas_tier(e, sig), ES_NONE) 75 zz_ck(cnt, "Z1a ES_NONE is NOT admissible" as *u8, es_admissible(e, sig), 0) 76 es_tier_label(es_eidas_tier(e, sig), lbl) 77 zz_cks(cnt, "Z1b absent label" as *u8, lbl, "NONE" as *u8) 78 zz_ck(cnt, "Z2 no audit facts -> all six missing" as *u8, es_audit_missing(e, sig), 6) 79 zz_ck(cnt, "Z2a -> audit incomplete" as *u8, es_audit_complete(e, sig), 0) 80 81 es_set(p, sig, "sig_data" as *u8, "yes" as *u8) 82 zz_ck(cnt, "S1 signature data alone -> SES" as *u8, es_eidas_tier(p, sig), ES_SES) 83 zz_ck(cnt, "S1a SES IS admissible (Art 25(1))" as *u8, es_admissible(p, sig), 1) 84 zz_ck(cnt, "S1b SES is NOT wet-ink equivalent" as *u8, es_handwritten_equivalent(p, sig), 0) 85 86 es_set(p, sig, "unique_link" as *u8, "yes" as *u8) 87 zz_ck(cnt, "A1 unique link alone does not reach AES" as *u8, es_eidas_tier(p, sig), ES_SES) 88 es_set(p, sig, "signatory_id" as *u8, "yes" as *u8) 89 zz_ck(cnt, "A2 + signatory identification -> still SES" as *u8, es_eidas_tier(p, sig), ES_SES) 90 es_set(p, sig, "sole_control" as *u8, "yes" as *u8) 91 zz_ck(cnt, "A3 + sole control -> still SES, tamper detection missing" as *u8, es_eidas_tier(p, sig), ES_SES) 92 es_set(p, sig, "tamper_detect" as *u8, "yes" as *u8) 93 zz_ck(cnt, "A4 the FOURTH property completes AES" as *u8, es_eidas_tier(p, sig), ES_AES) 94 zz_ck(cnt, "A4a AES is admissible..." as *u8, es_admissible(p, sig), 1) 95 zz_ck(cnt, "A4b ...but AES is NOT wet-ink equivalent" as *u8, es_handwritten_equivalent(p, sig), 0) 96 97 es_set(p, sig, "qualified_cert" as *u8, "yes" as *u8) 98 zz_ck(cnt, "Q1 qualified certificate WITHOUT a QSCD stays AES" as *u8, es_eidas_tier(p, sig), ES_AES) 99 zz_ck(cnt, "Q1a still not wet-ink equivalent" as *u8, es_handwritten_equivalent(p, sig), 0) 100 es_set(p, sig, "qscd" as *u8, "yes" as *u8) 101 zz_ck(cnt, "Q2 adding the QSCD completes QES" as *u8, es_eidas_tier(p, sig), ES_QES) 102 zz_ck(cnt, "Q2a QES ALONE is wet-ink equivalent (Art 25(2))" as *u8, es_handwritten_equivalent(p, sig), 1) 103 es_tier_label(es_eidas_tier(p, sig), lbl) 104 zz_cks(cnt, "Q2b label" as *u8, lbl, "QES" as *u8) 105 106 zz_ck(cnt, "R1 QES tier but NO US elements -> not ready to rely on" as *u8, es_ready(p, sig), 0) 107 es_set(p, sig, "intent" as *u8, "yes" as *u8) 108 es_set(p, sig, "consent" as *u8, "yes" as *u8) 109 es_set(p, sig, "association" as *u8, "yes" as *u8) 110 es_set(p, sig, "retention" as *u8, "yes" as *u8) 111 zz_ck(cnt, "R2 US statutory test now passes" as *u8, es_esign_valid(p, sig), 1) 112 zz_ck(cnt, "R2a but the audit record is still incomplete -> NOT ready" as *u8, es_ready(p, sig), 0) 113 zz_ck(cnt, "R2b six audit facts still missing" as *u8, es_audit_missing(p, sig), 6) 114 115 zz_puts("nx_esign_eidas_gate: pass=" as *u8); zz_putn(cnt[0]) 116 zz_puts(" fail=" as *u8); zz_putn(cnt[1]); zz_puts("\n" as *u8) 117 if cnt[1] == 0 { 118 zz_puts("EIDAS nx_esign_eidas: VERDICT=GREEN (ladder exact; admissible never widened to wet-ink equivalence)\n" as *u8) 119 return 0 120 } 121 zz_puts("EIDAS nx_esign_eidas: VERDICT=RED\n" as *u8) 122 return 1 123}