Skip to content
10 changes: 6 additions & 4 deletions client/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -808,10 +808,11 @@ func (c *cliClient) showIdentity() {
heading: "Identity",
rows: []cliRow{
cliRow{cols: []string{"Server", terminalEscape(c.server, false)}},
cliRow{cols: []string{"Public identity", fmt.Sprintf("%x", c.identityPublic[:])}},
cliRow{cols: []string{"Fingerprint", fmt.Sprintf("%d", c.fingerprint())}},
cliRow{cols: []string{"Public key", fmt.Sprintf("%x", c.pub[:])}},
cliRow{cols: []string{"Identity key", fmt.Sprintf("%x", c.identityPublic[:])}},
cliRow{cols: []string{"Generation", fmt.Sprintf("%d", c.generation)}},
cliRow{cols: []string{"State file", terminalEscape(c.stateFilename, false)}},
cliRow{cols: []string{"Group generation", fmt.Sprintf("%d", c.generation)}},
},
}
table.WriteTo(c.term)
Expand Down Expand Up @@ -1858,9 +1859,10 @@ func (c *cliClient) showContact(contact *Contact) {
rows: []cliRow{
cliRow{cols: []string{"Name", terminalEscape(contact.name, false)}},
cliRow{cols: []string{"Server", terminalEscape(contact.theirServer, false)}},
cliRow{cols: []string{"Generation", fmt.Sprintf("%d", contact.generation)}},
cliRow{cols: []string{"Public key", fmt.Sprintf("%x", contact.theirPub[:])}},
cliRow{cols: []string{"Fingerprint", fmt.Sprintf("%d", contact.fingerprint())}},
cliRow{cols: []string{"Identity key", fmt.Sprintf("%x", contact.theirIdentityPublic[:])}},
cliRow{cols: []string{"Public key", fmt.Sprintf("%x", contact.theirPub[:])}},
cliRow{cols: []string{"Generation", fmt.Sprintf("%d", contact.generation)}},
cliRow{cols: []string{"Client version", fmt.Sprintf("%d", contact.supportedVersion)}},
},
}
Expand Down
56 changes: 43 additions & 13 deletions client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -477,6 +477,17 @@ type Contact struct {
cliId cliId
}

func (contact *Contact) fingerprint() []byte {
if contact.isPending {
return []byte{}
}
return fingerprint(contact.theirPub[:])
}

func (c *client) fingerprint() []byte {
return fingerprint(c.pub[:])
}

// Event represents a log entry. This does not apply to the global log, which
// is quite chatty, but rather to significant events related to a given
// contact. These events are surfaced in the UI and recorded in the statefile.
Expand Down Expand Up @@ -802,11 +813,8 @@ func (c *client) loadUI() error {
copy(c.priv[:], priv[:])
copy(c.pub[:], pub[:])

if c.disableV2Ratchet {
c.randBytes(c.identity[:])
} else {
extra25519.PrivateKeyToCurve25519(&c.identity, priv)
}
// Avoid tying identity to pub to keep pub from being a selector
c.randBytes(c.identity[:])
curve25519.ScalarBaseMult(&c.identityPublic, &c.identity)

c.groupPriv, err = bbssig.GenerateGroup(rand.Reader)
Expand Down Expand Up @@ -907,6 +915,17 @@ func (contact *Contact) indicator() Indicator {
return indicatorNone
}

func (contact *Contact) ratchetVersion(disableV2Ratchet bool) int32 {
if disableV2Ratchet || contact.supportedVersion < 1 {
return 1
}
if protoVersion <= contact.supportedVersion {
return protoVersion
} else {
return contact.supportedVersion
}
}

func (contact *Contact) processKeyExchange(kxsBytes []byte, testing, simulateOldClient, disableV2Ratchet bool) error {
var kxs pond.SignedKeyExchange
if err := proto.Unmarshal(kxsBytes, &kxs); err != nil {
Expand Down Expand Up @@ -951,6 +970,11 @@ func (contact *Contact) processKeyExchange(kxsBytes []byte, testing, simulateOld
}
copy(contact.theirIdentityPublic[:], kx.IdentityPublic)

// Contact might be using the v2 ratchet if kx.SupportedVersion exists
if kx.SupportedVersion != nil {
contact.supportedVersion = *kx.SupportedVersion
}

if simulateOldClient {
kx.Dh1 = nil
}
Expand All @@ -966,12 +990,9 @@ func (contact *Contact) processKeyExchange(kxsBytes []byte, testing, simulateOld
copy(contact.theirCurrentDHPublic[:], kx.Dh)
contact.ratchet = nil
} else {
// If the identity and ed25519 public keys are the same (modulo
// isomorphism) then the contact is using the v2 ratchet.
var ed25519Public, curve25519Public [32]byte
copy(ed25519Public[:], kx.PublicKey)
extra25519.PublicKeyToCurve25519(&curve25519Public, &ed25519Public)
v2 := !disableV2Ratchet && bytes.Equal(curve25519Public[:], kx.IdentityPublic[:])
// Just leave contact.supportedVersion=0 if not specified, but maybe
// worth setting supportedVersion=1 if we've thought about it more.
v2 := (contact.ratchetVersion(disableV2Ratchet) == 2)
if err := contact.ratchet.CompleteKeyExchange(&kx, v2); err != nil {
return err
}
Expand Down Expand Up @@ -1035,11 +1056,20 @@ func (c *client) registerId(id uint64) {
}

func (c *client) newRatchet(contact *Contact) *ratchet.Ratchet {
// contact.ratchetVersion(disableV2Ratchet) == 2
r := ratchet.New(c.rand)
r.MyIdentityPrivate = &c.identity
r.MySigningPublic = &c.pub
r.TheirIdentityPublic = &contact.theirIdentityPublic
r.TheirSigningPublic = &contact.theirPub
switch contact.ratchetVersion(c.disableV2Ratchet) {
case 1:
r.MyIdentityPrivate = &c.identity
r.TheirIdentityPublic = &contact.theirIdentityPublic
case 2:
r.MyIdentityPrivate = new([32]byte)
extra25519.PrivateKeyToCurve25519(r.MyIdentityPrivate, &c.priv)
r.TheirIdentityPublic = new([32]byte)
extra25519.PublicKeyToCurve25519(r.TheirIdentityPublic, &contact.theirPub)
}
return r
}

Expand Down
8 changes: 8 additions & 0 deletions client/disk.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,14 @@ import (
"golang.org/x/crypto/curve25519"
)

//go:generate protoc --proto_path=$GOPATH/src:. --gogo_out=. disk/client.proto

// We use gogoprotobuf from https://code.google.com/p/gogoprotobuf/ because
// Francesc @Campoy indicated that even Google uses it over goprotobuf.
// See 29d5f5d16f523b0a113e786143fc4dacc8affa97 for goprotobuf scripts like :
// protoc --proto_path=$GOPATH/src:. --go_out=. disk/client.proto
// perl -p -i~ -e 's/(import protos \"github.com\/agl\/pond\/protos)\/pond.pb\"/$1\"/' disk/client.pb.go

// erasureRotationTime is the amount of time that we'll use a single erasure
// storage value before rotating.
const erasureRotationTime = 24 * time.Hour
Expand Down
Loading