blob: 912536eecb7253d08e9b797bbc6f06e6323e16c1 [file] [log] [blame]
Asim Shankare5de89e2014-06-01 17:43:21 -07001package security
2
3import (
4 "crypto/ecdsa"
5 "errors"
6 "fmt"
7 "reflect"
8 "strings"
9 "time"
10
11 "veyron2/security"
12 "veyron2/vom"
13)
14
15type setPublicID []security.PublicID
16
17var (
18 errEmptySet = errors.New("suspected manipulation of identity: empty set")
19 errSingleElementSet = errors.New("suspected manipulation of identity: single element set")
20 errNoNilsInSet = errors.New("suspected manipulation of identity: nil element in set")
21 errMismatchedKeys = errors.New("mismatched keys in elements of set")
22)
23
24// NewSetPublicID returns a security.PublicID containing the combined credentials of ids.
25// It requires that all elements of ids have the same public key.
26func NewSetPublicID(ids ...security.PublicID) (security.PublicID, error) {
27 // All public keys must match
28 switch len(ids) {
29 case 0:
30 return nil, nil
31 case 1:
32 return ids[0], nil
33 default:
34 for i := 1; i < len(ids); i++ {
35 if !reflect.DeepEqual(ids[0].PublicKey(), ids[i].PublicKey()) {
36 return nil, errMismatchedKeys
37 }
38 }
39 set := setPublicID(ids)
40 return &set, nil
41 }
42}
43
44func (s *setPublicID) Names() []string {
45 names := make([]string, 0, len(*s))
46 for _, id := range *s {
47 names = append(names, id.Names()...)
48 }
49 if len(names) == 0 {
50 return nil
51 }
52 return names
53}
54
Asim Shankare5de89e2014-06-01 17:43:21 -070055func (s *setPublicID) PublicKey() *ecdsa.PublicKey {
56 return (*s)[0].PublicKey()
57}
58
59func (s *setPublicID) Authorize(context security.Context) (security.PublicID, error) {
60 var authids []security.PublicID
61 var errs []error
62 for _, id := range *s {
63 if aid, err := id.Authorize(context); err != nil && len(authids) == 0 {
64 errs = append(errs, err)
65 } else if aid != nil {
66 authids = append(authids, aid)
67 }
68 }
69 if len(authids) == 0 {
70 return nil, joinerrs(errs)
71 }
72 return NewSetPublicID(authids...)
73}
74
75func (s *setPublicID) ThirdPartyCaveats() []security.ServiceCaveat {
76 set := make(map[security.ThirdPartyCaveatID]security.ServiceCaveat)
77 for _, id := range *s {
78 for _, c := range id.ThirdPartyCaveats() {
79 if tp, ok := c.Caveat.(security.ThirdPartyCaveat); ok {
80 set[tp.ID()] = c
81 }
82 // else { This should not be possible! }
83 }
84 }
85 if len(set) == 0 {
86 return nil
87 }
88 ret := make([]security.ServiceCaveat, 0, len(set))
89 for _, c := range set {
90 ret = append(ret, c)
91 }
92 return ret
93}
94
95func (s *setPublicID) String() string {
96 strs := make([]string, len(*s))
97 for ix, id := range *s {
98 strs[ix] = fmt.Sprintf("%v", id)
99 }
100 return strings.Join(strs, "#")
101}
102
103func (s *setPublicID) VomEncode() ([]security.PublicID, error) {
104 return []security.PublicID(*s), nil
105}
106
107func (s *setPublicID) VomDecode(ids []security.PublicID) error {
108 switch len(ids) {
109 case 0:
110 return errEmptySet
111 case 1:
112 return errSingleElementSet
113 }
114 if ids[0] == nil {
115 return errNoNilsInSet
116 }
117 for i := 1; i < len(ids); i++ {
118 if ids[i] == nil {
119 return errNoNilsInSet
120 }
121 if !reflect.DeepEqual(ids[0].PublicKey(), ids[i].PublicKey()) {
122 return errMismatchedKeys
123 }
124 }
125 *s = setPublicID(ids)
126 return nil
127}
128
129type setPrivateID []security.PrivateID
130
131// NewSetPrivateID returns a security.PrivateID contiaining the combined credentials of ids.
132// It requires that all ids have the same private key.
133func NewSetPrivateID(ids ...security.PrivateID) (security.PrivateID, error) {
134 switch len(ids) {
135 case 0:
136 return nil, nil
137 case 1:
138 return ids[0], nil
139 default:
Asim Shankarb38d0362014-06-11 12:47:46 -0700140 pub := ids[0].PublicID().PublicKey()
Asim Shankare5de89e2014-06-01 17:43:21 -0700141 for i := 1; i < len(ids); i++ {
Asim Shankarb38d0362014-06-11 12:47:46 -0700142 if !reflect.DeepEqual(pub, ids[i].PublicID().PublicKey()) {
Asim Shankare5de89e2014-06-01 17:43:21 -0700143 return nil, errMismatchedKeys
144 }
145 }
146 return setPrivateID(ids), nil
147 }
148}
149
150func (s setPrivateID) PublicID() security.PublicID {
151 pubs := make([]security.PublicID, len(s))
152 for ix, id := range s {
153 pubs[ix] = id.PublicID()
154 }
155 set := setPublicID(pubs)
156 return &set
157}
158
Asim Shankarb38d0362014-06-11 12:47:46 -0700159func (s setPrivateID) Sign(message []byte) (security.Signature, error) { return s[0].Sign(message) }
Asim Shankare5de89e2014-06-01 17:43:21 -0700160
Srdjan Petrovic4b0dfa02014-07-25 14:13:56 -0700161func (s setPrivateID) PublicKey() *ecdsa.PublicKey { return s[0].PublicKey() }
162
Asim Shankare5de89e2014-06-01 17:43:21 -0700163func (s setPrivateID) Bless(blessee security.PublicID, blessingName string, duration time.Duration, caveats []security.ServiceCaveat) (security.PublicID, error) {
164 pubs := make([]security.PublicID, len(s))
165 for ix, id := range s {
166 var err error
167 if pubs[ix], err = id.Bless(blessee, blessingName, duration, caveats); err != nil {
168 return nil, err
169 }
170 }
171 return NewSetPublicID(pubs...)
172}
173
174func (s setPrivateID) Derive(pub security.PublicID) (security.PrivateID, error) {
Asim Shankare5de89e2014-06-01 17:43:21 -0700175 switch p := pub.(type) {
176 case *chainPublicID:
177 return s[0].Derive(p)
178 case *setPublicID:
179 privs := make([]security.PrivateID, len(*p))
Asim Shankarb38d0362014-06-11 12:47:46 -0700180 var err error
Asim Shankare5de89e2014-06-01 17:43:21 -0700181 for ix, ip := range *p {
182 if privs[ix], err = s.Derive(ip); err != nil {
183 return nil, fmt.Errorf("Derive failed for %d of %d id in set", ix, len(*p))
184 }
185 }
186 return setPrivateID(privs), nil
187 default:
188 return nil, fmt.Errorf("PrivateID of type %T cannot be used to Derive from PublicID of type %T", s, pub)
189 }
190}
191
Andres Erbsendde52bf2014-06-09 09:42:33 -0700192func (s setPrivateID) MintDischarge(cav security.ThirdPartyCaveat, ctx security.Context, duration time.Duration, dischargeCaveats []security.ServiceCaveat) (security.ThirdPartyDischarge, error) {
Asim Shankare5de89e2014-06-01 17:43:21 -0700193 for _, id := range s {
Andres Erbsendde52bf2014-06-09 09:42:33 -0700194 if d, err := id.MintDischarge(cav, ctx, duration, dischargeCaveats); err == nil {
Asim Shankare5de89e2014-06-01 17:43:21 -0700195 return d, nil
196 }
197 }
198 return nil, fmt.Errorf("discharge cannot be constructed for %T from %T", cav, s)
199}
200
201func joinerrs(errs []error) error {
202 switch len(errs) {
203 case 0:
204 return nil
205 case 1:
206 return errs[0]
207 }
208 strs := make([]string, len(errs))
209 for i, err := range errs {
210 strs[i] = err.Error()
211 }
212 return fmt.Errorf("none of the blessings in the set are authorized: %v", strings.Join(strs, ", "))
213}
214
215func init() {
216 vom.Register(setPrivateID(nil))
217 vom.Register(setPublicID(nil))
218}