///|
fn compute_supported_digest(
algorithm : String,
body : Bytes,
) -> Bytes? raise DigestFieldError {
match algorithm {
"sha-256" => Some(sha256(body))
"sha-512" => Some(sha512(body))
_ => None
}
}
///|
/// Verify a parsed Content-Digest or Repr-Digest value against body bytes.
pub fn verify_digest(
target : IntegrityTarget,
field : DigestField,
body : Bytes,
policy : VerificationPolicy,
) -> Verification {
if body.length() > policy.max_body_bytes {
return {
target,
decision: BodyTooLarge,
algorithm: "",
code: "BODY_LIMIT",
checked: 0,
ignored: 0,
}
}
if field.members.length() > policy.max_field_members {
return {
target,
decision: PolicyBlocked,
algorithm: "",
code: "MEMBER_LIMIT",
checked: 0,
ignored: 0,
}
}
let mut checked = 0
let mut ignored = 0
let mut matched = 0
let mut last_algorithm = ""
for item in field.members {
let algorithm = ascii_lower(item.algorithm)
match algorithm_status(algorithm) {
Deprecated if policy.reject_deprecated =>
return {
target,
decision: PolicyBlocked,
algorithm,
code: "DEPRECATED_ALGORITHM",
checked,
ignored,
}
_ => ()
}
if !string_in(policy.allowed_algorithms, algorithm) {
ignored += 1
continue
}
let actual = compute_supported_digest(algorithm, body) catch {
_ =>
return {
target,
decision: InvalidField,
algorithm,
code: "DIGEST_FAILURE",
checked,
ignored,
}
}
guard actual is Some(actual_digest) else {
ignored += 1
continue
}
checked += 1
last_algorithm = algorithm
if bytes_equal_constant_time(actual_digest, item.value) {
matched += 1
} else if policy.require_all_supported {
return {
target,
decision: Mismatch,
algorithm,
code: "DIGEST_MISMATCH",
checked,
ignored,
}
}
}
if checked == 0 {
{
target,
decision: NoSupportedAlgorithm,
algorithm: "",
code: "NO_SUPPORTED_ALGORITHM",
checked,
ignored,
}
} else if matched > 0 {
{
target,
decision: Verified,
algorithm: last_algorithm,
code: "OK",
checked,
ignored,
}
} else {
{
target,
decision: Mismatch,
algorithm: last_algorithm,
code: "DIGEST_MISMATCH",
checked,
ignored,
}
}
}
///|
/// Parse and verify a wire-format field value.
pub fn verify_digest_field(
target : IntegrityTarget,
field_value : String,
body : Bytes,
policy : VerificationPolicy,
) -> Verification {
let field = parse_digest_field(field_value) catch {
_ =>
return {
target,
decision: InvalidField,
algorithm: "",
code: "INVALID_FIELD",
checked: 0,
ignored: 0,
}
}
verify_digest(target, field, body, policy)
}