xmpp/sasl.go
author Chris Jones <chris@cjones.org>
Sat, 09 Nov 2013 12:09:37 -0700
changeset 178 ccfebbd9f49b
parent 163 3f891f7fe817
child 184 ce49140fe60b
permissions -rw-r--r--
Changed the JID type to be an alias of string, rather than a struct. This allows it to be used as a key in a map, among other benefits.
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
143
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
     1
// Deal with SASL authentication.
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
     2
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
     3
package xmpp
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
     4
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
     5
import (
145
Chris Jones <christian.jones@sri.com>
parents: 143
diff changeset
     6
	"crypto/md5"
Chris Jones <christian.jones@sri.com>
parents: 143
diff changeset
     7
	"crypto/rand"
Chris Jones <christian.jones@sri.com>
parents: 143
diff changeset
     8
	"encoding/base64"
143
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
     9
	"encoding/xml"
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    10
	"fmt"
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    11
	"math/big"
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    12
	"regexp"
145
Chris Jones <christian.jones@sri.com>
parents: 143
diff changeset
    13
	"strings"
143
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    14
)
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    15
150
fa7f6ff10c67 Code reorder and doc cleanup.
Chris Jones <christian.jones@sri.com>
parents: 147
diff changeset
    16
// Server is advertising auth mechanisms it supports. Choose one and
fa7f6ff10c67 Code reorder and doc cleanup.
Chris Jones <christian.jones@sri.com>
parents: 147
diff changeset
    17
// respond.
143
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    18
// BUG(cjyar): Doesn't implement TLS/SASL EXTERNAL.
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    19
func (cl *Client) chooseSasl(fe *Features) {
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    20
	var digestMd5 bool
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    21
	for _, m := range fe.Mechanisms.Mechanism {
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    22
		switch strings.ToLower(m) {
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    23
		case "digest-md5":
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    24
			digestMd5 = true
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    25
		}
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    26
	}
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    27
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    28
	if digestMd5 {
147
d7679d991b17 Function renames and improved doc.
Chris Jones <christian.jones@sri.com>
parents: 145
diff changeset
    29
		auth := &auth{XMLName: xml.Name{Space: NsSASL, Local: "auth"},
d7679d991b17 Function renames and improved doc.
Chris Jones <christian.jones@sri.com>
parents: 145
diff changeset
    30
			Mechanism: "DIGEST-MD5"}
163
3f891f7fe817 Removed the weirdo logging facility. There's now a Debug variable which can be set which replaces the former debug log. NewClient() will return an error if something goes wrong setting up the connection.
Chris Jones <chris@cjones.org>
parents: 153
diff changeset
    31
		cl.sendRaw <- auth
143
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    32
	}
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    33
}
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    34
150
fa7f6ff10c67 Code reorder and doc cleanup.
Chris Jones <christian.jones@sri.com>
parents: 147
diff changeset
    35
// Server is responding to our auth request.
143
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    36
func (cl *Client) handleSasl(srv *auth) {
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    37
	switch strings.ToLower(srv.XMLName.Local) {
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    38
	case "challenge":
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    39
		b64 := base64.StdEncoding
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    40
		str, err := b64.DecodeString(srv.Chardata)
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    41
		if err != nil {
163
3f891f7fe817 Removed the weirdo logging facility. There's now a Debug variable which can be set which replaces the former debug log. NewClient() will return an error if something goes wrong setting up the connection.
Chris Jones <chris@cjones.org>
parents: 153
diff changeset
    42
			cl.setError(fmt.Errorf("SASL: %v", err))
143
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    43
			return
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    44
		}
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    45
		srvMap := parseSasl(string(str))
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    46
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    47
		if cl.saslExpected == "" {
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    48
			cl.saslDigest1(srvMap)
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    49
		} else {
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    50
			cl.saslDigest2(srvMap)
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    51
		}
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    52
	case "failure":
163
3f891f7fe817 Removed the weirdo logging facility. There's now a Debug variable which can be set which replaces the former debug log. NewClient() will return an error if something goes wrong setting up the connection.
Chris Jones <chris@cjones.org>
parents: 153
diff changeset
    53
		cl.setError(fmt.Errorf("SASL authentication failed"))
143
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    54
	case "success":
153
bbd4166df95d Simplified the API: There's only one constructor, and it does everything necessary to initiate the stream. StartSession() and Roster.Update() have both been eliminated.
Chris Jones <christian.jones@sri.com>
parents: 150
diff changeset
    55
		cl.setStatus(StatusAuthenticated)
143
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    56
		cl.Features = nil
178
ccfebbd9f49b Changed the JID type to be an alias of string, rather than a struct. This allows it to be used as a key in a map, among other benefits.
Chris Jones <chris@cjones.org>
parents: 163
diff changeset
    57
		ss := &stream{To: cl.Jid.Domain(), Version: XMPPVersion}
163
3f891f7fe817 Removed the weirdo logging facility. There's now a Debug variable which can be set which replaces the former debug log. NewClient() will return an error if something goes wrong setting up the connection.
Chris Jones <chris@cjones.org>
parents: 153
diff changeset
    58
		cl.sendRaw <- ss
143
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    59
	}
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    60
}
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    61
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    62
func (cl *Client) saslDigest1(srvMap map[string]string) {
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    63
	// Make sure it supports qop=auth
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    64
	var hasAuth bool
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    65
	for _, qop := range strings.Fields(srvMap["qop"]) {
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    66
		if qop == "auth" {
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    67
			hasAuth = true
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    68
		}
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    69
	}
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    70
	if !hasAuth {
163
3f891f7fe817 Removed the weirdo logging facility. There's now a Debug variable which can be set which replaces the former debug log. NewClient() will return an error if something goes wrong setting up the connection.
Chris Jones <chris@cjones.org>
parents: 153
diff changeset
    71
		cl.setError(fmt.Errorf("Server doesn't support SASL auth"))
143
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    72
		return
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    73
	}
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    74
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    75
	// Pick a realm.
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    76
	var realm string
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    77
	if srvMap["realm"] != "" {
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    78
		realm = strings.Fields(srvMap["realm"])[0]
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    79
	}
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    80
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    81
	passwd := cl.password
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    82
	nonce := srvMap["nonce"]
178
ccfebbd9f49b Changed the JID type to be an alias of string, rather than a struct. This allows it to be used as a key in a map, among other benefits.
Chris Jones <chris@cjones.org>
parents: 163
diff changeset
    83
	digestUri := "xmpp/" + cl.Jid.Domain()
143
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    84
	nonceCount := int32(1)
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    85
	nonceCountStr := fmt.Sprintf("%08x", nonceCount)
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    86
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    87
	// Begin building the response. Username is
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    88
	// user@domain or just domain.
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    89
	var username string
178
ccfebbd9f49b Changed the JID type to be an alias of string, rather than a struct. This allows it to be used as a key in a map, among other benefits.
Chris Jones <chris@cjones.org>
parents: 163
diff changeset
    90
	if cl.Jid.Node() == "" {
ccfebbd9f49b Changed the JID type to be an alias of string, rather than a struct. This allows it to be used as a key in a map, among other benefits.
Chris Jones <chris@cjones.org>
parents: 163
diff changeset
    91
		username = cl.Jid.Domain()
143
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    92
	} else {
178
ccfebbd9f49b Changed the JID type to be an alias of string, rather than a struct. This allows it to be used as a key in a map, among other benefits.
Chris Jones <chris@cjones.org>
parents: 163
diff changeset
    93
		username = cl.Jid.Node()
143
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    94
	}
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    95
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    96
	// Generate our own nonce from random data.
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    97
	randSize := big.NewInt(0)
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    98
	randSize.Lsh(big.NewInt(1), 64)
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    99
	cnonce, err := rand.Int(rand.Reader, randSize)
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   100
	if err != nil {
163
3f891f7fe817 Removed the weirdo logging facility. There's now a Debug variable which can be set which replaces the former debug log. NewClient() will return an error if something goes wrong setting up the connection.
Chris Jones <chris@cjones.org>
parents: 153
diff changeset
   101
		cl.setError(fmt.Errorf("SASL rand: %v", err))
143
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   102
		return
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   103
	}
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   104
	cnonceStr := fmt.Sprintf("%016x", cnonce)
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   105
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   106
	/* Now encode the actual password response, as well as the
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   107
	 * expected next challenge from the server. */
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   108
	response := saslDigestResponse(username, realm, passwd, nonce,
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   109
		cnonceStr, "AUTHENTICATE", digestUri, nonceCountStr)
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   110
	next := saslDigestResponse(username, realm, passwd, nonce,
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   111
		cnonceStr, "", digestUri, nonceCountStr)
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   112
	cl.saslExpected = next
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   113
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   114
	// Build the map which will be encoded.
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   115
	clMap := make(map[string]string)
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   116
	clMap["realm"] = `"` + realm + `"`
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   117
	clMap["username"] = `"` + username + `"`
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   118
	clMap["nonce"] = `"` + nonce + `"`
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   119
	clMap["cnonce"] = `"` + cnonceStr + `"`
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   120
	clMap["nc"] = nonceCountStr
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   121
	clMap["qop"] = "auth"
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   122
	clMap["digest-uri"] = `"` + digestUri + `"`
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   123
	clMap["response"] = response
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   124
	if srvMap["charset"] == "utf-8" {
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   125
		clMap["charset"] = "utf-8"
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   126
	}
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   127
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   128
	// Encode the map and send it.
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   129
	clStr := packSasl(clMap)
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   130
	b64 := base64.StdEncoding
147
d7679d991b17 Function renames and improved doc.
Chris Jones <christian.jones@sri.com>
parents: 145
diff changeset
   131
	clObj := &auth{XMLName: xml.Name{Space: NsSASL, Local: "response"},
d7679d991b17 Function renames and improved doc.
Chris Jones <christian.jones@sri.com>
parents: 145
diff changeset
   132
		Chardata: b64.EncodeToString([]byte(clStr))}
163
3f891f7fe817 Removed the weirdo logging facility. There's now a Debug variable which can be set which replaces the former debug log. NewClient() will return an error if something goes wrong setting up the connection.
Chris Jones <chris@cjones.org>
parents: 153
diff changeset
   133
	cl.sendRaw <- clObj
143
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   134
}
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   135
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   136
func (cl *Client) saslDigest2(srvMap map[string]string) {
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   137
	if cl.saslExpected == srvMap["rspauth"] {
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   138
		clObj := &auth{XMLName: xml.Name{Space: NsSASL, Local: "response"}}
163
3f891f7fe817 Removed the weirdo logging facility. There's now a Debug variable which can be set which replaces the former debug log. NewClient() will return an error if something goes wrong setting up the connection.
Chris Jones <chris@cjones.org>
parents: 153
diff changeset
   139
		cl.sendRaw <- clObj
143
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   140
	} else {
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   141
		clObj := &auth{XMLName: xml.Name{Space: NsSASL, Local: "failure"}, Any: &Generic{XMLName: xml.Name{Space: NsSASL,
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   142
			Local: "abort"}}}
163
3f891f7fe817 Removed the weirdo logging facility. There's now a Debug variable which can be set which replaces the former debug log. NewClient() will return an error if something goes wrong setting up the connection.
Chris Jones <chris@cjones.org>
parents: 153
diff changeset
   143
		cl.sendRaw <- clObj
143
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   144
	}
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   145
}
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   146
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   147
// Takes a string like `key1=value1,key2="value2"...` and returns a
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   148
// key/value map.
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   149
func parseSasl(in string) map[string]string {
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   150
	re := regexp.MustCompile(`([^=]+)="?([^",]+)"?,?`)
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   151
	strs := re.FindAllStringSubmatch(in, -1)
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   152
	m := make(map[string]string)
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   153
	for _, pair := range strs {
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   154
		key := strings.ToLower(string(pair[1]))
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   155
		value := string(pair[2])
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   156
		m[key] = value
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   157
	}
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   158
	return m
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   159
}
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   160
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   161
// Inverse of parseSasl().
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   162
func packSasl(m map[string]string) string {
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   163
	var terms []string
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   164
	for key, value := range m {
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   165
		if key == "" || value == "" || value == `""` {
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   166
			continue
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   167
		}
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   168
		terms = append(terms, key+"="+value)
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   169
	}
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   170
	return strings.Join(terms, ",")
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   171
}
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   172
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   173
// Computes the response string for digest authentication.
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   174
func saslDigestResponse(username, realm, passwd, nonce, cnonceStr,
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   175
	authenticate, digestUri, nonceCountStr string) string {
147
d7679d991b17 Function renames and improved doc.
Chris Jones <christian.jones@sri.com>
parents: 145
diff changeset
   176
	h := func(text string) string {
143
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   177
		h := md5.New()
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   178
		h.Write([]byte(text))
147
d7679d991b17 Function renames and improved doc.
Chris Jones <christian.jones@sri.com>
parents: 145
diff changeset
   179
		return string(h.Sum(nil))
143
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   180
	}
147
d7679d991b17 Function renames and improved doc.
Chris Jones <christian.jones@sri.com>
parents: 145
diff changeset
   181
	hex := func(input string) string {
d7679d991b17 Function renames and improved doc.
Chris Jones <christian.jones@sri.com>
parents: 145
diff changeset
   182
		return fmt.Sprintf("%x", input)
143
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   183
	}
147
d7679d991b17 Function renames and improved doc.
Chris Jones <christian.jones@sri.com>
parents: 145
diff changeset
   184
	kd := func(secret, data string) string {
143
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   185
		return h(secret + ":" + data)
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   186
	}
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   187
147
d7679d991b17 Function renames and improved doc.
Chris Jones <christian.jones@sri.com>
parents: 145
diff changeset
   188
	a1 := h(username+":"+realm+":"+passwd) + ":" +
143
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   189
		nonce + ":" + cnonceStr
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   190
	a2 := authenticate + ":" + digestUri
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   191
	response := hex(kd(hex(h(a1)), nonce+":"+
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   192
		nonceCountStr+":"+cnonceStr+":auth:"+
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   193
		hex(h(a2))))
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   194
	return response
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   195
}