blob: 5f2d08cf23a1960090ac29603aa7a0b9d09622bb [file] [log] [blame]
Asim Shankarae8d4c52014-10-08 13:03:31 -07001package security
2
3import (
Suharsh Sivakumaraca1c322014-10-21 11:27:32 -07004 "crypto/ecdsa"
5 "crypto/elliptic"
6 "crypto/rand"
Asim Shankarae8d4c52014-10-08 13:03:31 -07007 "io/ioutil"
8 "os"
Suharsh Sivakumaraca1c322014-10-21 11:27:32 -07009 "path"
gauthamtf8263932014-12-16 10:59:09 -080010 "reflect"
Asim Shankarae8d4c52014-10-08 13:03:31 -070011 "testing"
gauthamtf8263932014-12-16 10:59:09 -080012
13 "veyron.io/veyron/veyron2/security"
Asim Shankarae8d4c52014-10-08 13:03:31 -070014)
15
Suharsh Sivakumaraca1c322014-10-21 11:27:32 -070016func TestLoadPersistentPrincipal(t *testing.T) {
17 // If the directory does not exist want os.IsNotExists.
18 _, err := LoadPersistentPrincipal("/tmp/fake/path/", nil)
19 if !os.IsNotExist(err) {
20 t.Errorf("invalid path should return does not exist error, instead got %v", err)
21 }
22 // If the key file exists and is unencrypted we should succeed.
23 dir := generatePEMFile(nil)
24 if _, err = LoadPersistentPrincipal(dir, nil); err != nil {
25 t.Errorf("unencrypted LoadPersistentPrincipal should have succeeded: %v", err)
26 }
27 os.RemoveAll(dir)
28
29 // If the private key file exists and is encrypted we should succeed with correct passphrase.
30 passphrase := []byte("passphrase")
31 incorrect_passphrase := []byte("incorrect_passphrase")
32 dir = generatePEMFile(passphrase)
33 if _, err = LoadPersistentPrincipal(dir, passphrase); err != nil {
34 t.Errorf("encrypted LoadPersistentPrincipal should have succeeded: %v", err)
35 }
36 // and fail with an incorrect passphrase.
37 if _, err = LoadPersistentPrincipal(dir, incorrect_passphrase); err == nil {
38 t.Errorf("encrypted LoadPersistentPrincipal with incorrect passphrase should fail")
39 }
Suharsh Sivakumar4684f4e2014-10-24 13:42:06 -070040 // and return PassphraseError if the passphrase is nil.
41 if _, err = LoadPersistentPrincipal(dir, nil); err != PassphraseErr {
42 t.Errorf("encrypted LoadPersistentPrincipal with nil passphrase should return PassphraseErr: %v", err)
Suharsh Sivakumaraca1c322014-10-21 11:27:32 -070043 }
44 os.RemoveAll(dir)
45}
46
Ankuree0aa812014-11-14 10:56:52 -080047// This Test checks that the all changes made to the principal's serialization
48// format stay backwards compatible.
49//
50// The 'testdata' directory used by this test was generated using the
51// principal tool as part of CL #6820.
52// $VEYRON_BIN/principal create testdata test
53func TestLoadPersistentPrincipalBackwardsCompatibility(t *testing.T) {
54 if _, err := LoadPersistentPrincipal("./testdata", nil); err != nil {
55 t.Fatal("LoadPersistentPrincipal is not backwards compatible: failed to read serialized principal data from CL #6820")
56 }
57}
58
Suharsh Sivakumaraca1c322014-10-21 11:27:32 -070059func TestCreatePersistentPrincipal(t *testing.T) {
60 tests := []struct {
61 Message, Passphrase []byte
62 }{
63 {[]byte("unencrypted"), nil},
64 {[]byte("encrypted"), []byte("passphrase")},
65 }
66 for _, test := range tests {
67 testCreatePersistentPrincipal(t, test.Message, test.Passphrase)
68 }
69}
70
71func testCreatePersistentPrincipal(t *testing.T, message, passphrase []byte) {
Asim Shankarae8d4c52014-10-08 13:03:31 -070072 // Persistence of the BlessingRoots and BlessingStore objects is
73 // tested in other files. Here just test the persistence of the key.
Suharsh Sivakumaraca1c322014-10-21 11:27:32 -070074 dir, err := ioutil.TempDir("", "TestCreatePersistentPrincipal")
Asim Shankarae8d4c52014-10-08 13:03:31 -070075 if err != nil {
76 t.Fatal(err)
77 }
78 defer os.RemoveAll(dir)
79
Suharsh Sivakumaraca1c322014-10-21 11:27:32 -070080 p, err := CreatePersistentPrincipal(dir, passphrase)
Asim Shankarae8d4c52014-10-08 13:03:31 -070081 if err != nil {
82 t.Fatal(err)
83 }
gauthamtb7bb39b2014-11-10 11:40:41 -080084 _, err = CreatePersistentPrincipal(dir, passphrase)
Ankur4704f5f2014-10-23 12:40:54 -070085 if err == nil {
86 t.Error("CreatePersistentPrincipal passed unexpectedly")
87 }
Ankur4704f5f2014-10-23 12:40:54 -070088
Asim Shankarae8d4c52014-10-08 13:03:31 -070089 sig, err := p.Sign(message)
90 if err != nil {
91 t.Fatal(err)
92 }
93
Ankur4704f5f2014-10-23 12:40:54 -070094 p2, err := LoadPersistentPrincipal(dir, passphrase)
Asim Shankarae8d4c52014-10-08 13:03:31 -070095 if err != nil {
Suharsh Sivakumar8a7fba42014-10-27 12:40:48 -070096 t.Fatalf("%s failed: %v", message, err)
Asim Shankarae8d4c52014-10-08 13:03:31 -070097 }
Ankur4704f5f2014-10-23 12:40:54 -070098 if !sig.Verify(p2.PublicKey(), message) {
Suharsh Sivakumaraca1c322014-10-21 11:27:32 -070099 t.Errorf("%s failed: p.PublicKey=%v, p2.PublicKey=%v", message, p.PublicKey(), p2.PublicKey())
Asim Shankarae8d4c52014-10-08 13:03:31 -0700100 }
101}
Suharsh Sivakumaraca1c322014-10-21 11:27:32 -0700102
103func generatePEMFile(passphrase []byte) (dir string) {
104 dir, err := ioutil.TempDir("", "TestLoadPersistentPrincipal")
105 if err != nil {
106 panic(err)
107 }
108 key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
109 if err != nil {
110 panic(err)
111 }
112 f, err := os.Create(path.Join(dir, privateKeyFile))
113 if err != nil {
114 panic(err)
115 }
116 defer f.Close()
Ankur73e7a932014-10-24 15:57:03 -0700117 if err = SavePEMKey(f, key, passphrase); err != nil {
Suharsh Sivakumaraca1c322014-10-21 11:27:32 -0700118 panic(err)
119 }
120 return dir
121}
gauthamtf8263932014-12-16 10:59:09 -0800122
123func TestPrincipalBlessingsByName(t *testing.T) {
124 var p1, p2, p3 security.Principal
125 var err error
126
127 if p1, err = NewPrincipal(); err != nil {
128 t.Fatal(err)
129 }
130 if p2, err = NewPrincipal(); err != nil {
131 t.Fatal(err)
132 }
133 alice, err := p1.BlessSelf("alice")
134 if err != nil {
135 t.Fatal(err)
136 }
137 p2.AddToRoots(alice)
138 var aliceworkfriend, alicegymfriend, aliceworkboss security.Blessings
139
140 if aliceworkfriend, err = p1.Bless(p2.PublicKey(), alice, "work/friend", security.UnconstrainedUse()); err != nil {
141 t.Errorf("Bless(work/friend) failed: %v", err)
142 }
143 p2.BlessingStore().Set(aliceworkfriend, "alice/work/friend")
144 if alicegymfriend, err = p1.Bless(p2.PublicKey(), alice, "gym/friend", security.UnconstrainedUse()); err != nil {
145 t.Errorf("Bless(gym/friend) failed: %v", err)
146 }
147 p2.BlessingStore().Set(alicegymfriend, "alice/gym/friend")
148 if aliceworkboss, err = p1.Bless(p2.PublicKey(), alice, "work/boss", security.UnconstrainedUse()); err != nil {
149 t.Errorf("Bless(work/friend) failed: %v", err)
150 }
151 p2.BlessingStore().Set(aliceworkboss, "alice/work/boss")
152
153 // Blessing from an untrusted principal that should never be returned
154 if p3, err = NewPrincipal(); err != nil {
155 t.Fatal(err)
156 }
157 fake, err := p3.BlessSelf("alice")
158 if err != nil {
159 t.Fatal(err)
160 }
161 fakefriend, err := p3.Bless(p2.PublicKey(), fake, "work/friend", security.UnconstrainedUse())
162 if err != nil {
163 t.Errorf("Bless(work/friend) failed: %v", err)
164 }
165 _, err = p2.BlessingStore().Set(fakefriend, "fake/work/friend")
166
167 tests := []struct {
168 matched []security.Blessings
169 pattern security.BlessingPattern
170 }{
171 {
172 matched: []security.Blessings{aliceworkfriend, aliceworkboss},
173 pattern: "alice/work/...",
174 },
175 {
176 matched: []security.Blessings{aliceworkfriend},
177 pattern: "alice/work/friend",
178 },
179 {
180 matched: []security.Blessings{alicegymfriend},
181 pattern: "alice/gym/friend",
182 },
183 {
184 matched: []security.Blessings{aliceworkfriend, alicegymfriend, aliceworkboss},
185 pattern: "alice/...",
186 },
187 {
188 matched: []security.Blessings{aliceworkfriend, alicegymfriend, aliceworkboss},
189 pattern: "...",
190 },
191 {
192 matched: nil,
193 pattern: "alice/school/...",
194 },
195 }
196
197 for _, test := range tests {
198 matched := p2.BlessingsByName(test.pattern)
199 if len(matched) != len(test.matched) {
200 t.Errorf("BlessingsByName(%s) did not return expected number of matches wanted:%d got:%d", test.pattern, len(test.matched), len(matched))
201 }
202 for _, m := range matched {
203 found := false
204 for _, tm := range test.matched {
205 if reflect.DeepEqual(m, tm) {
206 found = true
207 break
208 }
209 }
210 if !found {
211 t.Errorf("Invalid blessing was returned as a match:%v for pattern:%s", m, test.pattern)
212 }
213 }
214 }
215}