// 独立自检:与 `moon test` 等价的固定语料校验。
//
// Windows 下 `moon test` 可能因嵌套进程限制失败(os error 5),
// 因此这里提供一条不依赖测试框架的校验路径,CI 与本地共用同一份断言。
///|
fn check_hex(name : String, actual : Bytes, expected : String) -> String? {
let got = @hex.encode(actual)
if got == expected {
None
} else {
Some("\{name}: expected \{expected}, got \{got}")
}
}
///|
pub fn run_selftest() -> Array[String] {
let failures : Array[String] = []
let cases : Array[(String, Bytes, String)] = [
(
"sha256/empty", b"", "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
),
(
"sha256/abc", b"abc", "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad",
),
(
"sha256/two-block", b"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
"248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1",
),
]
for case in cases {
match check_hex(case.0, sha256(case.1), case.2) {
Some(message) => failures.push(message)
None => ()
}
}
// 跨实现向量:由 Node/OpenSSL 生成密钥并签名,本项目只负责验签
let node_spki = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArtwFJjPn9RgRSAFlZlnT" +
"TNq3VZb5Bg4BXTTrAQ2m8cHz+ygndf9nfLLXRAxiWrGm/sxbYov2Nr7cs9bmrny58Jw0U773rtWrZ" +
"fKNlpWHA4r/gizPaaULMUSqk9d5Zj9pkWAwdAVQD+A8QH2BM/SQ6sf4OhVKE/q6PCHKwMxSoJc6qd4" +
"50XqwT44Itj3fzkGPFQe/BSv+8yKxqnEsc2cLXf31zJjPsftK3O++4UXjYHL7Mhs7m7S8JaIPUrRi4" +
"gf9l0vP/eYc22QYPWZQFQcRNud1ZiYYru3xi0SMvQxUUH59ikE/bSJhm1YZt9QDuhX3nn02wsAeyDF" +
"vycaCj0niuQIDAQAB"
let node_sig = "i57bUIntstS+H7+k6zMctOeeIri3KA1gvj+7zuhj+npGlkSiED0nnDnjg4GcCGzAaG7nrj" +
"BTLhT5O04EWgyqhupI7gNSNLVxqii1XHz1BIsjCWzxAST0I901l5QtsEVF8Lo2PGK8xLv7Fs5OX41l/" +
"kV90F94oPf609C2M5fNr+P8fvI/N2hvQO3zNX1KXAPWLxSuh7UwhtD1a3hgFP3sJUCLNmN2qwHmCf0w" +
"JQ94mgrqf5Ny+/7OwwPA0wsGruWaLV8WSzTpHYB3/5oohe90PWUSKk9kiuF1fw/DBJ3sfcTG8fYg6rI" +
"+ftr/owAspdQIozJye0e3rjHdoHlP4iDgFw=="
if !rsa_verify_sha256_base64(node_spki, b"mailauth-rsa-vector", node_sig) {
failures.push("rsa/openssl-vector: valid signature was rejected")
}
if rsa_verify_sha256_base64(node_spki, b"mailauth-rsa-vectoX", node_sig) {
failures.push("rsa/tamper: modified message was accepted")
}
// DKIM 跨实现语料:Node/OpenSSL 签名
let zone = Zone::from_text(dkim_zone_text)
let good = verify_dkim_all(
zone,
parse_message(@utf8.encode(dkim_relaxed_eml)),
now=1800000000,
)
if good.length() != 1 {
failures.push("dkim/relaxed: expected 1 signature, got \{good.length()}")
} else if good[0].status != Pass {
failures.push(
"dkim/relaxed: expected pass, got \{good[0].status.label()}: \{good[0].reason}",
)
}
let bad_body = verify_dkim_all(
zone,
parse_message(@utf8.encode(dkim_tampered_body_eml)),
now=1800000000,
)
if bad_body.length() != 1 || bad_body[0].status != Fail {
failures.push("dkim/tampered-body: tampered body was not rejected")
}
let bad_header = verify_dkim_all(
zone,
parse_message(@utf8.encode(dkim_tampered_header_eml)),
now=1800000000,
)
if bad_header.length() != 1 || bad_header[0].status != Fail {
failures.push("dkim/tampered-header: tampered header was not rejected")
}
for failure in run_spf_tests() {
failures.push(failure)
}
for failure in run_dmarc_tests() {
failures.push(failure)
}
failures
}
///|
fn run_spf_tests() -> Array[String] {
let failures : Array[String] = []
let zone_text = "example.com TXT v=spf1 ip4:192.0.2.0/24 -all\n" +
"inc.example.com TXT v=spf1 include:_spf.inc.example.com -all\n" +
"_spf.inc.example.com TXT v=spf1 ip4:203.0.113.0/24 -all\n" +
"macro.example.com TXT v=spf1 exists:%{i}.macro.example.com -all\n" +
"203.0.113.9.macro.example.com A 127.0.0.1\n" +
"v6.example.com TXT v=spf1 ip6:2001:db8::/32 -all\n" +
"void.example.com TXT v=spf1 exists:a.void.example.net exists:b.void.example.net exists:c.void.example.net -all\n"
let zone = Zone::from_text(zone_text)
let hit = evaluate_spf(zone, "example.com", "192.0.2.5")
if hit.status != Pass {
failures.push("spf/ip4-match: expected pass, got \{hit.status.label()}")
}
let miss = evaluate_spf(zone, "example.com", "198.51.100.1")
if miss.status != Fail {
failures.push("spf/all-fail: expected fail, got \{miss.status.label()}")
}
let included = evaluate_spf(zone, "inc.example.com", "203.0.113.9")
if included.status != Pass {
failures.push(
"spf/include: expected pass, got \{included.status.label()}: \{included.reason}",
)
}
let macro = evaluate_spf(zone, "macro.example.com", "203.0.113.9")
if macro.status != Pass {
failures.push(
"spf/macro-exists: expected pass, got \{macro.status.label()}: \{macro.reason}",
)
}
let v6 = evaluate_spf(zone, "v6.example.com", "2001:db8::1")
if v6.status != Pass {
failures.push("spf/ip6: expected pass, got \{v6.status.label()}")
}
let void_case = evaluate_spf(zone, "void.example.com", "192.0.2.5")
if void_case.status != PermError {
failures.push(
"spf/void-limit: expected permerror, got \{void_case.status.label()}",
)
}
// 10 次 DNS 查询上限
let lookup_zone = StringBuilder()
lookup_zone.write_string("too-many.example.com TXT v=spf1")
for i in 0..<11 {
lookup_zone.write_string(" include:i\{i}.too-many.example.net")
}
lookup_zone.write_string(" -all\n")
for i in 0..<11 {
lookup_zone.write_string("i\{i}.too-many.example.net TXT v=spf1 -all\n")
}
let limit_zone = Zone::from_text(lookup_zone.to_string())
let limited = evaluate_spf(limit_zone, "too-many.example.com", "192.0.2.5")
if limited.status != PermError {
failures.push(
"spf/lookup-limit: expected permerror, got \{limited.status.label()}",
)
}
failures
}
///|
fn run_dmarc_tests() -> Array[String] {
let failures : Array[String] = []
let zone_text = "_dmarc.example.com TXT v=DMARC1; p=reject; sp=quarantine\n" +
"_dmarc.strict.example.com TXT v=DMARC1; p=reject; adkim=s\n" +
"_dmarc.pct.example.com TXT v=DMARC1; p=reject; pct=0\n"
let zone = Zone::from_text(zone_text)
let passing : DkimResult = {
domain: "mail.example.com",
selector: "test",
algorithm: "rsa-sha256",
status: Pass,
reason: "signature verified",
evidence: [],
}
let relaxed = evaluate_dmarc(zone, "example.com", [passing], None, sample=0)
if relaxed.status != Pass || !relaxed.dkim_aligned {
failures.push("dmarc/relaxed-align: expected pass with aligned dkim")
}
// strict 对齐:子域签名不应通过
let strict = evaluate_dmarc(
zone,
"strict.example.com",
[passing],
None,
sample=0,
)
if strict.status != Fail || strict.disposition != "reject" {
failures.push("dmarc/strict-align: expected fail with reject disposition")
}
// pct=0:策略命中但采样外,处置降为 none
let sampled = evaluate_dmarc(zone, "pct.example.com", [], None, sample=0)
if sampled.status != Fail || sampled.disposition != "none" {
failures.push("dmarc/pct-zero: expected fail with none disposition")
}
// 子域策略
let sub = evaluate_dmarc(zone, "sub.example.com", [], None, sample=0)
if sub.disposition != "quarantine" {
failures.push(
"dmarc/subdomain-policy: expected quarantine, got \{sub.disposition}",
)
}
failures
}
///|
pub fn selftest_case_count() -> Int {
19
}