diff --git a/CHANGELOG.md b/CHANGELOG.md index d64561c225..47c75f4c31 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ - Session-token authenticated requests to the FxA auth-server now use the typed-Bearer token scheme (`Authorization: Bearer fxs_`) instead of Hawk. This is an internal change with no consumer-facing API impact; production routes accept both schemes. See the [authentication schemes reference](https://mozilla.github.io/ecosystem-platform/reference/authentication-schemes). ([#PRNUM](https://github.com/mozilla/application-services/pull/PRNUM)) +### Remote Settings + +- Skip verification of signatures with unknown signature types ([Bug 2055147](https://bugzilla.mozilla.org/show_bug.cgi?id=2055147)) + [Full Changelog](In progress) ## ✨ What's New ✨ diff --git a/components/remote_settings/src/client.rs b/components/remote_settings/src/client.rs index b951d45c0a..89ec6912a3 100644 --- a/components/remote_settings/src/client.rs +++ b/components/remote_settings/src/client.rs @@ -456,6 +456,12 @@ impl RemoteSettingsClient { "No valid signatures found".into(), )); for signature in &metadata.signatures { + if signature.mode != "p384ecdsa" { + // We currently only support ECDSA P384. + // Change this once `rc_crypto` will support more types (eg. post-quantum algorithms). + continue; + } + let cert_chain_bytes = inner.api_client.fetch_cert(&signature.x5u)?; // The signer name is hard-coded. This would have to be modified in the very (very) @@ -799,6 +805,8 @@ pub struct CollectionSignature { pub signature: String, /// X.509 certificate chain Url (x5u) pub x5u: String, + /// Signature type + pub mode: String, } /// A parsed Remote Settings record. Records can contain arbitrary fields, so clients @@ -1375,6 +1383,7 @@ IKdcFKAt3fFrpyMhlfIKkLfmm0iDjmfmIXbDGBJw9SE= &[CollectionSignature { signature: VALID_SIGNATURE.to_string(), x5u: "http://mocked".into(), + mode: "p384ecdsa".into(), }], VALID_CERT_EPOCH_SECONDS, "main", @@ -1394,10 +1403,39 @@ IKdcFKAt3fFrpyMhlfIKkLfmm0iDjmfmIXbDGBJw9SE= CollectionSignature { signature: "invalid signature".to_string(), x5u: "http://mocked".into(), + mode: "p384ecdsa".into(), + }, + CollectionSignature { + signature: VALID_SIGNATURE.to_string(), + x5u: "http://mocked".into(), + mode: "p384ecdsa".into(), + }, + ], + VALID_CERT_EPOCH_SECONDS, + "main", + ) + .expect("Valid signature"); + Ok(()) + } + + #[test] + fn test_first_signature_has_unknown_type() -> Result<()> { + ensure_initialized(); + run_client_sync( + &[], + &[], + VALID_CERTIFICATE, + &[ + CollectionSignature { + signature: "unkown signature".to_string(), + x5u: "http://mocked".into(), + // Unknown signature type. + mode: "mldsa".into(), }, CollectionSignature { signature: VALID_SIGNATURE.to_string(), x5u: "http://mocked".into(), + mode: "p384ecdsa".into(), }, ], VALID_CERT_EPOCH_SECONDS, @@ -1423,6 +1461,7 @@ IKdcFKAt3fFrpyMhlfIKkLfmm0iDjmfmIXbDGBJw9SE= &[CollectionSignature { signature: VALID_SIGNATURE.to_string(), x5u: "http://mocked".into(), + mode: "p384ecdsa".into(), }], VALID_CERT_EPOCH_SECONDS, "main", @@ -1441,6 +1480,7 @@ IKdcFKAt3fFrpyMhlfIKkLfmm0iDjmfmIXbDGBJw9SE= &[CollectionSignature { signature: "invalid signature".to_string(), x5u: "http://mocked".into(), + mode: "p384ecdsa".into(), }], VALID_CERT_EPOCH_SECONDS, "main", @@ -1462,6 +1502,7 @@ IKdcFKAt3fFrpyMhlfIKkLfmm0iDjmfmIXbDGBJw9SE= &[CollectionSignature { signature: VALID_SIGNATURE.to_string(), x5u: "http://mocked".into(), + mode: "p384ecdsa".into(), }], VALID_CERT_EPOCH_SECONDS, "main", @@ -1489,6 +1530,7 @@ IKdcFKAt3fFrpyMhlfIKkLfmm0iDjmfmIXbDGBJw9SE= &[CollectionSignature { signature: VALID_SIGNATURE.to_string(), x5u: "http://mocked".into(), + mode: "p384ecdsa".into(), }], december_20_2024, "main", @@ -1522,6 +1564,7 @@ IKdcFKAt3fFrpyMhlfIKkLfmm0iDjmfmIXbDGBJw9SE= &[CollectionSignature { signature: VALID_SIGNATURE.to_string(), x5u: "http://mocked".into(), + mode: "p384ecdsa".into(), }], VALID_CERT_EPOCH_SECONDS, "main", @@ -1544,6 +1587,7 @@ IKdcFKAt3fFrpyMhlfIKkLfmm0iDjmfmIXbDGBJw9SE= &[CollectionSignature { signature: VALID_SIGNATURE.to_string(), x5u: "http://mocked".into(), + mode: "p384ecdsa".into(), }], VALID_CERT_EPOCH_SECONDS, "security-state", diff --git a/components/remote_settings/src/storage.rs b/components/remote_settings/src/storage.rs index 8677980c1d..0c5b56f70c 100644 --- a/components/remote_settings/src/storage.rs +++ b/components/remote_settings/src/storage.rs @@ -143,7 +143,8 @@ impl Storage { SELECT cm.bucket, json_extract(sig.value, '$.x5u') AS x5u, - json_extract(sig.value, '$.signature') AS signature + json_extract(sig.value, '$.signature') AS signature, + json_extract(sig.value, '$.mode') AS mode FROM collection_metadata AS cm LEFT JOIN json_each(cm.signatures) AS sig ON true WHERE cm.collection_url = ? @@ -161,8 +162,13 @@ impl Storage { } let x5u: Option = row.get(1)?; let signature: Option = row.get(2)?; - if let (Some(x5u), Some(signature)) = (x5u, signature) { - signatures.push(CollectionSignature { signature, x5u }); + let mode: Option = row.get(3)?; + if let (Some(x5u), Some(signature), Some(mode)) = (x5u, signature, mode) { + signatures.push(CollectionSignature { + signature, + x5u, + mode, + }); } } match bucket { @@ -1123,10 +1129,12 @@ mod tests { CollectionSignature { signature: "b64encodedsig".into(), x5u: "http://15u/".into(), + mode: "mldsa".into(), }, CollectionSignature { signature: "b64encodedsig2".into(), x5u: "http://15u2/".into(), + mode: "p384ecdsa".into(), }, ], }, @@ -1136,8 +1144,10 @@ mod tests { assert_eq!(metadata.signatures[0].signature, "b64encodedsig"); assert_eq!(metadata.signatures[0].x5u, "http://15u/"); + assert_eq!(metadata.signatures[0].mode, "mldsa"); assert_eq!(metadata.signatures[1].signature, "b64encodedsig2"); assert_eq!(metadata.signatures[1].x5u, "http://15u2/"); + assert_eq!(metadata.signatures[1].mode, "p384ecdsa"); Ok(()) } diff --git a/components/search/src/selector.rs b/components/search/src/selector.rs index 44927aae5d..c1c2b27970 100644 --- a/components/search/src/selector.rs +++ b/components/search/src/selector.rs @@ -917,6 +917,7 @@ mod tests { "signatures": [{ "x5u": "fake", "signature": "fake", + "mode": "fake", }], }, "timestamp": 1000, @@ -982,6 +983,7 @@ mod tests { "signatures": [{ "x5u": "fake", "signature": "fake", + "mode": "fake", }], }, "timestamp": 1000, @@ -1031,6 +1033,7 @@ mod tests { "signatures": [{ "x5u": "fake", "signature": "fake", + "mode": "fake", }], }, "timestamp": 1000, @@ -1055,6 +1058,7 @@ mod tests { "signatures": [{ "x5u": "fake", "signature": "fake", + "mode": "fake", }], }, "timestamp": 1000, @@ -1142,6 +1146,7 @@ mod tests { "signatures": [{ "x5u": "fake", "signature": "fake", + "mode": "fake", }], }, "timestamp": 1000,