Skip to content
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

Handle PCK certificates #1068

Merged
merged 44 commits into from
Oct 28, 2024
Merged

Handle PCK certificates #1068

merged 44 commits into from
Oct 28, 2024

Conversation

ameba23
Copy link
Contributor

@ameba23 ameba23 commented Sep 25, 2024

This is a followup to #1051 in that it adds a way of parsing and validating the PCK certificates, as well as intermediary 'provider' certificates which sign the PCK cert and are in turn signed by intel's root certificate authority public key, which is hard coded. If all goes well the PCK public key is extracted from the certificate to be used in the ServerInfo struct.

This parsing / validating needs to happen when a validator initially joins, or when they change their endpoint (IP address).

@junkicide from poetic has also provided us with a function to validate a certificate chain of arbitrary length - im not sure whether in practice we can expect that there will be more than one intermediary provider beween the PCK cert and the root CA.

Related issue: #982

@ameba23 ameba23 marked this pull request as draft September 25, 2024 08:34
@ameba23 ameba23 self-assigned this Sep 26, 2024
@ameba23
Copy link
Contributor Author

ameba23 commented Oct 1, 2024

@HCastano now that #1063 is finished, i am a little bit unsure how to go ahead with this.

The function parse_pck_cert_chain which i have exposed here in the attestation pallet needs to be called by the staking pallet's validate function.

But it seems we can't have the attestation pallet be a dependency of the staking pallet.

Easiest thing to do would be to move this code to the staking pallet. But logically it kinda belongs here because its kinda related to attestation.

So dunno if i should make a crate for this, or think up another place to put it, or just not worry and stick it in the staking pallet (in its own module).

@HCastano
Copy link
Collaborator

HCastano commented Oct 1, 2024

@ameba23 I think it's fine for this to live somewhere in/near the staking pallet for now as long as it get abstracted correctly, e.g we go through an associated type (T::CertificateVerifier::verify_pck(...)) rather than hardcoding some of these decisions into the pallet.

A module with the trait implementation is probably alright. A standalone crate seems overkill at this point.

* master:
  Bump clap from 4.5.18 to 4.5.19 in the patch-dependencies group (#1091)
  Avoid panic by checking that we have a non-signing validator before selecting one (#1083)
  Fix master build (#1088)
  Small fixes to `test-cli` (#1084)
  Pregenerate keyshares sets for all possible initial signer comittees (#1073)
  Fix master build (#1079)
  Bump reqwest from 0.12.7 to 0.12.8 in the patch-dependencies group (#1082)
  Block tss chain when signer (#1078)
  Run multiple test validator (#1074)
  Bump tempfile from 3.12.0 to 3.13.0 (#1076)
  Bump axum from 0.7.6 to 0.7.7 in the patch-dependencies group (#1075)
  Unignore register and sign integration test, and do a non-mock jumpstart (#1070)
  No unbonding when signer or next signer (#1031)
  Add `/relay_tx` endpoint (#1050)
  Fix how pre-generated keyshares are added for tests (#1061)
  Handle Provisioning Certification Keys (PCKs) (#1051)
  Bump async-trait from 0.1.82 to 0.1.83 in the patch-dependencies group (#1067)
@@ -120,6 +124,15 @@ pub mod pallet {
pub endpoint: TssServerURL,
pub provisioning_certification_key: VerifyingKey,
}

#[derive(Encode, Decode, Clone, Eq, PartialEq, RuntimeDebug, TypeInfo)]
pub struct JoiningServerInfo<AccountId> {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is given as an argument to the validate extrinsic. I don't like having this extra struct, but i couldn't come up with another way of doing it which didn't make it possible that there exists a ServerInfo with no associated PCK which i want to avoid.

Ideally i would like to impl From<ServerInfo> for JoiningServerInfo but because it needs to call the cert validator which is a trait method, i couldn't figure out how to do that either.

Copy link
Collaborator

@HCastano HCastano Oct 23, 2024

Choose a reason for hiding this comment

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

Ideally i would like to impl From for JoiningServerInfo but because it needs to call the cert validator which is a trait method, i couldn't figure out how to do that either.

I think you actually want the other way around, but either way ya it seems a little tricky because of the T bound. We can do it as an internal method on the pallet implementation though.

    impl<T: Config> Pallet<T> {
        // ... snip ...
        fn server_info(joining_server_info: JoiningServerInfo<T::AccountId>) -> ServerInfo<T::AccountId> {
            let provisioning_certification_key =
                T::PckCertChainVerifier::verify_pck_certificate_chain(
                    joining_server_info.pck_certificate_chain,
                )
                .unwrap();

            ServerInfo::<T::AccountId> {
                tss_account: joining_server_info.tss_account,
                x25519_public_key: joining_server_info.x25519_public_key,
                endpoint: joining_server_info.endpoint,
                provisioning_certification_key,
            }
        }
}

This is given as an argument to the validate extrinsic. I don't like having this extra struct, but i couldn't come up with another way of doing it which didn't make it possible that there exists a ServerInfo with no associated PCK which i want to avoid.

But really the above conversion doesn't really handle the crux of the problem which is this. One approach is that we can pass in the certificate chain directly to the extrinsic and then have the ServerInfo.provisioning_certification_key field be an Option. It doesn't guarantee that it can't be None, but it is something that can be verified before writing ServerInfo to storage.

Copy link
Contributor Author

@ameba23 ameba23 Oct 28, 2024

Choose a reason for hiding this comment

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

I feel pretty strongly about wanting assurance at the type level that every ServerInfo has a PCK - i don't want it to be an Option.

I would like to somehow improve the conversion between JoiningServerInfo and ServerInfo but its going to have to be in a follow up as i don't wanna keep resolving conflicts here.

PckCertificateParse,
PckCertificateVerify,
PckCertificateBadPublicKey,
PckCertificateNoCertificate,
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I tried to add the error variant for these as PckCertificate(PckParseVerifyError), but i couldn't get adding #[pallet::Error] to that error type to work, and without it it doesn't implement the needed traits.

@ameba23
Copy link
Contributor Author

ameba23 commented Oct 23, 2024

@JesseAbram @HCastano a gentle reminder this has been up for review for a few weeks now. There were some messy conflicts and i'd like to avoid having more.

@ameba23
Copy link
Contributor Author

ameba23 commented Oct 23, 2024

Still getting an error when running the staking pallet benchmarks, will fix tomorrow.

@HCastano
Copy link
Collaborator

@ameba23 sorry, forgot about this. Will take a look today 🙇

Copy link
Collaborator

@HCastano HCastano left a comment

Choose a reason for hiding this comment

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

Left a few comments but nothing major.

I wasn't able to dig into your error conversion problem, if I have time tomorrow I might take another look at it.

pallets/attestation/src/mock.rs Outdated Show resolved Hide resolved
Comment on lines 546 to 553
pck::PckParseVerifyError::Parse => Error::<T>::PckCertificateParse,
pck::PckParseVerifyError::Verify => Error::<T>::PckCertificateVerify,
pck::PckParseVerifyError::BadPublicKey => {
Error::<T>::PckCertificateBadPublicKey
},
pck::PckParseVerifyError::NoCertificate => {
Error::<T>::PckCertificateNoCertificate
},
Copy link
Collaborator

Choose a reason for hiding this comment

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

We should try and implement a From implementation on these so that we can use ?/into() here

Copy link
Contributor Author

Choose a reason for hiding this comment

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

👍 i've added one but we still need to call map_err to tell rust what type we are converting into because this returns a DispatchResult, not a pallet::Error<T>.

pallets/staking/src/pck/production.rs Outdated Show resolved Hide resolved
pallets/staking/src/pck/production.rs Outdated Show resolved Hide resolved
CHANGELOG.md Outdated Show resolved Hide resolved
pallets/staking/src/pck/production.rs Show resolved Hide resolved
pallets/staking/src/pck/production.rs Outdated Show resolved Hide resolved
pallets/staking/src/tests.rs Outdated Show resolved Hide resolved
@@ -120,6 +124,15 @@ pub mod pallet {
pub endpoint: TssServerURL,
pub provisioning_certification_key: VerifyingKey,
}

#[derive(Encode, Decode, Clone, Eq, PartialEq, RuntimeDebug, TypeInfo)]
pub struct JoiningServerInfo<AccountId> {
Copy link
Collaborator

@HCastano HCastano Oct 23, 2024

Choose a reason for hiding this comment

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

Ideally i would like to impl From for JoiningServerInfo but because it needs to call the cert validator which is a trait method, i couldn't figure out how to do that either.

I think you actually want the other way around, but either way ya it seems a little tricky because of the T bound. We can do it as an internal method on the pallet implementation though.

    impl<T: Config> Pallet<T> {
        // ... snip ...
        fn server_info(joining_server_info: JoiningServerInfo<T::AccountId>) -> ServerInfo<T::AccountId> {
            let provisioning_certification_key =
                T::PckCertChainVerifier::verify_pck_certificate_chain(
                    joining_server_info.pck_certificate_chain,
                )
                .unwrap();

            ServerInfo::<T::AccountId> {
                tss_account: joining_server_info.tss_account,
                x25519_public_key: joining_server_info.x25519_public_key,
                endpoint: joining_server_info.endpoint,
                provisioning_certification_key,
            }
        }
}

This is given as an argument to the validate extrinsic. I don't like having this extra struct, but i couldn't come up with another way of doing it which didn't make it possible that there exists a ServerInfo with no associated PCK which i want to avoid.

But really the above conversion doesn't really handle the crux of the problem which is this. One approach is that we can pass in the certificate chain directly to the extrinsic and then have the ServerInfo.provisioning_certification_key field be an Option. It doesn't guarantee that it can't be None, but it is something that can be verified before writing ServerInfo to storage.

pallets/staking/src/pck/production.rs Outdated Show resolved Hide resolved
@HCastano HCastano added the Bump `transaction_version` A change which affects how existing extrinsics are created (e.g parameter changes) label Oct 23, 2024
@ameba23 ameba23 merged commit 5afd3f8 into master Oct 28, 2024
8 checks passed
@ameba23 ameba23 deleted the peg/handle-pck-certs branch October 28, 2024 11:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bump `transaction_version` A change which affects how existing extrinsics are created (e.g parameter changes)
Projects
Status: Done
Development

Successfully merging this pull request may close these issues.

3 participants