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