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

opaque-ke 2.0.0 is not compatible with Rust 1.81.0 and newer #359

Open
vdhanan opened this issue Sep 5, 2024 · 16 comments
Open

opaque-ke 2.0.0 is not compatible with Rust 1.81.0 and newer #359

vdhanan opened this issue Sep 5, 2024 · 16 comments

Comments

@vdhanan
Copy link

vdhanan commented Sep 5, 2024

opaque-ke 2.0.0 explicitly pins an older version of voprf that violates the new lifetime rules (rust-lang/rust#117967)

voprf fixed this issue in version 0.5.0: facebook/voprf#131

would it be possible to cut a new release of opaque-ke 2.0 with the latest version of voprf?

also, this issue probably affects the opaque-ke 3.0 pre-release, too, since it also pins an older version of voprf

@kevinlewi
Copy link
Contributor

Hi @vdhanan -- sorry for the delays in replying. This makes sense, however: do you need an explicit new release on top of opaque-ke 2.0, or would it suffice to just include this in an update to the pre-release for opaque-ke 3.0? There are protocol changes between 2.0 and 3.0, and at this point I am hoping it makes sense for applications to work off of 3.0 if they can upgrade.

@vdhanan
Copy link
Author

vdhanan commented Sep 18, 2024

We need a new release on top of 2.0 if possible!

@kevinlewi
Copy link
Contributor

@vdhanan Unfortunately, it won't really be possible to release with the latest version of voprf 0.5 on top of opaque-ke 2.0 since opaque-ke 2.0 pins voprf 0.4.0-pre.3, which is a different (and incompatible) protocol when compared with voprf 0.5.

Hence, I would recommend pulling in the latest pre-release for opaque-ke v3, which I can update to include the latest voprf dependency shortly.

@kevinlewi
Copy link
Contributor

https://crates.io/crates/opaque-ke/3.0.0-pre.5 has been published

@drey7925
Copy link

drey7925 commented Sep 21, 2024

Is there some sort of format conversion we would need to do to make a stored ServerSetup and ServerLogin produced by a v2 client/server work with a v3 client/server?

I tried just changing 2.0.0 to 3.0.0-pre.5 at both the client and the server of my application, and unless I'm doing something wrong on my end, it looks like existing logins no longer work. In case it matters, my parameters are

impl CipherSuite for MyApplicationAuth {
    type OprfCs = opaque_ke::Ristretto255;
    type KeGroup = opaque_ke::Ristretto255;
    type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDh;
    type Ksf = argon2::Argon2<'static>;
}

At least in my case, my application doesn't have any real users yet so I can wipe and recreate everything, but I suspect that there may be other users of this crate that are in the same situation.

I wonder if it may instead be possible/easier to backport the lifetimes fix on voprf 0.4 and then pin the updated voprf 0.4 in a new opaque-ke2.0 release, but I may also be misunderstanding the situation.

drey7925 added a commit to drey7925/perovskite that referenced this issue Sep 21, 2024
This is a breaking protocol change, and may also require servers to reset all user passwords. See facebook/opaque-ke#359 (comment) for context
@cyyynthia
Copy link
Contributor

There has been breaking changes introduced in the OPRF protocol, so yes all previous records need to be updated somehow (FYI #365 will introduce further breaking changes).

This process of updating records due to such type of changes are mentioned under application considerations, and some valuable discussions have happened over cfrg/draft-irtf-cfrg-opaque#394 (and other issues referenced there) about how to handle such type of updates.

Long story short, the protocol itself doesn't make any recommendation about how to proceed as it's inherently application specific and depends on what your needs are, how you're using OPAQUE, what security needs you have, etc. In all cases, re-registration is required. For live applications, available options include:

  • Authenticate using the old record (via an old build of the lib for instance), and perform re-registration
    • Make sure to do it securely, i.e. validating the public key matches. So long it's implemented correctly I think it may be acceptable to do it mostly automatically, thanks to OPAQUE's mutual authentication properties (the server also authenticates itself during the auth flow).
  • Drop records and require a re-registration
    • This should always come with another authentication factor, such as via a OTP sent by email or through any other applicable mean. This option is basically a forced password reset, which is an extremely sensitive point of failure and must be secured accordingly. Be careful not to introduce client enumeration risks while implementing such measure.

There's likely more, depending on your needs. Make sure whatever you pick doesn't introduce a problematic point of failure, and that it's safe for your use case. I'm also not necessarily a security expert, so double check the options I've cited if considering them, just in case I missed something obvious (or not so obvious) 😅

@drey7925
Copy link

Thanks, that makes sense from a protocol standpoint.

However, to validate both 2.0.0 and 3.0.0, I'd still need to be able to build 2.0.0 (which prevents me from using any new rust versions especially if everything is in one static binary unless a fix is backported to make opaque_ke 2.0.0 and voprf 0.4 build, right?)

@cyyynthia
Copy link
Contributor

That is very true. I opened facebook/voprf#135, so hopefully it can be released as 0.4.1 and opaque-ke 2.x can then be updated to this version without creating breaking changes 🙏🏻

drey7925 added a commit to drey7925/opaque-ke that referenced this issue Oct 9, 2024
voprf 0.4.0 is incompatible with Rust 1.81.0 and newer (see issue facebook#359); a fix was backported from voprf 0.5 to produce voprf 0.4.1.
@drey7925
Copy link

drey7925 commented Oct 9, 2024

I tried to prep a patch to pick up the new voprf but ran into CLA issues on my end; would you be able to bump the dependency from this crate to voprf when you have a chance?

@kevinlewi
Copy link
Contributor

https://crates.io/crates/opaque-ke/2.1.0-pre.1 has been released, which should hopefully address this issue -- @drey7925, @vdhanan let me know if this works!

@drey7925
Copy link

drey7925 commented Oct 10, 2024

Thank you so much! Unfortunately, I wasn't able to get a login working from a client with 2.1.0-pre.1, either to an existing server running 2.0.0, or to a local server with 2.0.0 records running 2.1.0-pre.1 - I get InvalidLoginError from trying to finish ClientLogin.

Here's a diff of Cargo.lock, from the last good build (either on old Rust, or with a local change to voprf to patch the lifetime specifier issue) to my attempt to build with 2.1.0-pre.1: https://gist.github.com/drey7925/f9fa8970b1ec2f85ce6a4e31aef846ae. Unfortunately, I'm not familiar enough with these packages to know which might affect the binary format.

@kevinlewi
Copy link
Contributor

kevinlewi commented Oct 10, 2024

Thank you so much! Unfortunately, I wasn't able to get a login working from a client with 2.1.0-pre.1, either to an existing server running 2.0.0, or to a local server with 2.0.0 records running 2.1.0-pre.1 - I get InvalidLoginError from trying to finish ClientLogin.

That's quite surprising, given that the diff between 2.0.0 and 2.1.0-pre.1 did not involve changing the test vector bytes (which are found here and here)...

Not entirely sure what the best way to debug is, but can you share the CipherSuite format you are using (is it DefaultCipherSuite?) as well as potentially a serialized password file assuming this is for non-sensitive data? <-- In general, will need a way to repro in order to debug

@drey7925
Copy link

drey7925 commented Oct 16, 2024

Sorry for the delay, I somehow missed the notification/email.

I'm using a ciphersuite that looks identical:

impl CipherSuite for PerovskiteOpaqueAuth {
    type OprfCs = opaque_ke::Ristretto255;
    type KeGroup = opaque_ke::Ristretto255;
    type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDh;
    type Ksf = argon2::Argon2<'static>;
}

Here's a test with a deterministic RNG (at time of login, but not at time of setup/registration, this is from my non-sensitive test server). The username is drey and the password is asdf:

As far as I can tell, these results are deterministic in each version for me, since everything uses this RNG:


struct FakeRng;
impl rand::RngCore for FakeRng {
    fn next_u32(&mut self) -> u32 {
        0x55555555
    }

    fn next_u64(&mut self) -> u64 {
        0x5555555555555555
    }

    fn fill_bytes(&mut self, dest: &mut [u8]) {
        dest.fill(0x55)
    }

    fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
        dest.fill(0x55);
        Ok(())
    }
}
impl rand::CryptoRng for FakeRng {}

For this test, server setup is CME11C0UAj78RaOjMroAkv/0LFHI5IHsoKOqE7ZYSg44Ux489erDiAbn/qJ9XrcuFa+RLFaPa2/VaHYe0xZJU9aFNJD+sUH39JOM3KM1jFxgu+6TQ75EuNwEELXRnqgLOrB+vhxnpJksUZy29AV2Dx1XO9erlxwROiF7zmzIZQg= and the password file is WB1cYUetbaTvf4TY7UmUjVO4LHmbLi9onpN10kUhkDk9cW8Ytp4VZSKbBBwpe4VFCGgjWC1inL6PSX0doyEMZw/YTSipu/eeAqcV+wFBxMVOy9prbO1e1e3ZyUT125+cjXojYeNUOK+No1Zsng6WBxbo9DZXqiAJlDBkTBtsWP2QALCjy5Pga3/LG9ARJg0LrBF5/SWxFp5RBuOojyayZjNsDlKapYYZpLATBQhhvtmP4giJGgs9zvK3Hcxz5Lkw (both base64). The username and password are ASCII drey and asdf, respectively.

Thank you so much for looking into this; please let me know if any other reproducer is needed and I can try to put it together.

@kevinlewi
Copy link
Contributor

@drey7925 I think I was able to diagnose the root cause: there is a difference between argon2 v0.4 and argon2 v0.5, in that the default parameters were changed. v0.4 has (m = 4096, t = 3, p = 1) whereas v0.5 has (m = 19456, t = 2, p = 1).

I was able to reproduce the error you were seeing originally. I then copied your base64 strings locally into a login attempt for v2.1.0-pre.1 and forced the use of the argon2 v0.4 default parameters, and the login was then successful.

Another way to check that these mismatching argon2 parameters is the root cause: see if v2.0.0 and v2.1.0-pre.1 are compatible if Ksf = Identity in the CipherSuite.

@drey7925
Copy link

Apologies for the toil looking into this. It looks like that was my mistake; I grabbed the upgrade blindly without checking for changes in other crates, and assumed that the hash was standardized and didn't change, while forgetting about the hash parameters.

I guess this means that DefaultCipherSuite in the example potentially changes since 2.0.0 picks up argon2 0.4 and references it while 2.1.0pre picks up argon2 0.5 (just not easily visible since the example doesn't persist data).

Is the best move, in my application, to wrap Argon2 myself and provide an impl of Ksf that runs Argon2 with the correct parameters?

@kevinlewi
Copy link
Contributor

Is the best move, in my application, to wrap Argon2 myself and provide an impl of Ksf that runs Argon2 with the correct parameters?

Yep, that should work.

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

No branches or pull requests

4 participants