forked from cmars/macaroon
-
Notifications
You must be signed in to change notification settings - Fork 0
/
packet.go
143 lines (128 loc) · 3.44 KB
/
packet.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
package macaroon
import (
"bytes"
"fmt"
)
// The macaroon binary encoding is made from a sequence
// of "packets", each of which has a field name and some data.
// The encoding is:
//
// - four ascii hex digits holding the entire packet size (including
// the digits themselves).
//
// - the field name, followed by an ascii space.
//
// - the raw data
//
// For efficiency, we store all the packets inside
// a single byte slice inside the macaroon, Macaroon.data. This
// is reasonable to do because we only ever append
// to macaroons.
//
// The packet struct below holds a reference into Macaroon.data.
type packet struct {
start int32
totalLen uint16
headerLen uint16
}
func (p packet) len() int {
return int(p.totalLen)
}
// dataBytes returns the data payload of the packet.
func (m *Macaroon) dataBytes(p packet) []byte {
return m.data[p.start+int32(p.headerLen) : p.start+int32(p.totalLen)]
}
func (m *Macaroon) dataStr(p packet) string {
return string(m.dataBytes(p))
}
// packetBytes returns the entire packet.
func (m *Macaroon) packetBytes(p packet) []byte {
return m.data[p.start : p.start+int32(p.totalLen)]
}
// fieldName returns the field name of the packet.
func (m *Macaroon) fieldName(p packet) []byte {
if p.totalLen == 0 {
return nil
}
return m.data[p.start+4 : p.start+int32(p.headerLen)-1]
}
// parsePacket parses the packet starting at the given
// index into m.data.
func (m *Macaroon) parsePacket(start int) (packet, error) {
data := m.data[start:]
if len(data) < 6 {
return packet{}, fmt.Errorf("packet too short")
}
plen, ok := parseSize(data)
if !ok {
return packet{}, fmt.Errorf("cannot parse size")
}
if plen > len(data) {
return packet{}, fmt.Errorf("packet size too big")
}
data = data[4:plen]
i := bytes.IndexByte(data, ' ')
if i <= 0 {
return packet{}, fmt.Errorf("cannot parse field name")
}
return packet{
start: int32(start),
totalLen: uint16(plen),
headerLen: uint16(4 + i + 1),
}, nil
}
const maxPacketLen = 0xffff
// appendPacket appends a packet with the given field name
// and data to m.data, and returns the packet appended.
//
// It returns false (and a zero packet) if the packet was too big.
func (m *Macaroon) appendPacket(field string, data []byte) (packet, bool) {
mdata, p, ok := rawAppendPacket(m.data, field, data)
if !ok {
return p, false
}
m.data = mdata
return p, true
}
// rawAppendPacket appends a packet to the given byte slice.
func rawAppendPacket(buf []byte, field string, data []byte) ([]byte, packet, bool) {
plen := 4 + len(field) + 1 + len(data)
if plen > maxPacketLen {
return nil, packet{}, false
}
s := packet{
start: int32(len(buf)),
totalLen: uint16(plen),
headerLen: uint16(4 + len(field) + 1),
}
buf = appendSize(buf, plen)
buf = append(buf, field...)
buf = append(buf, ' ')
buf = append(buf, data...)
return buf, s, true
}
var hexDigits = []byte("0123456789abcdef")
func appendSize(data []byte, size int) []byte {
return append(data,
hexDigits[size>>12],
hexDigits[(size>>8)&0xf],
hexDigits[(size>>4)&0xf],
hexDigits[size&0xf],
)
}
func parseSize(data []byte) (int, bool) {
d0, ok0 := asciiHex(data[0])
d1, ok1 := asciiHex(data[1])
d2, ok2 := asciiHex(data[2])
d3, ok3 := asciiHex(data[3])
return d0<<12 + d1<<8 + d2<<4 + d3, ok0 && ok1 && ok2 && ok3
}
func asciiHex(b byte) (int, bool) {
switch {
case b >= '0' && b <= '9':
return int(b) - '0', true
case b >= 'a' && b <= 'f':
return int(b) - 'a' + 0xa, true
}
return 0, false
}