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

Make more 'transactional' #6

Open
nelz9999 opened this issue Sep 4, 2014 · 4 comments
Open

Make more 'transactional' #6

nelz9999 opened this issue Sep 4, 2014 · 4 comments

Comments

@nelz9999
Copy link
Contributor

nelz9999 commented Sep 4, 2014

I'm trying to use this library in a Web context... I would prefer if at least the Verifier-side wasn't required to be long-lived.

Here's an example of the unit test rewritten to show what I'm talking about:

import srp

        # The salt and verifier returned from srp.create_salted_verification_key() should be
        # stored on the server.
        username = 'testuser'
        password = 'testpassword'
        salt, vkey = srp.create_salted_verification_key(username, password)

        class AuthenticationFailed (Exception):
            pass

        # ~~~ Begin Authentication ~~~
        usr      = srp.User(username, password)
        uname, A = usr.start_authentication()

        # The authentication process can fail at each step from this
        # point on. To comply with the SRP protocol, the authentication
        # process should be aborted on the first failure.

        # Client => Server: username, A
        svr      = srp.Verifier(uname, salt, vkey, A)
        s,B      = svr.get_challenge()

        if s is None or B is None:
            raise AuthenticationFailed()

        # Server => Client: s, B
        M        = usr.process_challenge( s, B )

        if M is None:
            raise AuthenticationFailed()

        # Client => Server: M
        svr      = srp.Verifier(uname, salt, vkey, A)
        HAMK     = svr.verify_session( M )
        if HAMK is None:
            raise AuthenticationFailed()

        private_b = srv.get_private_b()
        svr2    = srp.Verifier(uname, salt, vkey, A, private_b=private_b)
        HAMK2   = svr2.verify_session( M )
        if HAMK2 is None:
            raise AuthenticationFailed()

        # Server => Client: HAMK
        usr.verify_session( HAMK )
        usr.verify_session( HAMK2 )

        # At this point the authentication process is complete.

        assert usr.authenticated()
        assert svr.authenticated()
        assert svr2.authenticated()

Notice that srv2 was recreated from srv. This will enable the web back-end to be short-lived while doing two client->server hits.

@cocagne
Copy link
Owner

cocagne commented Sep 4, 2014

In what way would this allow the verifier portion to be more short lived? Some state must be persisted for the duration of the authentication attempt. On the surface, it would seem that there's little, if any, advantage to that approach. You already have an object reference to the full verifier object, why trade that for an object reference to a sub-component of that object and re-create it later?

@nelz9999
Copy link
Contributor Author

nelz9999 commented Sep 4, 2014

Thanks for entertaining my request.

Here's the flow... (I'll use the nomenclature from the doc here: http://srp.stanford.edu/design.html)

At account-setup-time:
(Like normal) User sends I and p. I use create_salted_verification_key to create s and v. I store v and s keyed by I.

User now wants to log in:
ROUNDTRIP No.1 - Client does HTTP POST to (LoadBalancer->)ServerA: I and A. ServerA creates b and B and a transaction_id. ServerA saves A, I, and b, keyed by transaction_id as a short-lived entry in a data store. RETURN: B, s, and transaction_id.

ROUNDTRIP No.2 - Client does HTTP POST to (LoadBalancer->)ServerB: transaction_id and M. ServerB is able to use transaction_id to find I, s, v, A, and b from the data store, and recreates the srp.Verifier to generate the HAMK. RETURN: HAMK.

This allows me to server the two round-trips via stateless webservers.

@cocagne
Copy link
Owner

cocagne commented Sep 4, 2014

Now I follow you. You're looking to effectively span process boundaries via
a backing store. That makes sense and, skimming the code, it looks fairly
easy to implement. The only real complicating factor is that pysrp has 3
implementations, plain python, ctypes + openssl, and a built-in python
module. All three would need to be updated to support the new
keyword-argument to the verifier class.

It's a good idea and shouldn't take more than a handful of hours to
complete. I'm pretty tied down at the moment though. I'll put it on my
queue for eventual implementation but it could be a while before I get
around to it. If you'd like to take a crack at it yourself, I'd gladly
accept a merge request.

Thanks for the suggestion.

Tom

On Wed, Sep 3, 2014 at 11:02 PM, Nelz notifications@github.com wrote:

Thanks for entertaining my request.

Here's the flow... (I'll use the nomenclature from the doc here:
http://srp.stanford.edu/design.html)

At account-setup-time:
(Like normal) User sends I and p. I use create_salted_verification_key to
create s and v. I store v and s keyed by I.

User now wants to log in:
ROUNDTRIP No.1 - Client does HTTP POST to (LoadBalancer->)ServerA: I
and A. ServerA creates b and B and a transaction_id. ServerA saves A,
I, and b, keyed by transaction_id as a short-lived entry in a data store.
RETURN: B, s, and transaction_id.

ROUNDTRIP No.2 - Client does HTTP POST to (LoadBalancer->)ServerB:
transaction_id and M. ServerB is able to use transaction_id to find I, s,
v, A, and b from the data store, and recreates the srp.Verifier to
generate the HAMK. RETURN: HAMK.

This allows me to server the two round-trips via stateless webservers.


Reply to this email directly or view it on GitHub
#6 (comment).

@nelz9999
Copy link
Contributor Author

nelz9999 commented Sep 9, 2014

I should have something for you in a couple of days.

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

2 participants