-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathentry.go
149 lines (119 loc) · 3.48 KB
/
entry.go
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
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
package esni
import (
"encoding/binary"
"encoding/hex"
"fmt"
"io"
"strings"
"github.com/pkg/errors"
)
// KeyShareEntry represents a public key
// of a specific type presented as supported
// by the server for the purpose of encrypting
// an SNI
type KeyShareEntry struct {
// Group specifies the encryption type
// of the public key
Group Group
// KeyExchange represents the bytes of
// the public key
KeyExchange []byte
}
// Size returns the number of bytes that the
// entry would produce when marshaled to a binary
// format
func (entry KeyShareEntry) Size() uint16 {
return uint16(len(entry.KeyExchange)) + 4
}
// MarshalBinary will marshal the entry into
// a binary format to be included in a list of
// supported keys
func (entry KeyShareEntry) MarshalBinary() ([]byte, error) {
data := make([]byte, entry.Size())
binary.BigEndian.PutUint16(data[0:2], uint16(entry.Group))
binary.BigEndian.PutUint16(data[2:4], uint16(len(entry.KeyExchange)))
copy(data[4:], entry.KeyExchange)
return data, nil
}
// UnmarshalBinary will attempt to unmarshal
// a key share entry from the provided binary
// data
func (entry *KeyShareEntry) UnmarshalBinary(data []byte) error {
if len(data) < 4 {
return errors.Wrap(io.ErrUnexpectedEOF, "buffer is too small for key share entry")
}
entry.Group = Group(binary.BigEndian.Uint16(data[:2]))
keyLen := binary.BigEndian.Uint16(data[2:])
if len(data) < int(keyLen)+4 {
return errors.Wrap(io.ErrUnexpectedEOF, "buffer is too small for key exchange")
}
entry.KeyExchange = make([]byte, keyLen)
copy(entry.KeyExchange, data[4:keyLen+4])
return nil
}
// KeyShareEntryList represents a list of
// individual public keys that belong to
// unique key types
type KeyShareEntryList []KeyShareEntry
// Size returns the number of bytes that would
// be produced if the list was to be marshaled to
// a binary format
func (list KeyShareEntryList) Size() (size uint16) {
for i := range list {
size += list[i].Size()
}
return
}
func (list KeyShareEntryList) String() string {
var builder strings.Builder
builder.WriteString("[")
for i := range list {
if i > 0 {
builder.WriteString(", ")
}
_, _ = fmt.Fprintf(&builder, "{Group:%s, Value:%s}", list[i].Group, hex.EncodeToString(list[i].KeyExchange))
}
builder.WriteString("]")
return builder.String()
}
// Contains checks if the list already contains
// a key share entry with the same group type
func (list KeyShareEntryList) Contains(entry KeyShareEntry) bool {
for i := range list {
if list[i].Group == entry.Group {
return true
}
}
return false
}
// MarshalBinary attempts to marshal the list of
// key share entries into a binary format for inclusion
// in a ESNI keys record
func (list KeyShareEntryList) MarshalBinary() ([]byte, error) {
data := make([]byte, list.Size())
var pos int
for i := range list {
entry, err := list[i].MarshalBinary()
if err != nil {
return nil, errors.Wrap(err, "marshal key share entry")
}
pos += copy(data[pos:], entry)
}
return data, nil
}
// UnmarshalBinary attempts to unmarshal a list of
// key share entries from the provided binary data
func (list *KeyShareEntryList) UnmarshalBinary(data []byte) error {
for pos := 0; pos < len(data); {
entry := KeyShareEntry{}
if err := entry.UnmarshalBinary(data[pos:]); err != nil {
return errors.Wrap(err, "unmarshal key share entry")
}
if list.Contains(entry) {
return errors.New("duplicate key share group")
}
pos += int(entry.Size()) + 1
*list = append(*list, entry)
}
return nil
}