blob: 5c0a7b2e05d0f2a33ff4f82015eb6fe60be07287 [file] [log] [blame]
Jiri Simsad7616c92015-03-24 23:44:30 -07001// Copyright 2015 The Vanadium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
Asim Shankarae8d4c52014-10-08 13:03:31 -07005package security
Ankur100eb272014-09-15 16:48:12 -07006
7import (
Ankur1615a7d2014-10-09 11:58:02 -07008 "bytes"
Ankur1615a7d2014-10-09 11:58:02 -07009 "fmt"
Asim Shankarf11b1bc2014-11-12 17:18:45 -080010 "sort"
Ankur100eb272014-09-15 16:48:12 -070011 "sync"
12
Jiri Simsa6ac95222015-02-23 16:11:49 -080013 "v.io/v23/security"
Mike Burrows7f7088d2015-03-25 13:05:00 -070014 "v.io/v23/verror"
Ankur9e5b7722015-04-28 15:00:25 -070015 "v.io/x/lib/vlog"
Todd Wangb3511492015-04-07 23:32:34 -070016 "v.io/x/ref/lib/security/serialization"
Ankur100eb272014-09-15 16:48:12 -070017)
18
Ankur344bbdf2015-05-07 18:26:15 -070019var errRootsAddPattern = verror.Register(pkgPath+".errRootsAddPattern", verror.NoRetry, "{1:}{2:} a root cannot be recognized for all blessing names (i.e., the pattern '...')")
20
Ankur100eb272014-09-15 16:48:12 -070021// blessingRoots implements security.BlessingRoots.
22type blessingRoots struct {
gauthamt1e313bc2014-11-10 15:45:56 -080023 persistedData SerializerReaderWriter
24 signer serialization.Signer
25 mu sync.RWMutex
Ankurcc043852015-04-14 13:10:28 -070026 state blessingRootsState // GUARDED_BY(mu)
Ankur100eb272014-09-15 16:48:12 -070027}
28
Ankurcc043852015-04-14 13:10:28 -070029func stateMapKey(root security.PublicKey) (string, error) {
Ankur100eb272014-09-15 16:48:12 -070030 rootBytes, err := root.MarshalBinary()
31 if err != nil {
32 return "", err
33 }
Ankur1615a7d2014-10-09 11:58:02 -070034 return string(rootBytes), nil
Ankur100eb272014-09-15 16:48:12 -070035}
36
37func (br *blessingRoots) Add(root security.PublicKey, pattern security.BlessingPattern) error {
Ankur344bbdf2015-05-07 18:26:15 -070038 if pattern == security.AllPrincipals {
39 return verror.New(errRootsAddPattern, nil)
40 }
Ankurcc043852015-04-14 13:10:28 -070041 key, err := stateMapKey(root)
Ankur100eb272014-09-15 16:48:12 -070042 if err != nil {
43 return err
44 }
45
46 br.mu.Lock()
47 defer br.mu.Unlock()
Ankurcc043852015-04-14 13:10:28 -070048 patterns := br.state[key]
Ankur100eb272014-09-15 16:48:12 -070049 for _, p := range patterns {
50 if p == pattern {
51 return nil
52 }
53 }
Ankurcc043852015-04-14 13:10:28 -070054 br.state[key] = append(patterns, pattern)
Ankur100eb272014-09-15 16:48:12 -070055
56 if err := br.save(); err != nil {
Ankurcc043852015-04-14 13:10:28 -070057 br.state[key] = patterns[:len(patterns)-1]
Ankur100eb272014-09-15 16:48:12 -070058 return err
59 }
Ankur9e5b7722015-04-28 15:00:25 -070060
Ankur100eb272014-09-15 16:48:12 -070061 return nil
62}
63
64func (br *blessingRoots) Recognized(root security.PublicKey, blessing string) error {
Ankurcc043852015-04-14 13:10:28 -070065 key, err := stateMapKey(root)
Ankur100eb272014-09-15 16:48:12 -070066 if err != nil {
67 return err
68 }
69
70 br.mu.RLock()
71 defer br.mu.RUnlock()
Ankurcc043852015-04-14 13:10:28 -070072 for _, p := range br.state[key] {
Ankur100eb272014-09-15 16:48:12 -070073 if p.MatchedBy(blessing) {
74 return nil
75 }
76 }
Asim Shankar3c134af2015-03-23 19:41:31 -070077 return security.NewErrUnrecognizedRoot(nil, root.String(), nil)
Ankur100eb272014-09-15 16:48:12 -070078}
79
Ankur9e5b7722015-04-28 15:00:25 -070080func (br *blessingRoots) Dump() map[security.BlessingPattern][]security.PublicKey {
81 dump := make(map[security.BlessingPattern][]security.PublicKey)
82 br.mu.RLock()
83 defer br.mu.RUnlock()
84 for keyStr, patterns := range br.state {
85 key, err := security.UnmarshalPublicKey([]byte(keyStr))
86 if err != nil {
87 vlog.Errorf("security.UnmarshalPublicKey(%v) returned error: %v", []byte(keyStr), err)
88 return nil
89 }
90 for _, p := range patterns {
91 dump[p] = append(dump[p], key)
92 }
93 }
94 return dump
95}
96
Ankur1615a7d2014-10-09 11:58:02 -070097// DebugString return a human-readable string encoding of the roots
98// DebugString encodes all roots into a string in the following
99// format
100//
Suharsh Sivakumar4bbe8ed2015-04-09 14:21:44 -0700101// Public key Pattern
102// <public key> <patterns>
Ankur1615a7d2014-10-09 11:58:02 -0700103// ...
Suharsh Sivakumar4bbe8ed2015-04-09 14:21:44 -0700104// <public key> <patterns>
Ankur1615a7d2014-10-09 11:58:02 -0700105func (br *blessingRoots) DebugString() string {
Suharsh Sivakumar4bbe8ed2015-04-09 14:21:44 -0700106 const format = "%-47s %s\n"
Ankur1615a7d2014-10-09 11:58:02 -0700107 b := bytes.NewBufferString(fmt.Sprintf(format, "Public key", "Pattern"))
Asim Shankarf11b1bc2014-11-12 17:18:45 -0800108 var s rootSorter
Ankurcc043852015-04-14 13:10:28 -0700109 for keyBytes, patterns := range br.state {
Ankur1615a7d2014-10-09 11:58:02 -0700110 key, err := security.UnmarshalPublicKey([]byte(keyBytes))
111 if err != nil {
112 return fmt.Sprintf("failed to decode public key: %v", err)
113 }
Asim Shankarf11b1bc2014-11-12 17:18:45 -0800114 s = append(s, &root{key, fmt.Sprintf("%v", patterns)})
115 }
116 sort.Sort(s)
117 for _, r := range s {
118 b.WriteString(fmt.Sprintf(format, r.key, r.patterns))
Ankur1615a7d2014-10-09 11:58:02 -0700119 }
120 return b.String()
121}
122
Asim Shankarf11b1bc2014-11-12 17:18:45 -0800123type root struct {
124 key security.PublicKey
125 patterns string
126}
127
128type rootSorter []*root
129
130func (s rootSorter) Len() int { return len(s) }
131func (s rootSorter) Less(i, j int) bool { return s[i].patterns < s[j].patterns }
132func (s rootSorter) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
133
Ankur100eb272014-09-15 16:48:12 -0700134func (br *blessingRoots) save() error {
gauthamt1e313bc2014-11-10 15:45:56 -0800135 if (br.signer == nil) && (br.persistedData == nil) {
Ankur100eb272014-09-15 16:48:12 -0700136 return nil
137 }
gauthamt1e313bc2014-11-10 15:45:56 -0800138 data, signature, err := br.persistedData.Writers()
139 if err != nil {
140 return err
141 }
Ankurcc043852015-04-14 13:10:28 -0700142 return encodeAndStore(br.state, data, signature, br.signer)
Ankur100eb272014-09-15 16:48:12 -0700143}
144
Ankur7c890592014-10-02 11:36:28 -0700145// newInMemoryBlessingRoots returns an in-memory security.BlessingRoots.
Ankur100eb272014-09-15 16:48:12 -0700146//
147// The returned BlessingRoots is initialized with an empty set of keys.
Ankur7c890592014-10-02 11:36:28 -0700148func newInMemoryBlessingRoots() security.BlessingRoots {
Ankur100eb272014-09-15 16:48:12 -0700149 return &blessingRoots{
Ankurcc043852015-04-14 13:10:28 -0700150 state: make(blessingRootsState),
Ankur100eb272014-09-15 16:48:12 -0700151 }
152}
153
gauthamt1e313bc2014-11-10 15:45:56 -0800154// newPersistingBlessingRoots returns a security.BlessingRoots for a principal
155// that is initialized with the persisted data. The returned security.BlessingRoots
156// also persists any updates to its state.
157func newPersistingBlessingRoots(persistedData SerializerReaderWriter, signer serialization.Signer) (security.BlessingRoots, error) {
158 if persistedData == nil || signer == nil {
Mike Burrows7f7088d2015-03-25 13:05:00 -0700159 return nil, verror.New(errDataOrSignerUnspecified, nil)
Ankur100eb272014-09-15 16:48:12 -0700160 }
161 br := &blessingRoots{
Ankurcc043852015-04-14 13:10:28 -0700162 state: make(blessingRootsState),
gauthamt1e313bc2014-11-10 15:45:56 -0800163 persistedData: persistedData,
164 signer: signer,
Ankur100eb272014-09-15 16:48:12 -0700165 }
gauthamt1e313bc2014-11-10 15:45:56 -0800166 data, signature, err := br.persistedData.Readers()
167 if err != nil {
Ankur100eb272014-09-15 16:48:12 -0700168 return nil, err
169 }
gauthamt1e313bc2014-11-10 15:45:56 -0800170 if (data != nil) && (signature != nil) {
Ankurcc043852015-04-14 13:10:28 -0700171 if err := decodeFromStorage(&br.state, data, signature, br.signer.PublicKey()); err != nil {
gauthamt1e313bc2014-11-10 15:45:56 -0800172 return nil, err
173 }
174 }
Ankur100eb272014-09-15 16:48:12 -0700175 return br, nil
176}