You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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. typeStateint8const (
InitialState=iotaAuthTextSentResponseSentValidServerResponse
)
const (
// Bit is on if the remote client or server supports channel binding.RemoteCBState=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.typeMechanismstruct {
// The name of the mechanism (eg. `DIGEST-MD5` or `SCRAM-SHA-2`).Namestring// 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.Startfunc(nNegotiator) (morebool, resp []byte, cacheinterface{}, errerror)
Nextfunc(nNegotiator, challenge []byte, datainterface{}) (morebool, resp []byte, cacheinterface{}, errerror)
}
// 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. typeNegotiatorinterface {
// 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) (morebool, resp []byte, errerror)
State() StateConfig() ConfigNonce() []byteReset()
}
// NewClient creates a new SASL client that supports the given mechanisms.funcNewClient(mMechanism, opts...Option) Negotiator// Config is a SASL client or server configuration.typeConfigstruct {
// 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, Passwordstring
}
typeOptionfunc(*Config)
funcAuthz(identitystring) Option {}
funcConnState(cs tls.ConnectionState) Option {}
funcCredentials(username, passwordstring) Option {}
funcRemoteMechanisms(m...string) Option {}
…
var (
PlainMechanism=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)
)
@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).
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 asgolang.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 aSCRAM-SHA-1
implementation.The API I had in mind (and have an implementation of) is something like this:
EDIT: I pushed my initial, experimental, implementation with an API similar to this: https://godoc.org/mellium.im/sasl
The text was updated successfully, but these errors were encountered: