///|
/// Build RFC4034 signing input. IN class only; RRsets must be homogeneous.
pub fn signing_input(
records : Array[Record],
signature : Rrsig,
limits : Limits,
) -> Result[Bytes, DnsError] {
match limits.validate() {
Ok(_) => ()
Err(e) => return Err(e)
}
if records.is_empty() {
return Err(Malformed("empty RRset"))
}
if records.length() > limits.max_records {
return Err(ResourceLimit("RRset record count"))
}
let owner = records[0].owner
let rrtype = records[0].rrtype
if signature.covered != rrtype {
return Err(Bogus("RRSIG covers another type"))
}
if signature.original_ttl >= 0x80000000U {
return Err(Malformed("RRSIG original TTL"))
}
if !owner.is_subdomain(signature.signer) {
return Err(Bogus("signer does not contain owner"))
}
let signed_owner = match owner.signed_owner(signature.labels) {
Ok(n) => n
Err(e) => return Err(e)
}
if !signed_owner.is_subdomain(signature.signer) {
return Err(Bogus("wildcard outside signer zone"))
}
let mut total = signature.preamble().length()
for rr in records {
if rr.owner != owner || rr.rrtype != rrtype {
return Err(Malformed("mixed owners or types in RRset"))
}
total += signed_owner.wire().length() + 10 + rr.data.length()
if total > limits.max_signed_bytes {
return Err(ResourceLimit("RRset signing bytes"))
}
}
let canonical : Array[Bytes] = []
for rr in records {
match rr.canonical_rdata() {
Ok(b) => canonical.push(b)
Err(e) => return Err(e)
}
}
canonical.sort_by(bytes_compare)
let out : Array[Byte] = []
append_bytes(out, signature.preamble())
let mut previous : Bytes? = None
for data in canonical {
if previous == Some(data) {
continue
}
append_bytes(out, signed_owner.wire())
append16(out, rrtype)
append16(out, 1)
append32(out, signature.original_ttl)
append16(out, data.length())
append_bytes(out, data)
previous = Some(data)
}
Ok(Bytes::from_array(out))
}