{"record":{"id":"99f7ced811fc7a0c","repo":"jdx/mise","slug":"signature-does-not-match-any-trusted-public-key","errorCode":null,"errorMessage":"signature does not match any trusted public key","messagePattern":"signature does not match any trusted public key","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"src/gpg.rs","lineNumber":63,"sourceCode":"        bail!(\"no signature found to verify\");\n    }\n\n    // Fast path: only try keys whose id/fingerprint matches the signature's issuer, so the signed\n    // content is hashed at most once in the common case.\n    for sig in &signatures {\n        if verify_against_keys(sig, &keys, &open_data, true)? {\n            return Ok(());\n        }\n    }\n    // Fallback: try every trusted key, but only for signatures that carried no usable issuer\n    // hint. A signature that named an issuer we don't trust is genuinely unverifiable, so skip it\n    // rather than re-hashing the (potentially large) content against every key.\n    for sig in signatures.iter().filter(|sig| !has_issuer(&sig.signature)) {\n        if verify_against_keys(sig, &keys, &open_data, false)? {\n            return Ok(());\n        }\n    }\n    bail!(\"signature does not match any trusted public key\");\n}\n\nfn verify_against_keys<R, F>(\n    sig: &DetachedSignature,\n    keys: &[SignedPublicKey],\n    open_data: &F,\n    require_issuer_match: bool,\n) -> Result<bool>\nwhere\n    R: Read,\n    F: Fn() -> Result<R>,\n{\n    for key in keys {\n        if (!require_issuer_match\n            || issuer_matches(&sig.signature, &key.fingerprint(), &key.legacy_key_id()))\n            && try_verify(sig, key, open_data)?\n        {\n            return Ok(true);","sourceCodeStart":45,"sourceCodeEnd":81,"githubUrl":"https://github.com/jdx/mise/blob/afd2eddd3a50c16190efc1c7e94404b48f72af57/src/gpg.rs#L45-L81","documentation":"verify_detached tried every parsed signature against every trusted public key (fast path for signatures with an issuer subpacket, then the full loop for the rest) and none verified. This means the artifact's signature does not cryptographically match any of the configured trusted keys.","triggerScenarios":"verify_node/verify_swift/verify_swift_bytes called with a signature signed by a key not in public_keys_asc, a corrupted/tampered artifact, or mismatched signature/archive pairing.","commonSituations":"Upstream rotated signing keys (e.g. new Node/Swift release signed with a fresh key) while local trusted key list is stale; MITM or corrupted mirror served a tampered archive; downloaded the .sig from a different release version than the archive; revoked or outdated keys in config.","solutions":["Update the trusted public keys to the project's current official signing keys (fetch new keys from the upstream release/keyserver)","Re-download both the archive and its signature from the official source to rule out a corrupted or mismatched pair","Confirm the archive and signature come from the exact same release/version","If the artifact is trusted and genuinely signed by a new key, add that key to the trusted key list; if not, treat it as tampered","Clear any cached partial downloads/mirrors and retry"],"exampleFix":"// before\nlet keys = read(\"node-v16-keys.asc\")?; // stale: new release signed with rotated key\nverify_node(&archive, sig, keys)?;\n// after\nlet keys = fetch_current_keys(\"node\")?; // includes rotated signing key\nverify_node(&archive, sig, keys)?;","handlingStrategy":"try-catch","validationCode":"// ensure keys include the current upstream signing key fingerprints\nlet fingerprints: Vec<_> = parse_public_keys(&keys)?.iter().map(|k| hex::encode(k.key_id())).collect();\neprintln!(\"trusted keys: {:?}\", fingerprints);","typeGuard":null,"tryCatchPattern":"match verify_node(&archive, sig, keys) {\n    Ok(()) => println!(\"signature verified\"),\n    Err(e) if e.to_string().contains(\"does not match any trusted public key\") => {\n        eprintln!(\"artifact untrusted: refresh official keys or suspect tampering\");\n        std::process::exit(1); // fail closed, never proceed unverified\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Keep trusted key lists updated when upstream rotates signing keys","Always re-download archive and signature from the same official release","Treat this error as a potential supply-chain red flag; fail closed","Compare the failing artifact's digest with the official checksum file as a cross-check"],"tags":["gpg","signature","verification","security"],"backgroundTag":"checksum-mismatch","analyzedSha":"afd2eddd3a50c16190efc1c7e94404b48f72af57","analyzedAt":"2026-09-09T01:38:25.179Z","contentChangedAt":"2026-09-09T01:38:25.179Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}