File: version.go

package info (click to toggle)
golang-github-twstrike-otr3 0.0~git20161015.0.744856d-3.1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, bullseye, forky, sid, trixie
  • size: 1,080 kB
  • sloc: ansic: 127; makefile: 76
file content (110 lines) | stat: -rw-r--r-- 2,468 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
package otr3

import (
	"bytes"
	"errors"
	"hash"
	"math/big"
)

type otrVersion interface {
	protocolVersion() uint16
	parameterLength() int
	isGroupElement(n *big.Int) bool
	isFragmented(data []byte) bool
	parseFragmentPrefix(c *Conversation, data []byte) (rest []byte, ignore bool, ok bool)
	fragmentPrefix(n, total int, itags uint32, itagr uint32) []byte
	whitespaceTag() []byte
	messageHeader(c *Conversation, msgType byte) ([]byte, error)
	parseMessageHeader(c *Conversation, msg []byte) ([]byte, []byte, error)
	hash([]byte) []byte
	hashInstance() hash.Hash
	hashLength() int
	hash2([]byte) []byte
	hash2Instance() hash.Hash
	hash2Length() int
	truncateLength() int
	keyLength() int
}

func newOtrVersion(v uint16, p policies) (version otrVersion, err error) {
	toCheck := policy(0)
	switch v {
	case 2:
		version = otrV2{}
		toCheck = allowV2
	case 3:
		version = otrV3{}
		toCheck = allowV3
	default:
		return nil, errUnsupportedOTRVersion
	}
	if !p.has(toCheck) {
		return nil, errInvalidVersion
	}
	return
}

func versionFromFragment(fragment []byte) uint16 {
	var messageVersion uint16

	switch {
	case bytes.HasPrefix(fragment, otrv3FragmentationPrefix):
		messageVersion = 3
	case bytes.HasPrefix(fragment, otrv2FragmentationPrefix):
		messageVersion = 2
	}

	return messageVersion
}

func (c *Conversation) checkVersion(message []byte) (err error) {
	_, messageVersion, ok := extractShort(message)
	if !ok {
		return errInvalidOTRMessage
	}

	versions := 1 << messageVersion
	if err := c.commitToVersionFrom(versions); err != nil {
		return err
	}

	if c.version.protocolVersion() != messageVersion {
		return errWrongProtocolVersion
	}

	return nil
}

// Based on the policy, commit to a version given a set of versions offered by the other peer unless the conversation has already committed to a version.
func (c *Conversation) commitToVersionFrom(versions int) error {
	if c.version != nil {
		return nil
	}

	var version otrVersion

	switch {
	case c.Policies.has(allowV3) && versions&(1<<3) > 0:
		version = otrV3{}
	case c.Policies.has(allowV2) && versions&(1<<2) > 0:
		version = otrV2{}
	default:
		return errUnsupportedOTRVersion
	}

	c.version = version

	return c.setKeyMatchingVersion()
}

func (c *Conversation) setKeyMatchingVersion() error {
	for _, k := range c.ourKeys {
		if k.IsAvailableForVersion(c.version.protocolVersion()) {
			c.ourCurrentKey = k
			return nil
		}
	}

	return errors.New("no possible key for current version")
}