Exemple #1
0
// Initializes the SASL handshake using the specified mechanism
func Init(mechanism string, data []byte) ([]byte, []byte, error) {
	switch mechanism {
	case "SCRAM-SHA-1":
		msg, err := auth.DecodeBase64(data)
		if err != nil {
			log.Println(err)
			return nil, nil, AuthFailError
		}
		nonce := genNonce()
		response, err := InitialResponseSCRAMSHA1(msg, nonce)
		if err != nil {
			return nil, nil, err
		}
		splitMsg := strings.Split(string(msg), ",")
		data := []byte(splitMsg[2] + "," + splitMsg[3] + "," + string(response))

		return auth.EncodeBase64(response), data, nil

	default:
		return nil, nil, UnsupportedAuthenticationMechanism(mechanism)
	}

	log.Printf("Impossible program flow!\n")
	return nil, nil, nil
}
func FinalResponseSCRAMSHA1(clientFinalMsg, prevMsg []byte) ([]byte, error) {
	oldMsg := strings.Split(string(prevMsg), ",")
	components := strings.Split(string(clientFinalMsg), ",")

	if oldMsg[2] != components[1] {
		log.Println("session nonce does not match")
		return nil, AuthFailError
	}

	authMsg := string(prevMsg) + "," + components[0] + "," + components[1]

	username := oldMsg[2][2:]
	user := records.Users.FindByName(username)

	// for some reason there are null characters at the end?
	tmp := strings.TrimRight(components[2][2:], "\x00")
	clientProof, err := auth.DecodeBase64([]byte(tmp))
	if err != nil {
		log.Println(err)
		return nil, AuthFailError
	}
	clientKey := auth.HMAC(user.Pass.Key, "Client Key")
	storedKey := auth.H(clientKey)
	clientSignature := auth.HMAC(storedKey, authMsg)

	length := len(storedKey)
	authFailed := false
	for i := 0; i < length; i++ {
		v := clientKey[i] ^ clientSignature[i]
		if clientProof[i] != v {
			authFailed = true
		}
	}

	// avoid early exit when comparing password related data
	if authFailed {
		log.Println("Invalid Client Proof")
		return nil, AuthFailError
	}

	serverKey := auth.HMAC(user.Pass.Key, "Server Key")
	signature := auth.HMAC(serverKey, authMsg)
	armouredSignature := auth.EncodeBase64(signature)
	return []byte("v=" + string(armouredSignature)), nil
}
Exemple #3
0
// Continues the SASL handshake
func Respond(mech string, data []byte, storedData []byte) ([]byte, error) {
	switch mech {
	case "SCRAM-SHA-1":
		raw, err := auth.DecodeBase64(data)
		if err != nil {
			log.Println(err)
			return nil, AuthFailError
		}

		response, err := FinalResponseSCRAMSHA1(raw, storedData)
		if err != nil {
			return nil, err
		}

		return auth.EncodeBase64(response), nil

	default:
		return nil, UnsupportedAuthenticationMechanism(mech)
	}
}
func InitialResponseSCRAMSHA1(initialMsg, nonce []byte) ([]byte, error) {
	// first message must start with either "n", "y" or "p"
	if initialMsg[0] != 'n' { // && initialMsg[0] != 'p' && initialMsg[0] != 'y' {
		log.Println("invalid initial response")
		return nil, AuthFailError
	}

	s := strings.Split(string(initialMsg), ",")

	// well formed messages will result in 4 components
	if len(s) != 4 {
		log.Println("invalid initial response")
		return nil, AuthFailError
	}

	username := string(s[2][2:])
	clientNonce := string(s[3][2:])

	user := records.Users.FindByName(username)

	encodedSalt := string(auth.EncodeBase64(user.Pass.Salt))
	return []byte("r=" + clientNonce + string(nonce) + ",s=" + encodedSalt + ",i=" + strconv.Itoa(auth.PASSWORD_ITERATIONS)), nil
}
			It("should not generate an error", func() {
				Ω(err).To(BeNil())
			})

			It("should have exactly 3 components", func() {
				Ω(len(components)).To(Equal(3))
			})

			It("should set the first component to be the combined nonce", func() {
				Ω(components[0]).To(Equal("r=" + string(clientNonce) + string(nonce)))
			})

			It("should set the second component to the users salt", func() {
				raw := StubUser.Pass.Salt
				encBase64 := auth.EncodeBase64(raw)
				Ω(components[1][2:]).To(Equal(string(encBase64)))
			})

			It("should contain the correct number of iterations", func() {
				iters, _ := strconv.Atoi(components[2][2:])
				Ω(iters).To(Equal(auth.PASSWORD_ITERATIONS))
			})
		})

		Context("with invalid requests", func() {
			It("should throw an error when it receives malformed requests", func() {
				_, err := InitialResponseSCRAMSHA1([]byte("thisissomerandommessage"), nonce)
				Expect(err).NotTo(BeNil())
			})
		})
Exemple #6
0
var _ = Describe("Anonymous connections", func() {

	Context("authentication", func() {

		salt, _ := auth.DecodeBase64([]byte("QSXCR+Q6sek8bf92"))
		user := CreateStubUserWithSalt("user", "pencil", salt)
		connection := NewAnonymousConnection()

		BeforeEach(func() {
			connection.ClearMessages()
		})

		It("should respond to the first message in the authentication handshake", func() {
			clientMsg := "n,,u=" + user.Name + ",n=fyko+d2lbbFgONRv9qkxdawL"
			msg := auth.EncodeBase64([]byte(clientMsg))
			err := connection.Send("<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='SCRAM-SHA-1'>" + string(msg) + "</auth>")
			if err != nil {
				panic(err)
			}

			Expect(connection.LastMessage()).To(MatchRegexp("^<challenge(.*)challenge>$"))
		})

		It("should respond with successful authentication on the second part of the handshake", func() {
			clientFinalMsg := "c=biws,r=fyko+d2lbbFgONRv9qkxdawL3rfcNHYJY1ZVvWVs7j,p=v0X8v3Bz2T0CJGbJQyF0X+HI4Ts="
			msg := auth.EncodeBase64([]byte(clientFinalMsg))
			err := connection.Send("<response xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>" + string(msg) + "</response>")
			if err != nil {
				panic(err)
			}