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

UCAN 1.0-RC.1 #247

Closed
wants to merge 3 commits into from
Closed

UCAN 1.0-RC.1 #247

wants to merge 3 commits into from

Conversation

expede
Copy link
Member

@expede expede commented Mar 7, 2024

No description provided.

Comment on lines +238 to +241
// 1. account -*-> server
// 2. server -a-> device
// 3. dnslink -d-> account
// 4. [dnslink -d-> account -*-> server -a-> device]
Copy link
Member Author

@expede expede Mar 7, 2024

Choose a reason for hiding this comment

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

From looking at the existing code, I think its built around the idea that there would be a /ucan/proxy type?

We... may have a problem with powerlines where they help with the simple case but nothing more complex.

If I'm reading the scenario that you put together correctly, it looks something like this:

1.               account -*-> server
2.               account -*-------------> device
3.  dnslink -d-> account
4. [dnslink -d-> account -*-------------> device]

Which powerlines handle perfectly 👍

// 2.
delegation::Payload {
    subject: None,
    issuer: account_did,
    audience: device_did,
    command: "/",
    policy: vec![],
   // ...


// 3.
delegation::Payload {
    subject: Some(dnslink_did),
    issuer: dnslink_did,
    audience: account_did,
    command: "/",
    policy: vec![],
   // ...
}}

// 4.
invocation::Payload {
    subject: dnslink_did,
    issuer: device_did,
    prf: ["bafy...2", "bafy...3"]
   // ...
}}

...but that doesn't help if the device gets revoked/lost. We need to either put a server in the middle, or reissue UCANs by keeping a signing key around (which would be nice to avoid). The problem with using a subject = None from the server is that you're granting everything delegated to the server, which we obviously don't want.

1.               account -*-> server
2.                            server -a-> device
3.  dnslink -d-> account
4. [dnslink -d-> account -*-> server -a-> device]

This is much closer to the original design with a Proxy ability...

pub struct Proxy<DID: Did, T> {
    pub subject: DID,
    pub proxy: T,
    pub prf: Vec<Cid>
}

...which totally works iff you understand the special proxy type.

Anyhow, just something to ponder. I don't think we can wedge this into the core type, but worth putting some cycles into.

Copy link
Member

Choose a reason for hiding this comment

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

We need to either put a server in the middle, or reissue UCANs by keeping a signing key around (which would be nice to avoid). The problem with using a subject = None from the server is that you're granting everything delegated to the server, which we obviously don't want.

Yeah, the idea was to put the server in the middle, and yes, that would grant everything delegated to the server.

I was thinking of two ways forward:

  • In the future, implement a mode where the user 'owns' their key, by means of BLS multisig + server cosigner n' stuff.
  • In the future, implement multiple server keys in a hierarchy, where the 'root' key is the one that gets full control and is a BLS key.

Copy link
Member Author

Choose a reason for hiding this comment

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

implement multiple server keys in a hierarchy

Just because it's unclear in the above text: is this the version in the design docs, or a new design that relies on BLS features?

Copy link
Member

Choose a reason for hiding this comment

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

The version from the design docs :)

let server_sk = ed25519_dalek::SigningKey::generate(&mut thread_rng());
let server_signer =
ucan::did::preset::Signer::Key(ucan::did::key::Signer::EdDsa(server_sk));
let server_ed_did_key = EdDidKey::new(server_sk);
Copy link
Member Author

@expede expede Mar 7, 2024

Choose a reason for hiding this comment

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

We have incompatible wrappers 😅 Luckily they're all the same key types under the hood. Let's chat about what we like from each approach, and make One Key Wrapper to Rule them All

Copy link
Member

Choose a reason for hiding this comment

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

Yep. Happy to just adopt your key wrapper. The EdDidKey is still an artifact from times where rs_ucan didn't have its own wrapper that worked for me.

server,
"/".into(),
ucan::time::Timestamp::five_years_from_now(),
);
Copy link
Member Author

@expede expede Mar 7, 2024

Choose a reason for hiding this comment

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

☝️ I threw this helper together quickly:

    pub fn powerbox(issuer: DID, audience: DID, command: String, expiration: Timestamp) -> Self {
        let mut seed = vec![];
        let nonce = Nonce::generate_12(seed.as_mut());

        Payload {
            issuer,
            subject: None,
            audience,
            command,
            policy: vec![],
            metadata: BTreeMap::new(),
            nonce,
            expiration,
            not_before: None,
        }
    }

I expect that we'll have a bunch of these kind of utilities

Copy link
Member Author

Choose a reason for hiding this comment

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

I keep thinking about switching command: String to something more structured, but ultimately this just does string comparison at runtime

Copy link
Member

@matheus23 matheus23 Mar 7, 2024

Choose a reason for hiding this comment

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

It's an interesting idea to add helpers for these :)

IMO it would still make sense to expose a builder, so e.g. you'd have a nonce set by default, don't need to set metadata or not_before everytime, etc.

Helpers like powerbox could then return the builder, too, so you could do "a powerbox, but with a slight twist" lol

Copy link
Member Author

Choose a reason for hiding this comment

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

Great idea; I'll add that with the builder macro now 👍

Copy link
Member Author

Choose a reason for hiding this comment

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

BOOM
Screenshot 2024-03-07 at 10 27 36

Copy link
Member

Choose a reason for hiding this comment

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

Ah sweet. It uses &mut Self style. My personal fav

Copy link
Member Author

Choose a reason for hiding this comment

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

I might actually extend this to the Delegation envelope, too, so that you don't have to manually wrap: on build (maybe a different name?) it will run signing etc. This also avoids having to lift multiple layers of failure (inner builder / outer builder)

// 2. server -a-> device
let account_device_ucan = ucan::delegation::Payload {
// subject: None, // Some(account_did), // FIXME
subject: Some(account_did), // FIXME
Copy link
Member Author

Choose a reason for hiding this comment

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

(Note that this is adapted to the more complex powerline scenario mentioned in the comment at the top of the module.)

Why the FIXME? This grants access to do anything ("/") with the account, not a powerline.

nonce: Nonce::generate_12(seed.as_mut()),
expiration: ucan::time::Timestamp::five_years_from_now(),
not_before: None
} // FIXME sign
Copy link
Member Author

@expede expede Mar 7, 2024

Choose a reason for hiding this comment

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

None of these are signed at the moment. It's not difficult, I just haven't done it yet:

let varsig_header = ucan::crypto::varsig::header::EdDsaHeader {
            codec: libipld::cbor::DagCborCodec,
        };

let delegation = Delegation::try_sign(
    &server_signer,
    varsig_header,
    delegation_payload
);

// or just

let delegation = Delegation::try_sign(
    &server_signer,
    varsig_header,
    delegation::Payload {
      issuer: server,
      audience: device,
      command: "/".into(),
      // ...
});

Copy link
Member Author

@expede expede Mar 7, 2024

Choose a reason for hiding this comment

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

Actually, this should get further cleaned up so that devs don't have to explicitly build a varsig header

let delegation = Delegation::try_sign(
    &server_signer,
    codec, // Can build a varsig header from the signer + codec internally
    delegation::Payload {
      issuer: server,
      audience: device,
      command: "/".into(),
      // ...
});

// FissionAbility::AccountInfo,
// now(),
// &did_verifier_map,
// &store,
Copy link
Member Author

Choose a reason for hiding this comment

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

Remember how I said that I don't promise that anything actually works?

I need to fix my MemoryStore because it depends on the DID having Ord, which they don't currently (going to use string/byte comparison).

@matheus23
Copy link
Member

Should we close this in favor of the test being moved to rs-ucan? fission-codes/rs-ucan@6e9131c#diff-ddd02e63303bee6ac70bb11c3e11f325550ca6431bbc18a94ec4981624077e37R267

@expede
Copy link
Member Author

expede commented Mar 8, 2024

@matheus23 good point!

@expede expede closed this Mar 8, 2024
@expede expede deleted the ucan-1.0-rc.1 branch March 8, 2024 17:23
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.

None yet

2 participants