mirror of
https://github.com/rustfs/rustfs.git
synced 2026-09-07 20:46:11 +00:00
fix(connect): preserve signature precedence across chain parsing
This commit is contained in:
@@ -286,7 +286,7 @@ struct DocumentSignature {
|
|||||||
struct ChallengeRouting {
|
struct ChallengeRouting {
|
||||||
connect_key_id: String,
|
connect_key_id: String,
|
||||||
issued_at: String,
|
issued_at: String,
|
||||||
trust_chain: Vec<SignedDocument>,
|
trust_chain: Vec<serde_json::Value>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
@@ -382,26 +382,33 @@ impl OfflineEnrollment {
|
|||||||
let issued_at = parse_timestamp(&routing.issued_at)?;
|
let issued_at = parse_timestamp(&routing.issued_at)?;
|
||||||
|
|
||||||
// The frozen decision order classifies the top-level signature before
|
// The frozen decision order classifies the top-level signature before
|
||||||
// parsing any trust-link routing fields. Otherwise a malformed first
|
// parsing any trust-link envelope or routing fields. Otherwise a
|
||||||
// link could mask a malformed artifact signature with DOCUMENT_MALFORMED.
|
// malformed link could mask a malformed artifact signature with
|
||||||
|
// DOCUMENT_MALFORMED.
|
||||||
let signature = decode_signature(&envelope.signature)?;
|
let signature = decode_signature(&envelope.signature)?;
|
||||||
|
|
||||||
let first = routing.trust_chain.first().ok_or(EnrollmentError::MalformedDocument)?;
|
let first = routing.trust_chain.first().ok_or(EnrollmentError::MalformedDocument)?;
|
||||||
let first_bytes = decode_document_bytes(&first.bytes)?;
|
let first_bytes = first
|
||||||
|
.get("bytes")
|
||||||
|
.and_then(serde_json::Value::as_str)
|
||||||
|
.ok_or(EnrollmentError::MalformedDocument)
|
||||||
|
.and_then(decode_document_bytes)?;
|
||||||
let first_routing: TrustLinkRouting =
|
let first_routing: TrustLinkRouting =
|
||||||
serde_json::from_slice(&first_bytes).map_err(|_| EnrollmentError::MalformedDocument)?;
|
serde_json::from_slice(&first_bytes).map_err(|_| EnrollmentError::MalformedDocument)?;
|
||||||
if !is_key_id(&first_routing.issuer_key_id) {
|
if !is_key_id(&first_routing.issuer_key_id) {
|
||||||
return Err(EnrollmentError::MalformedDocument);
|
return Err(EnrollmentError::MalformedDocument);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The pinned-root decision precedes full chain-envelope validation.
|
||||||
|
if first_routing.issuer_key_id != root.key_id {
|
||||||
|
return Err(EnrollmentError::EnrollmentRootUnknown);
|
||||||
|
}
|
||||||
|
let trust_chain: Vec<SignedDocument> = serde_json::from_value(serde_json::Value::Array(routing.trust_chain))
|
||||||
|
.map_err(|_| EnrollmentError::TrustChainInvalid)?;
|
||||||
|
|
||||||
// Steps 3 to 5.
|
// Steps 3 to 5.
|
||||||
let connect_key = verify_trust_chain(
|
let connect_key =
|
||||||
&routing.trust_chain,
|
verify_trust_chain(&trust_chain, &routing.connect_key_id, &first_routing.issuer_key_id, issued_at, root)?;
|
||||||
&routing.connect_key_id,
|
|
||||||
&first_routing.issuer_key_id,
|
|
||||||
issued_at,
|
|
||||||
root,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
// Step 6. The detached signature must name the same chained key whose
|
// Step 6. The detached signature must name the same chained key whose
|
||||||
// public key verifies it. A different well-formed key id is a signature
|
// public key verifies it. A different well-formed key id is a signature
|
||||||
|
|||||||
@@ -594,6 +594,25 @@ fn malformed_top_level_signature_precedes_malformed_first_link_routing() {
|
|||||||
assert_eq!(error.reason(), "SIGNATURE_MALFORMED");
|
assert_eq!(error.reason(), "SIGNATURE_MALFORMED");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn malformed_top_level_signature_precedes_malformed_second_link_envelope() {
|
||||||
|
let source = accept_vector_named("challenge signed by a chained signing key under the pinned root");
|
||||||
|
let now = unix(field(&source, "evaluationTime"));
|
||||||
|
let mut challenge_envelope = source["document"].clone();
|
||||||
|
challenge_envelope["signature"]["algorithm"] = Value::String("ES384".to_string());
|
||||||
|
|
||||||
|
let mut challenge = signed_document(&challenge_envelope);
|
||||||
|
challenge["trustChain"].as_array_mut().expect("challenge carries a chain")[1]
|
||||||
|
.as_object_mut()
|
||||||
|
.expect("trust link envelope is an object")
|
||||||
|
.remove("signature");
|
||||||
|
challenge_envelope["bytes"] = Value::String(encoded_document(&challenge));
|
||||||
|
|
||||||
|
let error = OfflineEnrollment::verify_challenge(&envelope(&challenge_envelope), now)
|
||||||
|
.expect_err("a malformed top-level signature and second-link envelope must not verify");
|
||||||
|
assert_eq!(error.reason(), "SIGNATURE_MALFORMED");
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn unpinned_root_precedes_a_malformed_chain_shape() {
|
fn unpinned_root_precedes_a_malformed_chain_shape() {
|
||||||
let source = accept_vector_named("challenge signed by a chained signing key under the pinned root");
|
let source = accept_vector_named("challenge signed by a chained signing key under the pinned root");
|
||||||
|
|||||||
Reference in New Issue
Block a user