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

proposal: add SASL package to subrepos #16257

Open
SamWhited opened this issue Jul 3, 2016 · 4 comments

Comments

@SamWhited
Copy link
Member

commented Jul 3, 2016

I'd like to see a package that provides RFC 4422 Simple Authentication and Security Layer (SASL) support in the golang.org/x/ package tree (possibly as golang.org/x/crypto/sasl).

This could potentially be used under the covers in the net/smtp package in the future, and would be broadly useful for people implementing other protocols (IMAP, AMQP, IRC, XMPP, memcached, POP, etc.). It would provide a way for varoius packages to share implementations of SASL mechanisms and not introduce problems by always reinventing the wheel every time something needs a SCRAM-SHA-1 implementation.

The API I had in mind (and have an implementation of) is something like this:

//  State represents the current state of a Mechanism's underlying state machine. 
type State int8

const (
    Initial State = iota
    AuthTextSent
    ResponseSent
    ValidServerResponse
)

const (
    // Bit is on if the remote client or server supports channel binding.
    RemoteCB State = 1 << (iota + 3)

    // Bit is on if the machine has errored.
    Errored

    // Bit is on if the machine is a server.
    Receiving
)

// Mechanism represents a SASL mechanism.
// A Mechanism is stateless and may be shared between goroutines or Negotiators.
type Mechanism struct {
    //  The name of the mechanism (eg. `DIGEST-MD5` or `SCRAM-SHA-2`).
    Name  string

    // These functions get called by a Negotiator.
    // I suppose Mechanism could be an interface too, but I like the idea of having
    // it contain these functions so that Step can enforce security constraints on
    // the state machine as much as possible (eg. it can be the only thing that's
    // allowed to mutate the internal state). The bool returned from Next indicates
    // that we should expect more challenges (Step needs to be called again
    // before auth can be completed). The cache return value is stored by a
    // Negotiator and passed back in as the data parameter with the next invocation
    // of Next so that mechanisms can pass state between their steps while still
    // remaining stateless themselves.
    Start func(n Negotiator) (more bool, resp []byte, cache interface{}, err error)
    Next  func(n Negotiator, challenge []byte, data interface{}) (more bool, resp []byte, cache interface{}, err error)
}

// A Negotiator represents a SASL client or server state machine that can attempt
// to negotiate auth. Negotiators should not be used from multiple goroutines, and
// must be reset between negotiation attempts. 
type Negotiator interface {
    // Step is responsible for advancing the state machine and using the
    // underlying mechanism. It should base64 decode the challenge (using the
    // standard base64 encoding) and base64 encode the response generated from the
    // underlying mechanism before returning it.
    Step(challenge []byte) (more bool, resp []byte, err error)
    State() State
    Config() Config
    Nonce() []byte
    Reset()
}

// NewClient creates a new SASL client that supports the given mechanisms.
func NewClient(m Mechanism, opts ...Option) Negotiator

// Config is a SASL client or server configuration.
type Config struct {
    // The state of any TLS connections being used to negotiate SASL (for channel
    // binding).
    TLSState *tls.ConnectionState

    // A list of mechanisms as advertised by the other side of a SASL negotiation.
    RemoteMechanisms []string

    // I don't like having these here because other things might need other
    // credentials (PGP key to sign a challenge with, OAuth token, etc.) and
    // Adding tons of extra stuff here isn't very flexible. Suggestions welcome.
    Identity, Username, Password string
}

type Option func(*Config)
func Authz(identity string) Option {}
func ConnState(cs tls.ConnectionState) Option {}
func Credentials(username, password string) Option {}
func RemoteMechanisms(m ...string) Option {}
…

var (
    Plain Mechanism = plain

    // These are identical internally, just the Hash used is different. Maybe it would make
    // more sense just to expose a `SCRAM(h hash.Hash) Mechanism`
    // function? On the other hand, 99% of the time people will probably just want these 4
    // since they're the only ones standardized.
    ScramSha256Plus = scram("SCRAM-SHA-256-PLUS", sha256.New)
    ScramSha256 = scram("SCRAM-SHA-256", sha256.New)
    ScramSha1Plus = scram("SCRAM-SHA-1-PLUS", sha1.New)
    ScramSha1 = scram("SCRAM-SHA-1", sha1.New)
)

EDIT: I pushed my initial, experimental, implementation with an API similar to this: https://godoc.org/mellium.im/sasl

@ianlancetaylor ianlancetaylor added this to the Proposal milestone Jul 4, 2016

@SamWhited SamWhited changed the title proposal: add SASL package (x/sasl) proposal: add SASL package to subrepos Aug 5, 2016

@emersion

This comment has been minimized.

Copy link

commented Nov 3, 2016

I'm also interested in a common sasl package. I've also already built one for my go-imap package: https://github.com/emersion/go-sasl

If it's not possible to include a new package in the standard library, maybe we can at least have a common API?

@rsc rsc added the Proposal-Hold label Nov 21, 2016

@ernado

This comment has been minimized.

Copy link
Contributor

commented Feb 26, 2017

I'm also interested in a common sasl package, need one for STUN implementation (for performing SASLprep)

@SamWhited

This comment has been minimized.

Copy link
Member Author

commented Feb 26, 2017

@ernado slightly off topic, but you don't need a SASL package for SASLprep, you can use PRECIS which should be mostly compatible with the exception of a few edge cases (this has replaced stringprep).

@Neustradamus

This comment has been minimized.

Copy link

commented Jan 4, 2019

Any news on it?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
6 participants
You can’t perform that action at this time.