Skip to content

Relax measurements#80

Merged
labbott merged 2 commits into
mainfrom
relax_measurements
Jul 16, 2025
Merged

Relax measurements#80
labbott merged 2 commits into
mainfrom
relax_measurements

Conversation

@labbott

@labbott labbott commented Jul 9, 2025

Copy link
Copy Markdown
Contributor

No description provided.

@labbott
labbott requested review from andrewjstone and flihp July 9, 2025 18:39

@andrewjstone andrewjstone left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good. However, I think it's headed slightly in the wrong direction.

@flihp's PR for #75 ends up returning the PlatformId with a method on Stream. I think it would be better if we could do the same thing here, and add a bool to Stream when constructed indicating if measurement verification failed. Then we'd add a bool method accessor to Stream. This logically separates the use of PlaftormId and verifications failed at the API level, and allows example code and the like to not even bother looking at whether measurements verified or not. This is usefu,l because eventually, we'll always fail the connection if measurements fail to verify, and we won't have to change the code that isn't worrying about that. I also just prefer the logical separation which helpfully prevents bikeshedding about type names.

Comment thread tls/src/keys.rs Outdated

/// The result of measurement appraisal
#[derive(Clone, Debug, Deserialize)]
pub enum SprocketsResult {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think a better name would be MeasurementStatus, and then the variants could be Verified and Unverified.

I find it confusing when a type includes Result in the name even though it is not a Result.

Comment thread tls/src/keys.rs Outdated
MeasurementsUnverified(PlatformId),
}

impl SprocketsResult {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Presumably, the purpose of this type is to allow us to check inside omicron whether measurements passed or succeeded. In that case, maybe we should add a method here for ergonomics. Something like:

pub fn measurements_verified() -> bool {
    matches!(self, SprocketsResult::MeasurementsVerified(_))
}

@labbott

labbott commented Jul 10, 2025

Copy link
Copy Markdown
Contributor Author

This looks good. However, I think it's headed slightly in the wrong direction.

@flihp's PR for #75 ends up returning the PlatformId with a method on Stream. I think it would be better if we could do the same thing here, and add a bool to Stream when constructed indicating if measurement verification failed. Then we'd add a bool method accessor to Stream. This logically separates the use of PlaftormId and verifications failed at the API level, and allows example code and the like to not even bother looking at whether measurements verified or not. This is usefu,l because eventually, we'll always fail the connection if measurements fail to verify, and we won't have to change the code that isn't worrying about that. I also just prefer the logical separation which helpfully prevents bikeshedding about type names.

Ah I hadn't seen that PR! I like that approach.

@labbott
labbott force-pushed the relax_measurements branch 2 times, most recently from 21ee83f to 6059adc Compare July 14, 2025 19:13
Comment thread tls/src/lib.rs Outdated
Comment on lines +150 to +156
pub fn peer_platform_id_unchecked(&self) -> &PlatformId {
&self.platform_id
}

pub fn peer_platform_id(&self) -> Option<&PlatformId> {
if self.corpus_appraisal_success {
Some(&self.platform_id)
} else {
None
}
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will admit this is a little goofy but I wanted to make it difficult to use the unappraised version without being intentional.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Won't this practically prevent us from operating with the appraisal turned off for initial trust quorum? Or do we expect that we'll turn it on always by the time TQ is in production?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My initial thought was to always use peer_platform_id_unchecked for now. I think by the time we want to deploy TQ we should be requiring the appraisal. We could return (PlatformId, bool) indicating the appraisal status but that also allows you to do let (id, _) = stream.peer_platform_id() to skip the appraisal status which maybe is fine? I kind of liked the enum return and requiring the caller to always check the appraisal status but I love my types a lot (maybe too much).

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it. I had a different expectation for how we'd always enable appraisal, which I believe is what's causing some confusion here. I figured that once we enabled appraisal, we'd do so by changing the sprockets code to return an error rather than making the caller check via looking at the platform id.

In essence I expected we'd back out this code and go back to returning an error, rather than changing the code at the call sites. Once we have some testing under our belt, the API should not allow a stream to be constructed with a failure ever again. This is how SPDM works, and how I always intended sprockets to work. It makes it foolproof to do the right thing, because you literally can't get a stream object if appraisal fails.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay I see your point. My thought was we could have some intermediate APIs but you're right we eventually want the current behavior.

Currently we require measurement appraisal against a valid corpus
set to be successful in order to connect via sprockets. This is
what we want in the ideal world. Unfortunately, we don't live in
the ideal world and we're still working out how the corpus should
be updated. Allow callers to determine how to handle measurement
failures should be handled. This still requires a full verifcation
of the certificate chain which should always work on hardware.
@labbott
labbott force-pushed the relax_measurements branch from 6059adc to 4109fa5 Compare July 15, 2025 19:17

@andrewjstone andrewjstone left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great @labbott. Thanks for bearing with me.

Comment thread tls/src/lib.rs Outdated
&self.platform_id
}

pub fn appraisal_status(&self) -> bool {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Maybe call this appraisal_success to be more clear that true is success and false is not.

Mock up what happens if we have a client who doesn't follow the
protocol and just sends messages
@labbott
labbott force-pushed the relax_measurements branch from 4109fa5 to 7c47daa Compare July 16, 2025 13:25
@labbott
labbott merged commit 7b63ccb into main Jul 16, 2025
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants