-
Notifications
You must be signed in to change notification settings - Fork 0
/
submods.go
139 lines (107 loc) · 2.97 KB
/
submods.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
// Copyright 2020 Contributors to the Veraison project.
// SPDX-License-Identifier: Apache-2.0
package eat
import (
"bytes"
"encoding/base64"
"encoding/json"
"errors"
)
// Submod is the type of a submod: either a raw EAT (wrapped in a Sign1 CWT), or
// a map of EAT claims
type Submod struct{ value interface{} }
// MarshalJSON encodes the submod value wrapped in the Submod receiver to JSON
func (s Submod) MarshalJSON() ([]byte, error) {
return json.Marshal(s.value)
}
// MarshalCBOR encodes the submod value wrapped in the Submod receiver to CBOR
func (s Submod) MarshalCBOR() ([]byte, error) {
return em.Marshal(s.value)
}
// UnmarshalJSON attempts to decode the supplied JSON data into the Submod
// receiver, peeking into the stream to choose between one of the two target
// formats (i.e., eat-token or eat-claims)
func (s *Submod) UnmarshalJSON(data []byte) error {
if data[0] == '{' { // eat-claims
var eatClaims Eat
if err := eatClaims.FromJSON(data); err != nil {
return err
}
s.value = eatClaims
return nil
}
// eat-token
b64 := string(data[1 : len(data)-1]) // remove quotes
eatToken, err := base64.StdEncoding.DecodeString(b64)
if err != nil {
return err
}
if err := s.setEatToken(eatToken); err != nil {
return err
}
return nil
}
func (s *Submod) setEatToken(data []byte) error {
if err := checkTags(data); err != nil {
return err
}
s.value = data
return nil
}
// UnmarshalCBOR attempts to decode the supplied CBOR data into the Submod
// receiver, peeking into the stream to choose between one of the two target
// formats (i.e., eat-token or eat-claims)
func (s *Submod) UnmarshalCBOR(data []byte) error {
if isCBORByteString(data) {
var eatToken []byte
if err := dm.Unmarshal(data, &eatToken); err != nil {
return err
}
if err := s.setEatToken(eatToken); err != nil {
return err
}
return nil
}
var eatClaims Eat
if err := eatClaims.FromCBOR(data); err != nil {
return err
}
s.value = eatClaims
return nil
}
func checkTags(data []byte) error {
// d8 3d # tag(61) -- CWT
// d2 # tag(18) -- Sign1
prefix := []byte{0xd8, 0x3d, 0xd2}
if len(data) < len(prefix)+1 {
return errors.New("not enough bytes")
}
if !bytes.HasPrefix(data, prefix) {
return errors.New("CWT and COSE Sign1 tags not found")
}
return nil
}
// Submods models the submods type
type Submods map[string]Submod
// Get retrieves a submod by name (either int64 or string)
func (s Submods) Get(name string) interface{} {
return s[name].value
}
// Add inserts the named submod in the Submods container. The supplied name must
// be of type string or int64
func (s *Submods) Add(name string, submod interface{}) error {
switch t := submod.(type) {
case Eat: // OK as-is
case []byte: // make sure that the wrapping tags are in the right place
if err := checkTags(t); err != nil {
return err
}
default:
return errors.New("submod must be Eat or []byte")
}
if *s == nil {
*s = make(Submods)
}
(*s)[name] = Submod{submod}
return nil
}