Repository navigation
Expand file tree
/
Copy pathexecution_identity.go
More file actions
189 lines (176 loc) · 7.23 KB
/
Copy pathexecution_identity.go
File metadata and controls
189 lines (176 loc) · 7.23 KB
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
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
package driver
import (
"crypto/sha256"
"encoding/binary"
"errors"
"hash"
"slices"
"github.com/GiGurra/bork/internal/check"
)
const (
executionIdentityVersion = 1
executionIdentityMaxBytes = 8 << 20
executionPriorMaxCount = 4096
executionInvocationMaxCount = 4096
)
type executionDecline string
const executionClosureUnavailable executionDecline = "execution closure not certified"
// These owned primitives establish identity and invocation accounting only.
// No current() call qualifies until the execution closure collector is added.
type executionCandidate struct {
input []byte
key [sha256.Size]byte
output executionOutputIdentity
}
type executionOutputIdentity struct {
Site, Type string
Codec, Policy uint32
}
type executionReceipt struct {
input []byte
inputKey [sha256.Size]byte
output executionOutputIdentity
result []byte
valueKey [sha256.Size]byte
key [sha256.Size]byte
}
type executionPriorIdentity struct {
Site, Type string
Codec, Policy uint32
Receipt, Value [sha256.Size]byte
}
// executionIdentityData must be derived by the future collector from resolved
// selections and captured inputs. Hashes supplied by a caller never authorize
// eligibility. Bounded identity construction does not certify a candidate.
type executionIdentityData struct {
Namespace [sha256.Size]byte
Descriptor, Program []byte
Output executionOutputIdentity
Prior []executionPriorIdentity
}
func newExecutionCandidate(data executionIdentityData) (*executionCandidate, error) {
if len(data.Descriptor) > executionIdentityMaxBytes || len(data.Program) > executionIdentityMaxBytes || len(data.Output.Site) > executionIdentityMaxBytes || len(data.Output.Type) > executionIdentityMaxBytes {
return nil, errors.New("execution identity limit exceeded")
}
if len(data.Prior) > executionPriorMaxCount {
return nil, errors.New("execution prior limit exceeded")
}
// Check the complete encoding size before cloning or appending any payload.
size := 8 + sha256.Size + 8 + len(data.Descriptor) + 8 + len(data.Program) + 8 + len(data.Output.Site) + 8 + len(data.Output.Type) + 8 + 8
if size > executionIdentityMaxBytes || len(data.Output.Site)+len(data.Output.Type) > executionIdentityMaxBytes-size {
return nil, errors.New("execution identity limit exceeded")
}
for _, prior := range data.Prior {
if len(prior.Site) > executionIdentityMaxBytes || len(prior.Type) > executionIdentityMaxBytes {
return nil, errors.New("execution identity limit exceeded")
}
itemSize := 8 + len(prior.Site) + 8 + len(prior.Type) + 8 + 2*sha256.Size
if itemSize > executionIdentityMaxBytes-size-len(data.Output.Site)-len(data.Output.Type) {
return nil, errors.New("execution identity limit exceeded")
}
size += itemSize
}
if data.Output.Codec == 0 || data.Output.Policy == 0 || data.Output.Type == "" {
return nil, errors.New("missing execution output identity")
}
input := make([]byte, 0, size)
input = binary.BigEndian.AppendUint64(input, executionIdentityVersion)
input = append(input, data.Namespace[:]...)
appendBytes := func(value []byte) {
input = binary.BigEndian.AppendUint64(input, uint64(len(value)))
input = append(input, value...)
}
appendBytes(data.Descriptor)
appendBytes(data.Program)
appendBytes([]byte(data.Output.Site))
appendBytes([]byte(data.Output.Type))
input = binary.BigEndian.AppendUint32(input, data.Output.Codec)
input = binary.BigEndian.AppendUint32(input, data.Output.Policy)
input = binary.BigEndian.AppendUint64(input, uint64(len(data.Prior)))
for _, prior := range data.Prior {
appendBytes([]byte(prior.Site))
appendBytes([]byte(prior.Type))
input = binary.BigEndian.AppendUint32(input, prior.Codec)
input = binary.BigEndian.AppendUint32(input, prior.Policy)
input = append(input, prior.Receipt[:]...)
input = append(input, prior.Value[:]...)
}
return &executionCandidate{input: input, key: executionInputIdentity(input, data.Output), output: data.Output}, nil
}
func (candidate *executionCandidate) identity() [sha256.Size]byte {
if candidate == nil {
return [sha256.Size]byte{}
}
return candidate.key
}
func (candidate *executionCandidate) current() bool { return false }
func (candidate *executionCandidate) certify(_ []byte) (*executionReceipt, error) {
return nil, errors.New(string(executionClosureUnavailable))
}
func (receipt *executionReceipt) current() bool { return false }
func (receipt *executionReceipt) identity() [sha256.Size]byte {
if receipt == nil {
return [sha256.Size]byte{}
}
return receipt.key
}
func executionDigest(tag string, parts ...[]byte) [sha256.Size]byte {
h := sha256.New()
executionHashPart(h, []byte("bork-execution-identity-v1"))
executionHashPart(h, []byte(tag))
for _, part := range parts {
executionHashPart(h, part)
}
var digest [sha256.Size]byte
copy(digest[:], h.Sum(nil))
return digest
}
func executionHashPart(h hash.Hash, part []byte) {
var size [8]byte
binary.BigEndian.PutUint64(size[:], uint64(len(part)))
_, _ = h.Write(size[:])
_, _ = h.Write(part)
}
func executionInputIdentity(input []byte, output executionOutputIdentity) [sha256.Size]byte {
var versions [8]byte
binary.BigEndian.PutUint32(versions[:4], output.Codec)
binary.BigEndian.PutUint32(versions[4:], output.Policy)
return executionDigest("input", input, []byte(output.Site), []byte(output.Type), versions[:])
}
func executionValueIdentity(output executionOutputIdentity, result []byte) [sha256.Size]byte {
var versions [8]byte
binary.BigEndian.PutUint32(versions[:4], output.Codec)
binary.BigEndian.PutUint32(versions[4:], output.Policy)
return executionDigest("typed-value", []byte(output.Site), []byte(output.Type), versions[:], result)
}
func (receipt *executionReceipt) validIdentity() bool {
if receipt == nil || len(receipt.input) > executionIdentityMaxBytes || len(receipt.output.Site) > executionIdentityMaxBytes || len(receipt.output.Type) > executionIdentityMaxBytes {
return false
}
metadata := len(receipt.output.Site) + len(receipt.output.Type)
if metadata > executionIdentityMaxBytes-len(receipt.input) {
return false
}
if len(receipt.result) > check.ComptimeResultLimit || receipt.output.Type == "" || receipt.output.Codec == 0 || receipt.output.Policy == 0 {
return false
}
if receipt.inputKey != executionInputIdentity(receipt.input, receipt.output) || receipt.valueKey != executionValueIdentity(receipt.output, receipt.result) {
return false
}
return receipt.key == executionDigest("receipt", receipt.inputKey[:], receipt.valueKey[:])
}
func (receipt *executionReceipt) clone() (*executionReceipt, error) {
if !receipt.validIdentity() {
return nil, errors.New("invalid execution receipt identity")
}
owned := *receipt
owned.input = slices.Clone(receipt.input)
owned.result = slices.Clone(receipt.result)
return &owned, nil
}
func (receipt *executionReceipt) prior(site, typ string, codec, policy uint32, value [sha256.Size]byte) (executionPriorIdentity, error) {
if !receipt.validIdentity() || receipt.output != (executionOutputIdentity{Site: site, Type: typ, Codec: codec, Policy: policy}) || value != receipt.valueKey {
return executionPriorIdentity{}, errors.New("execution prior identity mismatch")
}
return executionPriorIdentity{Site: site, Type: typ, Codec: codec, Policy: policy, Receipt: receipt.key, Value: value}, nil
}