-
Notifications
You must be signed in to change notification settings - Fork 5
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Hashes revocation #3
Conversation
912efed
to
84db7b4
Compare
023caa2
to
5dd5500
Compare
@@ -106,7 +106,7 @@ fn verify_signature<T: Signable>( | |||
None => continue, | |||
}; | |||
|
|||
match key.verify(T::SIGNED_BY_ROLE, &signed, &signature.signature) { | |||
match key.verify_payload(T::SIGNED_BY_ROLE, &signed, &signature.signature) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should check the revocation in most cases when decoding a signed payload. The two only cases where we can't realistically do that is (a) when decoding the public keys (as at that point we haven't decoded the revocation key) and (b) when decoding the revocation payload.
To have a hard-to-misuse interface, I'd add something like this:
pub trait NoRevocationsCheck {}
impl<T: Signable + NoRevocationsCheck> SignedPayload<T> {
pub fn get_verified_without_checking_revocations(...) -> ... {}
}
Then we can implement NoRevocationsCheck
just on the payloads where we have to avoid checking revocations.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@pietroalbini I did add the trait but I could not achieve everything, including calling verify_signature
standalone function. Given the deadline is cutting close, I created a ticket for 1.1 https://ferroussystems.clickup.com/t/8694mfy8z for myself.
ba103a7
to
fbf9cde
Compare
Reviewed-by: Ana Hobden <ana.hobden@ferrous-systems.com> Ticket: https://ferroussystems.clickup.com/t/86947z6fp
Reviewed-by: Pietro Albini <pietro.albini@ferrous-systems.com> Ticket: https://ferroussystems.clickup.com/t/86947z6fp
…cific. Reviewed-by: Pietro Albini <pietro.albini@ferrous-systems.com> Ticket: https://ferroussystems.clickup.com/t/86947z6fp
Reviewed-by: Pietro Albini <pietro.albini@ferrous-systems.com> Ticket: https://ferroussystems.clickup.com/t/86947z6fp
fbf9cde
to
7733b97
Compare
Reviewed-by: Pietro Albini <pietro.albini@ferrous-systems.com> Ticket: https://ferroussystems.clickup.com/t/86947z6fp
@@ -109,6 +109,7 @@ mod tests { | |||
// "localstack", a local replica of AWS services meant for testing. | |||
|
|||
#[test] | |||
#[ignore = "This test will be enabled in a later release."] | |||
fn test_roundtrip() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@pietroalbini I have no idea why yet, but this test is super flaky.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It just started breaking???
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this the failure you're referring to?
$ cargo test -p criticaltrust --features aws-kms roundtrip
Finished `test` profile [unoptimized + debuginfo] target(s) in 0.08s
Running unittests src/lib.rs (target/debug/deps/criticaltrust-6080a18de3f40575)
running 1 test
test keys::pair_aws_kms::tests::test_roundtrip ... FAILED
failures:
---- keys::pair_aws_kms::tests::test_roundtrip stdout ----
running "docker" "pull" "localstack/localstack:2.2.0"
finished running "docker" "pull" "localstack/localstack:2.2.0"
running "docker" "create" "--name" "criticaltrust-localstack-3090418271525868829" "-p" "4566" "localstack/localstack:2.2.0"
finished running "docker" "create" "--name" "criticaltrust-localstack-3090418271525868829" "-p" "4566" "localstack/localstack:2.2.0"
running "docker" "start" "criticaltrust-localstack-3090418271525868829"
finished running "docker" "start" "criticaltrust-localstack-3090418271525868829"
running "docker" "port" "criticaltrust-localstack-3090418271525868829" "4566/tcp"
finished running "docker" "port" "criticaltrust-localstack-3090418271525868829" "4566/tcp"
thread 'keys::pair_aws_kms::tests::test_roundtrip' panicked at crates/criticaltrust/src/keys/pair_aws_kms.rs:214:18:
failed to create kms key: DispatchFailure(DispatchFailure { source: ConnectorError { kind: Io, source: hyper::Error(Canceled, hyper::Error(IncompleteMessage)), connection: Unknown } })
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
running "docker" "stop" "criticaltrust-localstack-3090418271525868829" "-t" "10"
finished running "docker" "stop" "criticaltrust-localstack-3090418271525868829" "-t" "10"
running "docker" "rm" "criticaltrust-localstack-3090418271525868829"
finished running "docker" "rm" "criticaltrust-localstack-3090418271525868829"
failures:
keys::pair_aws_kms::tests::test_roundtrip
test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 88 filtered out; finished in 4.19s
error: test failed, to rerun pass `-p criticaltrust --lib`
This seems to break on main
too. :(
…tory for EphemeralKeyPair Reviewed-by: Pietro Albini <pietro.albini@ferrous-systems.com> Ticket: https://ferroussystems.clickup.com/t/86947z6fp
Reviewed-by: Pietro Albini <pietro.albini@ferrous-systems.com> Ticket: https://ferroussystems.clickup.com/t/86947z6fp
Checking for payload's SHA256 is the requirement, not the base64 of the signature. Reviewed-by: Ana Hobden <ana.hobden@ferrous-systems.com> Ticket: https://ferroussystems.clickup.com/t/86947z6fp
use serde::{Deserialize, Serialize}; | ||
use time::OffsetDateTime; | ||
|
||
/// Expiration of `RevocationInfo` should be at least this many number of days out from now. | ||
const MAX_REVOCATION_INFO_EXPIRATION_DURATION: i64 = 90; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this ok with the current expiration of the payload of 2024-10-01?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Days from today to Oct 1, 2024 are about 130. So, this seems fine to me.
/// Make sure verification of `PublicKey` type does no checks for revocations. | ||
/// | ||
/// This is done because when decoding the public keys, we haven't yet decoded the revocation key. | ||
impl NoRevocationCheck for SignedPayload<PublicKey> {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
impl NoRevocationCheck for SignedPayload<PublicKey> {} | |
impl NoRevocationCheck for PublicKey {} |
If we implement it for SignedPayload<PublicKey>
:
- The trait bound of
impl<T: NoRevocationCheck> SignedPayload<T>
will not work. - It won't be possible to implement
NoRevocationCheck
outside CriticalTrust due to the orphan rule (as bothNoRevocationCheck
andSignedPayload
are defined in CriticalTrust).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since, the get_verified
method is on SignedPayload
, you won't be able to restrict that method if you do impl NoRevocationCheck for PublicKey {}
. IIUC, that was your idea, to make this API more stringent so harder to abuse. There is no get_verified
on PublicKey
, as an example.
I actually started with what you suggested and learned that, that does not work. as in one could still call .get_verified
on PublicKey
.
/// Make sure verification of `RevocationInfo` type does no checks for revocations. | ||
/// | ||
/// If we did, then this would be a circular logic. We say no to such logic. | ||
impl NoRevocationCheck for SignedPayload<RevocationInfo> {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as the other NoRevocationCheck
impl.
@@ -106,7 +133,11 @@ fn verify_signature<T: Signable>( | |||
None => continue, | |||
}; | |||
|
|||
match key.verify(T::SIGNED_BY_ROLE, &signed, &signature.signature) { | |||
match key.verify_without_checking_revocations( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We still need to make sure this verifies revocations if called by get_verified
or into_verified
.
revoked_signatures: SignedPayload::new(&RevocationInfo { | ||
revoked_content_sha256: Vec::new(), | ||
expires_at: OffsetDateTime::now_utc(), | ||
}) | ||
.unwrap(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not correct: it expires immediately, and it's not signed. It will cause CriticalUp tests to fail.
let key = generate(KeyRole::Root, None); | ||
let signature = key.sign(&SAMPLE_REVOKED_PAYLOAD).unwrap(); | ||
|
||
let payload_sha256 = String::from_utf8(SAMPLE_REVOKED_PAYLOAD.as_bytes().to_vec()).unwrap(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not the sha256?
let payload_sha256 = String::from_utf8(SAMPLE_REVOKED_PAYLOAD.as_bytes().to_vec()).unwrap(); | ||
let signed_revocation_info = SignedPayload::new(&RevocationInfo { | ||
revoked_content_sha256: vec![payload_sha256], | ||
expires_at: days_diff(10000).unwrap(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This test is failing due to the expires_at
date, not due to the content being revoked.
let verified_revoked_content = signed_revocation_info.get_verified(self)?; | ||
let expiration_in_days = | ||
(verified_revoked_content.expires_at - OffsetDateTime::now_utc()).whole_days(); | ||
if expiration_in_days < MAX_REVOCATION_INFO_EXPIRATION_DURATION { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am a bit confused by this check. The check doesn't seem to actually check the revocation date, only that the period between the expiration and now is less than 90 days.
I would make two separate checks:
expires_at < now() + 90 days
expires_at > now()
A new PR will be opened at a later stage using reviews from this PR. |
Adds the ability to check for revoked content which are served as signed hashes.
Ticket: https://ferroussystems.clickup.com/t/86947z6fp