blob: a0b60eec2a70604073654725f95a335625aee80d [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
Asim Shankar6eba9862015-09-03 01:07:14 -040029func (br *blessingRoots) Add(root []byte, pattern security.BlessingPattern) error {
Ankur344bbdf2015-05-07 18:26:15 -070030 if pattern == security.AllPrincipals {
31 return verror.New(errRootsAddPattern, nil)
32 }
Asim Shankar6eba9862015-09-03 01:07:14 -040033 // Sanity check to avoid invalid keys being added.
34 if _, err := security.UnmarshalPublicKey(root); err != nil {
Ankur100eb272014-09-15 16:48:12 -070035 return err
36 }
Asim Shankar6eba9862015-09-03 01:07:14 -040037 key := string(root)
Ankur100eb272014-09-15 16:48:12 -070038 br.mu.Lock()
39 defer br.mu.Unlock()
Ankurcc043852015-04-14 13:10:28 -070040 patterns := br.state[key]
Ankur100eb272014-09-15 16:48:12 -070041 for _, p := range patterns {
42 if p == pattern {
43 return nil
44 }
45 }
Ankurcc043852015-04-14 13:10:28 -070046 br.state[key] = append(patterns, pattern)
Ankur100eb272014-09-15 16:48:12 -070047
48 if err := br.save(); err != nil {
Ankurcc043852015-04-14 13:10:28 -070049 br.state[key] = patterns[:len(patterns)-1]
Ankur100eb272014-09-15 16:48:12 -070050 return err
51 }
Ankur9e5b7722015-04-28 15:00:25 -070052
Ankur100eb272014-09-15 16:48:12 -070053 return nil
54}
55
Asim Shankar6eba9862015-09-03 01:07:14 -040056func (br *blessingRoots) Recognized(root []byte, blessing string) error {
57 key := string(root)
Ankur100eb272014-09-15 16:48:12 -070058 br.mu.RLock()
Ankurcc043852015-04-14 13:10:28 -070059 for _, p := range br.state[key] {
Ankur100eb272014-09-15 16:48:12 -070060 if p.MatchedBy(blessing) {
Asim Shankar6eba9862015-09-03 01:07:14 -040061 br.mu.RUnlock()
Ankur100eb272014-09-15 16:48:12 -070062 return nil
63 }
64 }
Asim Shankar6eba9862015-09-03 01:07:14 -040065 br.mu.RUnlock()
66 // Silly to have to unmarshal the public key on an error.
67 // Change the error message to not require that?
68 obj, err := security.UnmarshalPublicKey(root)
69 if err != nil {
70 return err
71 }
72 return security.NewErrUnrecognizedRoot(nil, obj.String(), nil)
Ankur100eb272014-09-15 16:48:12 -070073}
74
Ankur9e5b7722015-04-28 15:00:25 -070075func (br *blessingRoots) Dump() map[security.BlessingPattern][]security.PublicKey {
76 dump := make(map[security.BlessingPattern][]security.PublicKey)
77 br.mu.RLock()
78 defer br.mu.RUnlock()
79 for keyStr, patterns := range br.state {
80 key, err := security.UnmarshalPublicKey([]byte(keyStr))
81 if err != nil {
82 vlog.Errorf("security.UnmarshalPublicKey(%v) returned error: %v", []byte(keyStr), err)
83 return nil
84 }
85 for _, p := range patterns {
86 dump[p] = append(dump[p], key)
87 }
88 }
89 return dump
90}
91
Ankur1615a7d2014-10-09 11:58:02 -070092// DebugString return a human-readable string encoding of the roots
93// DebugString encodes all roots into a string in the following
94// format
95//
Suharsh Sivakumar4bbe8ed2015-04-09 14:21:44 -070096// Public key Pattern
97// <public key> <patterns>
Ankur1615a7d2014-10-09 11:58:02 -070098// ...
Suharsh Sivakumar4bbe8ed2015-04-09 14:21:44 -070099// <public key> <patterns>
Ankur1615a7d2014-10-09 11:58:02 -0700100func (br *blessingRoots) DebugString() string {
Suharsh Sivakumar4bbe8ed2015-04-09 14:21:44 -0700101 const format = "%-47s %s\n"
Ankur1615a7d2014-10-09 11:58:02 -0700102 b := bytes.NewBufferString(fmt.Sprintf(format, "Public key", "Pattern"))
Asim Shankarf11b1bc2014-11-12 17:18:45 -0800103 var s rootSorter
Ankurcc043852015-04-14 13:10:28 -0700104 for keyBytes, patterns := range br.state {
Ankur1615a7d2014-10-09 11:58:02 -0700105 key, err := security.UnmarshalPublicKey([]byte(keyBytes))
106 if err != nil {
107 return fmt.Sprintf("failed to decode public key: %v", err)
108 }
Asim Shankarf11b1bc2014-11-12 17:18:45 -0800109 s = append(s, &root{key, fmt.Sprintf("%v", patterns)})
110 }
111 sort.Sort(s)
112 for _, r := range s {
113 b.WriteString(fmt.Sprintf(format, r.key, r.patterns))
Ankur1615a7d2014-10-09 11:58:02 -0700114 }
115 return b.String()
116}
117
Asim Shankarf11b1bc2014-11-12 17:18:45 -0800118type root struct {
119 key security.PublicKey
120 patterns string
121}
122
123type rootSorter []*root
124
125func (s rootSorter) Len() int { return len(s) }
126func (s rootSorter) Less(i, j int) bool { return s[i].patterns < s[j].patterns }
127func (s rootSorter) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
128
Ankur100eb272014-09-15 16:48:12 -0700129func (br *blessingRoots) save() error {
gauthamt1e313bc2014-11-10 15:45:56 -0800130 if (br.signer == nil) && (br.persistedData == nil) {
Ankur100eb272014-09-15 16:48:12 -0700131 return nil
132 }
gauthamt1e313bc2014-11-10 15:45:56 -0800133 data, signature, err := br.persistedData.Writers()
134 if err != nil {
135 return err
136 }
Ankurcc043852015-04-14 13:10:28 -0700137 return encodeAndStore(br.state, data, signature, br.signer)
Ankur100eb272014-09-15 16:48:12 -0700138}
139
Ankur7c890592014-10-02 11:36:28 -0700140// newInMemoryBlessingRoots returns an in-memory security.BlessingRoots.
Ankur100eb272014-09-15 16:48:12 -0700141//
142// The returned BlessingRoots is initialized with an empty set of keys.
Ankur7c890592014-10-02 11:36:28 -0700143func newInMemoryBlessingRoots() security.BlessingRoots {
Ankur100eb272014-09-15 16:48:12 -0700144 return &blessingRoots{
Ankurcc043852015-04-14 13:10:28 -0700145 state: make(blessingRootsState),
Ankur100eb272014-09-15 16:48:12 -0700146 }
147}
148
gauthamt1e313bc2014-11-10 15:45:56 -0800149// newPersistingBlessingRoots returns a security.BlessingRoots for a principal
150// that is initialized with the persisted data. The returned security.BlessingRoots
151// also persists any updates to its state.
152func newPersistingBlessingRoots(persistedData SerializerReaderWriter, signer serialization.Signer) (security.BlessingRoots, error) {
153 if persistedData == nil || signer == nil {
Mike Burrows7f7088d2015-03-25 13:05:00 -0700154 return nil, verror.New(errDataOrSignerUnspecified, nil)
Ankur100eb272014-09-15 16:48:12 -0700155 }
156 br := &blessingRoots{
Ankurcc043852015-04-14 13:10:28 -0700157 state: make(blessingRootsState),
gauthamt1e313bc2014-11-10 15:45:56 -0800158 persistedData: persistedData,
159 signer: signer,
Ankur100eb272014-09-15 16:48:12 -0700160 }
gauthamt1e313bc2014-11-10 15:45:56 -0800161 data, signature, err := br.persistedData.Readers()
162 if err != nil {
Ankur100eb272014-09-15 16:48:12 -0700163 return nil, err
164 }
gauthamt1e313bc2014-11-10 15:45:56 -0800165 if (data != nil) && (signature != nil) {
Ankurcc043852015-04-14 13:10:28 -0700166 if err := decodeFromStorage(&br.state, data, signature, br.signer.PublicKey()); err != nil {
gauthamt1e313bc2014-11-10 15:45:56 -0800167 return nil, err
168 }
169 }
Ankur100eb272014-09-15 16:48:12 -0700170 return br, nil
171}