///|
/// ASCII host presentation required by the reused MoonZoneGuard association API.
pub fn Name::host_text(self : Name) -> Result[String, DnsError] {
let out = StringBuilder()
if self.labels.is_empty() {
return Ok(".")
}
for label in self.labels {
for b in label {
let n = b.to_int()
if !((n >= 97 && n <= 122) || (n >= 48 && n <= 57) || n == 45 || n == 95) {
return Err(Unsupported("DS association requires ASCII host labels"))
}
out.write_char(n.unsafe_to_char())
}
out.write_string(".")
}
Ok(out.to_string())
}
///|
fn key_fingerprint(
owner : Name,
key : Dnskey,
) -> Result[@zone.DnskeyFingerprint, DnsError] {
let name = match owner.host_text() {
Ok(n) => n
Err(e) => return Err(e)
}
let rr : @zone.ResourceRecord = {
owner: name,
origin: ".",
ttl: 0,
class_name: "IN",
record_type: "DNSKEY",
rdata: [
key.flags.to_string(),
"3",
key.algorithm.to_string(),
@base64.encode(key.data[4:]),
],
line: 0,
column: 0,
}
match @zone.dnskey_ds_sha256(rr) {
Ok(f) => Ok(f)
Err(e) => Err(Unsupported("association dependency: " + e))
}
}
///|
pub fn Dnskey::key_tag(self : Dnskey, owner : Name) -> Result[Int32, DnsError] {
match key_fingerprint(owner, self) {
Ok(f) => Ok(f.key_tag)
Err(e) => Err(e)
}
}
///|
/// SHA256 DS is delegated to the established ecosystem implementation.
/// Other digest types are reported unsupported, never silently downgraded.
pub fn Ds::matches(
self : Ds,
owner : Name,
key : Dnskey,
) -> Result[Bool, DnsError] {
if self.digest_type != 2 {
return Err(Unsupported("only DS SHA256 is enabled"))
}
if self.algorithm != key.algorithm {
return Ok(false)
}
match key_fingerprint(owner, key) {
Err(e) => Err(e)
Ok(f) => {
if f.key_tag != self.key_tag {
return Ok(false)
}
Ok(hex(self.digest) == f.sha256_digest.to_lower())
}
}
}
///|
fn hex(data : Bytes) -> String {
let out = StringBuilder()
let alphabet = "0123456789abcdef"
for b in data {
out.write_char(alphabet[b.to_int() >> 4].to_int().unsafe_to_char())
out.write_char(alphabet[b.to_int() & 15].to_int().unsafe_to_char())
}
out.to_string()
}