blob: 5f314d86fca38075d69c9569329ef179023d8953 [file] [log] [blame]
Asim Shankarae8d4c52014-10-08 13:03:31 -07001package security
Ankur100eb272014-09-15 16:48:12 -07002
3import (
Ankur1615a7d2014-10-09 11:58:02 -07004 "bytes"
Ankur100eb272014-09-15 16:48:12 -07005 "errors"
Ankur1615a7d2014-10-09 11:58:02 -07006 "fmt"
Ankur100eb272014-09-15 16:48:12 -07007 "sync"
8
Jiri Simsa519c5072014-09-17 21:37:57 -07009 "veyron.io/veyron/veyron/security/serialization"
Ankur100eb272014-09-15 16:48:12 -070010
Jiri Simsa519c5072014-09-17 21:37:57 -070011 "veyron.io/veyron/veyron2/security"
Ankur100eb272014-09-15 16:48:12 -070012)
13
14const (
15 blessingRootsDataFile = "blessingroots.data"
16 blessingRootsSigFile = "blessingroots.sig"
17)
18
19// blessingRoots implements security.BlessingRoots.
20type blessingRoots struct {
Ankur100eb272014-09-15 16:48:12 -070021 dir string
22 signer serialization.Signer
23 mu sync.RWMutex
Asim Shankarae8d4c52014-10-08 13:03:31 -070024 store map[string][]security.BlessingPattern // GUARDED_BY(mu)
Ankur100eb272014-09-15 16:48:12 -070025}
26
27func storeMapKey(root security.PublicKey) (string, error) {
28 rootBytes, err := root.MarshalBinary()
29 if err != nil {
30 return "", err
31 }
Ankur1615a7d2014-10-09 11:58:02 -070032 return string(rootBytes), nil
Ankur100eb272014-09-15 16:48:12 -070033}
34
35func (br *blessingRoots) Add(root security.PublicKey, pattern security.BlessingPattern) error {
36 key, err := storeMapKey(root)
37 if err != nil {
38 return err
39 }
40
41 br.mu.Lock()
42 defer br.mu.Unlock()
43 patterns := br.store[key]
44 for _, p := range patterns {
45 if p == pattern {
46 return nil
47 }
48 }
49 br.store[key] = append(patterns, pattern)
50
51 if err := br.save(); err != nil {
52 br.store[key] = patterns[:len(patterns)-1]
53 return err
54 }
55 return nil
56}
57
58func (br *blessingRoots) Recognized(root security.PublicKey, blessing string) error {
59 key, err := storeMapKey(root)
60 if err != nil {
61 return err
62 }
63
64 br.mu.RLock()
65 defer br.mu.RUnlock()
66 for _, p := range br.store[key] {
67 if p.MatchedBy(blessing) {
68 return nil
69 }
70 }
71 return errors.New("PublicKey is not a recognized root for this blessing")
72}
73
Ankur1615a7d2014-10-09 11:58:02 -070074// DebugString return a human-readable string encoding of the roots
75// DebugString encodes all roots into a string in the following
76// format
77//
78// Public key : Pattern
79// <public key> : <pattern>
80// ...
81// <public key> : <pattern>
82func (br *blessingRoots) DebugString() string {
83 const format = "%-47s : %s\n"
84 b := bytes.NewBufferString(fmt.Sprintf(format, "Public key", "Pattern"))
85 for keyBytes, pattern := range br.store {
86 key, err := security.UnmarshalPublicKey([]byte(keyBytes))
87 if err != nil {
88 return fmt.Sprintf("failed to decode public key: %v", err)
89 }
90 b.WriteString(fmt.Sprintf(format, key, pattern))
91 }
92 return b.String()
93}
94
Ankur100eb272014-09-15 16:48:12 -070095func (br *blessingRoots) save() error {
96 if (br.signer == nil) && (br.dir == "") {
97 return nil
98 }
99 return encodeAndStore(br.store, br.dir, blessingRootsDataFile, blessingRootsSigFile, br.signer)
100}
101
Ankur7c890592014-10-02 11:36:28 -0700102// newInMemoryBlessingRoots returns an in-memory security.BlessingRoots.
Ankur100eb272014-09-15 16:48:12 -0700103//
104// The returned BlessingRoots is initialized with an empty set of keys.
Ankur7c890592014-10-02 11:36:28 -0700105func newInMemoryBlessingRoots() security.BlessingRoots {
Ankur100eb272014-09-15 16:48:12 -0700106 return &blessingRoots{
107 store: make(map[string][]security.BlessingPattern),
108 }
109}
110
Ankur7c890592014-10-02 11:36:28 -0700111// newPersistingBlessingRoots returns a security.BlessingRoots that signs
Ankur100eb272014-09-15 16:48:12 -0700112// and persists all updates to the provided directory. Signing is carried
113// out using the provided signer.
114//
115// The returned BlessingRoots is initialized from the existing data present
116// in the directory. The data is verified to have been written by a persisting
117// BlessingRoots object constructed from the same signer.
118//
119// Any errors obtained in reading or verifying the data are returned.
Ankur7c890592014-10-02 11:36:28 -0700120func newPersistingBlessingRoots(directory string, signer serialization.Signer) (security.BlessingRoots, error) {
Ankur100eb272014-09-15 16:48:12 -0700121 if directory == "" || signer == nil {
122 return nil, errors.New("directory or signer is not specified")
123 }
124 br := &blessingRoots{
125 store: make(map[string][]security.BlessingPattern),
126 dir: directory,
127 signer: signer,
128 }
129
130 if err := decodeFromStorage(&br.store, br.dir, blessingRootsDataFile, blessingRootsSigFile, br.signer.PublicKey()); err != nil {
131 return nil, err
132 }
133 return br, nil
134}