x/crypto/otr: clear key slots when handshaking.

The OTR implementation had a bug where key slots would not be marked as
unused after a rehandshake. Since handshaking resets the key ids, some
key slots would be left over with much higher key ids. These key slots
would lead to an error when the code ran out of slots.

Fixes agl/xmpp-client#96.

Change-Id: I013bbc4eaf0616373ab52f14b7f7757c353983ca
Reviewed-on: https://go-review.googlesource.com/16934
Reviewed-by: Andrew Gerrand <adg@golang.org>
diff --git a/otr/otr.go b/otr/otr.go
index f872a9d..549be11 100644
--- a/otr/otr.go
+++ b/otr/otr.go
@@ -277,7 +277,7 @@
 		in = in[len(msgPrefix) : len(in)-1]
 	} else if version := isQuery(in); version > 0 {
 		c.authState = authStateAwaitingDHKey
-		c.myKeyId = 0
+		c.reset()
 		toSend = c.encode(c.generateDHCommit())
 		return
 	} else {
@@ -311,7 +311,7 @@
 			if err = c.processDHCommit(msg); err != nil {
 				return
 			}
-			c.myKeyId = 0
+			c.reset()
 			toSend = c.encode(c.generateDHKey())
 			return
 		case authStateAwaitingDHKey:
@@ -330,7 +330,7 @@
 				if err = c.processDHCommit(msg); err != nil {
 					return
 				}
-				c.myKeyId = 0
+				c.reset()
 				toSend = c.encode(c.generateDHKey())
 				return
 			}
@@ -343,7 +343,7 @@
 			if err = c.processDHCommit(msg); err != nil {
 				return
 			}
-			c.myKeyId = 0
+			c.reset()
 			toSend = c.encode(c.generateDHKey())
 			c.authState = authStateAwaitingRevealSig
 		default:
@@ -1036,8 +1036,7 @@
 		}
 	}
 	if slot == nil {
-		err = errors.New("otr: internal error: no key slots")
-		return
+		return nil, errors.New("otr: internal error: no more key slots")
 	}
 
 	var myPriv, myPub, theirPub *big.Int
@@ -1163,6 +1162,14 @@
 	return ret
 }
 
+func (c *Conversation) reset() {
+	c.myKeyId = 0
+
+	for i := range c.keySlots {
+		c.keySlots[i].used = false
+	}
+}
+
 type PublicKey struct {
 	dsa.PublicKey
 }