xmpp/sasl.go
author Chris Jones <christian.jones@sri.com>
Sun, 15 Sep 2013 16:30:55 -0600
changeset 149 22c96a9ab289
parent 147 d7679d991b17
child 150 fa7f6ff10c67
permissions -rw-r--r--
Removed an unused parameter.
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
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    16
// 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
    17
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
    18
	var digestMd5 bool
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    19
	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
    20
		switch strings.ToLower(m) {
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    21
		case "digest-md5":
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    22
			digestMd5 = true
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    23
		}
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    24
	}
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
	if digestMd5 {
147
d7679d991b17 Function renames and improved doc.
Chris Jones <christian.jones@sri.com>
parents: 145
diff changeset
    27
		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
    28
			Mechanism: "DIGEST-MD5"}
143
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    29
		cl.sendXml <- auth
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    30
	}
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    31
}
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
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
    34
	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
    35
	case "challenge":
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    36
		b64 := base64.StdEncoding
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    37
		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
    38
		if err != nil {
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    39
			Warn.Logf("SASL challenge decode: %s", err)
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    40
			return
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    41
		}
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    42
		srvMap := parseSasl(string(str))
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    43
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    44
		if cl.saslExpected == "" {
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    45
			cl.saslDigest1(srvMap)
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    46
		} else {
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    47
			cl.saslDigest2(srvMap)
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    48
		}
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    49
	case "failure":
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    50
		Info.Log("SASL authentication failed")
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    51
	case "success":
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    52
		Info.Log("Sasl authentication succeeded")
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    53
		cl.Features = nil
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    54
		ss := &stream{To: cl.Jid.Domain, Version: XMPPVersion}
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    55
		cl.sendXml <- ss
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    56
	}
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    57
}
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    58
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    59
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
    60
	// 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
    61
	var hasAuth bool
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    62
	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
    63
		if qop == "auth" {
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    64
			hasAuth = true
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    65
		}
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    66
	}
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    67
	if !hasAuth {
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    68
		Warn.Log("Server doesn't support SASL auth")
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    69
		return
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    70
	}
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    71
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    72
	// Pick a realm.
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    73
	var realm string
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    74
	if srvMap["realm"] != "" {
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    75
		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
    76
	}
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    77
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    78
	passwd := cl.password
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    79
	nonce := srvMap["nonce"]
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    80
	digestUri := "xmpp/" + cl.Jid.Domain
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    81
	nonceCount := int32(1)
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    82
	nonceCountStr := fmt.Sprintf("%08x", nonceCount)
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    83
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    84
	// 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
    85
	// user@domain or just domain.
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    86
	var username string
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    87
	if cl.Jid.Node == "" {
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    88
		username = cl.Jid.Domain
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    89
	} else {
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    90
		username = cl.Jid.Node
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    91
	}
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    92
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    93
	// 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
    94
	randSize := big.NewInt(0)
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    95
	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
    96
	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
    97
	if err != nil {
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    98
		Warn.Logf("SASL rand: %s", err)
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
    99
		return
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   100
	}
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   101
	cnonceStr := fmt.Sprintf("%016x", cnonce)
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   102
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   103
	/* 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
   104
	 * 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
   105
	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
   106
		cnonceStr, "AUTHENTICATE", digestUri, nonceCountStr)
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   107
	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
   108
		cnonceStr, "", digestUri, nonceCountStr)
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   109
	cl.saslExpected = next
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   110
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   111
	// 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
   112
	clMap := make(map[string]string)
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   113
	clMap["realm"] = `"` + realm + `"`
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   114
	clMap["username"] = `"` + username + `"`
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   115
	clMap["nonce"] = `"` + nonce + `"`
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   116
	clMap["cnonce"] = `"` + cnonceStr + `"`
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   117
	clMap["nc"] = nonceCountStr
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   118
	clMap["qop"] = "auth"
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   119
	clMap["digest-uri"] = `"` + digestUri + `"`
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   120
	clMap["response"] = response
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   121
	if srvMap["charset"] == "utf-8" {
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   122
		clMap["charset"] = "utf-8"
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   123
	}
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   124
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   125
	// 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
   126
	clStr := packSasl(clMap)
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   127
	b64 := base64.StdEncoding
147
d7679d991b17 Function renames and improved doc.
Chris Jones <christian.jones@sri.com>
parents: 145
diff changeset
   128
	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
   129
		Chardata: b64.EncodeToString([]byte(clStr))}
143
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   130
	cl.sendXml <- clObj
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   131
}
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   132
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   133
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
   134
	if cl.saslExpected == srvMap["rspauth"] {
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   135
		clObj := &auth{XMLName: xml.Name{Space: NsSASL, Local: "response"}}
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   136
		cl.sendXml <- clObj
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   137
	} else {
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: "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
   139
			Local: "abort"}}}
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   140
		cl.sendXml <- clObj
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   141
	}
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   142
}
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   143
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   144
// 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
   145
// key/value map.
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   146
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
   147
	re := regexp.MustCompile(`([^=]+)="?([^",]+)"?,?`)
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   148
	strs := re.FindAllStringSubmatch(in, -1)
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   149
	m := make(map[string]string)
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   150
	for _, pair := range strs {
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   151
		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
   152
		value := string(pair[2])
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   153
		m[key] = value
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   154
	}
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   155
	return m
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   156
}
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
// Inverse of parseSasl().
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   159
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
   160
	var terms []string
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   161
	for key, value := range m {
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   162
		if key == "" || value == "" || value == `""` {
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   163
			continue
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   164
		}
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   165
		terms = append(terms, key+"="+value)
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   166
	}
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   167
	return strings.Join(terms, ",")
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   168
}
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
// 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
   171
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
   172
	authenticate, digestUri, nonceCountStr string) string {
147
d7679d991b17 Function renames and improved doc.
Chris Jones <christian.jones@sri.com>
parents: 145
diff changeset
   173
	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
   174
		h := md5.New()
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   175
		h.Write([]byte(text))
147
d7679d991b17 Function renames and improved doc.
Chris Jones <christian.jones@sri.com>
parents: 145
diff changeset
   176
		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
   177
	}
147
d7679d991b17 Function renames and improved doc.
Chris Jones <christian.jones@sri.com>
parents: 145
diff changeset
   178
	hex := func(input string) string {
d7679d991b17 Function renames and improved doc.
Chris Jones <christian.jones@sri.com>
parents: 145
diff changeset
   179
		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
   180
	}
147
d7679d991b17 Function renames and improved doc.
Chris Jones <christian.jones@sri.com>
parents: 145
diff changeset
   181
	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
   182
		return h(secret + ":" + data)
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   183
	}
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   184
147
d7679d991b17 Function renames and improved doc.
Chris Jones <christian.jones@sri.com>
parents: 145
diff changeset
   185
	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
   186
		nonce + ":" + cnonceStr
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   187
	a2 := authenticate + ":" + digestUri
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   188
	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
   189
		nonceCountStr+":"+cnonceStr+":auth:"+
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   190
		hex(h(a2))))
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   191
	return response
62166e57800e Split stream.go into layer1, layer2, layer3, and sasl.
Chris Jones <christian.jones@sri.com>
parents:
diff changeset
   192
}