blob: 9a3234f1ad5d5763f318e68f0be749fb324ff501 [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
6
7import (
Suharsh Sivakumaraca1c322014-10-21 11:27:32 -07008 "crypto/ecdsa"
9 "crypto/elliptic"
10 "crypto/rand"
Asim Shankarae8d4c52014-10-08 13:03:31 -070011 "io/ioutil"
12 "os"
Suharsh Sivakumaraca1c322014-10-21 11:27:32 -070013 "path"
gauthamtf8263932014-12-16 10:59:09 -080014 "reflect"
Asim Shankarae8d4c52014-10-08 13:03:31 -070015 "testing"
gauthamtf8263932014-12-16 10:59:09 -080016
Jiri Simsa6ac95222015-02-23 16:11:49 -080017 "v.io/v23/security"
Mike Burrows7f7088d2015-03-25 13:05:00 -070018 "v.io/v23/verror"
Asim Shankarae8d4c52014-10-08 13:03:31 -070019)
20
Suharsh Sivakumaraca1c322014-10-21 11:27:32 -070021func TestLoadPersistentPrincipal(t *testing.T) {
22 // If the directory does not exist want os.IsNotExists.
23 _, err := LoadPersistentPrincipal("/tmp/fake/path/", nil)
24 if !os.IsNotExist(err) {
25 t.Errorf("invalid path should return does not exist error, instead got %v", err)
26 }
27 // If the key file exists and is unencrypted we should succeed.
28 dir := generatePEMFile(nil)
29 if _, err = LoadPersistentPrincipal(dir, nil); err != nil {
30 t.Errorf("unencrypted LoadPersistentPrincipal should have succeeded: %v", err)
31 }
32 os.RemoveAll(dir)
33
34 // If the private key file exists and is encrypted we should succeed with correct passphrase.
35 passphrase := []byte("passphrase")
36 incorrect_passphrase := []byte("incorrect_passphrase")
37 dir = generatePEMFile(passphrase)
38 if _, err = LoadPersistentPrincipal(dir, passphrase); err != nil {
39 t.Errorf("encrypted LoadPersistentPrincipal should have succeeded: %v", err)
40 }
41 // and fail with an incorrect passphrase.
42 if _, err = LoadPersistentPrincipal(dir, incorrect_passphrase); err == nil {
43 t.Errorf("encrypted LoadPersistentPrincipal with incorrect passphrase should fail")
44 }
Mike Burrows7f7088d2015-03-25 13:05:00 -070045 // and return ErrBadPassphrase if the passphrase is nil.
46 if _, err = LoadPersistentPrincipal(dir, nil); verror.ErrorID(err) != ErrBadPassphrase.ID {
47 t.Errorf("encrypted LoadPersistentPrincipal with nil passphrase should return ErrBadPassphrase: %v", err)
Suharsh Sivakumaraca1c322014-10-21 11:27:32 -070048 }
49 os.RemoveAll(dir)
50}
51
52func TestCreatePersistentPrincipal(t *testing.T) {
53 tests := []struct {
54 Message, Passphrase []byte
55 }{
56 {[]byte("unencrypted"), nil},
57 {[]byte("encrypted"), []byte("passphrase")},
58 }
59 for _, test := range tests {
60 testCreatePersistentPrincipal(t, test.Message, test.Passphrase)
61 }
62}
63
64func testCreatePersistentPrincipal(t *testing.T, message, passphrase []byte) {
Asim Shankarae8d4c52014-10-08 13:03:31 -070065 // Persistence of the BlessingRoots and BlessingStore objects is
66 // tested in other files. Here just test the persistence of the key.
Suharsh Sivakumaraca1c322014-10-21 11:27:32 -070067 dir, err := ioutil.TempDir("", "TestCreatePersistentPrincipal")
Asim Shankarae8d4c52014-10-08 13:03:31 -070068 if err != nil {
69 t.Fatal(err)
70 }
71 defer os.RemoveAll(dir)
72
Suharsh Sivakumaraca1c322014-10-21 11:27:32 -070073 p, err := CreatePersistentPrincipal(dir, passphrase)
Asim Shankarae8d4c52014-10-08 13:03:31 -070074 if err != nil {
75 t.Fatal(err)
76 }
gauthamtb7bb39b2014-11-10 11:40:41 -080077 _, err = CreatePersistentPrincipal(dir, passphrase)
Ankur4704f5f2014-10-23 12:40:54 -070078 if err == nil {
79 t.Error("CreatePersistentPrincipal passed unexpectedly")
80 }
Ankur4704f5f2014-10-23 12:40:54 -070081
Asim Shankarae8d4c52014-10-08 13:03:31 -070082 sig, err := p.Sign(message)
83 if err != nil {
84 t.Fatal(err)
85 }
86
Ankur4704f5f2014-10-23 12:40:54 -070087 p2, err := LoadPersistentPrincipal(dir, passphrase)
Asim Shankarae8d4c52014-10-08 13:03:31 -070088 if err != nil {
Suharsh Sivakumar8a7fba42014-10-27 12:40:48 -070089 t.Fatalf("%s failed: %v", message, err)
Asim Shankarae8d4c52014-10-08 13:03:31 -070090 }
Ankur4704f5f2014-10-23 12:40:54 -070091 if !sig.Verify(p2.PublicKey(), message) {
Suharsh Sivakumaraca1c322014-10-21 11:27:32 -070092 t.Errorf("%s failed: p.PublicKey=%v, p2.PublicKey=%v", message, p.PublicKey(), p2.PublicKey())
Asim Shankarae8d4c52014-10-08 13:03:31 -070093 }
94}
Suharsh Sivakumaraca1c322014-10-21 11:27:32 -070095
96func generatePEMFile(passphrase []byte) (dir string) {
97 dir, err := ioutil.TempDir("", "TestLoadPersistentPrincipal")
98 if err != nil {
99 panic(err)
100 }
101 key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
102 if err != nil {
103 panic(err)
104 }
105 f, err := os.Create(path.Join(dir, privateKeyFile))
106 if err != nil {
107 panic(err)
108 }
109 defer f.Close()
Ankur73e7a932014-10-24 15:57:03 -0700110 if err = SavePEMKey(f, key, passphrase); err != nil {
Suharsh Sivakumaraca1c322014-10-21 11:27:32 -0700111 panic(err)
112 }
113 return dir
114}
gauthamtf8263932014-12-16 10:59:09 -0800115
116func TestPrincipalBlessingsByName(t *testing.T) {
117 var p1, p2, p3 security.Principal
118 var err error
119
120 if p1, err = NewPrincipal(); err != nil {
121 t.Fatal(err)
122 }
123 if p2, err = NewPrincipal(); err != nil {
124 t.Fatal(err)
125 }
126 alice, err := p1.BlessSelf("alice")
127 if err != nil {
128 t.Fatal(err)
129 }
130 p2.AddToRoots(alice)
131 var aliceworkfriend, alicegymfriend, aliceworkboss security.Blessings
132
133 if aliceworkfriend, err = p1.Bless(p2.PublicKey(), alice, "work/friend", security.UnconstrainedUse()); err != nil {
134 t.Errorf("Bless(work/friend) failed: %v", err)
135 }
136 p2.BlessingStore().Set(aliceworkfriend, "alice/work/friend")
137 if alicegymfriend, err = p1.Bless(p2.PublicKey(), alice, "gym/friend", security.UnconstrainedUse()); err != nil {
138 t.Errorf("Bless(gym/friend) failed: %v", err)
139 }
140 p2.BlessingStore().Set(alicegymfriend, "alice/gym/friend")
141 if aliceworkboss, err = p1.Bless(p2.PublicKey(), alice, "work/boss", security.UnconstrainedUse()); err != nil {
142 t.Errorf("Bless(work/friend) failed: %v", err)
143 }
144 p2.BlessingStore().Set(aliceworkboss, "alice/work/boss")
145
146 // Blessing from an untrusted principal that should never be returned
147 if p3, err = NewPrincipal(); err != nil {
148 t.Fatal(err)
149 }
150 fake, err := p3.BlessSelf("alice")
151 if err != nil {
152 t.Fatal(err)
153 }
154 fakefriend, err := p3.Bless(p2.PublicKey(), fake, "work/friend", security.UnconstrainedUse())
155 if err != nil {
156 t.Errorf("Bless(work/friend) failed: %v", err)
157 }
158 _, err = p2.BlessingStore().Set(fakefriend, "fake/work/friend")
159
160 tests := []struct {
161 matched []security.Blessings
162 pattern security.BlessingPattern
163 }{
164 {
165 matched: []security.Blessings{aliceworkfriend, aliceworkboss},
Ankur78b8b2a2015-02-04 20:16:28 -0800166 pattern: "alice/work",
gauthamtf8263932014-12-16 10:59:09 -0800167 },
168 {
169 matched: []security.Blessings{aliceworkfriend},
170 pattern: "alice/work/friend",
171 },
172 {
173 matched: []security.Blessings{alicegymfriend},
174 pattern: "alice/gym/friend",
175 },
176 {
177 matched: []security.Blessings{aliceworkfriend, alicegymfriend, aliceworkboss},
Ankur78b8b2a2015-02-04 20:16:28 -0800178 pattern: "alice",
gauthamtf8263932014-12-16 10:59:09 -0800179 },
180 {
181 matched: []security.Blessings{aliceworkfriend, alicegymfriend, aliceworkboss},
Ankur78b8b2a2015-02-04 20:16:28 -0800182 pattern: security.AllPrincipals,
gauthamtf8263932014-12-16 10:59:09 -0800183 },
184 {
185 matched: nil,
Ankur78b8b2a2015-02-04 20:16:28 -0800186 pattern: "alice/school",
gauthamtf8263932014-12-16 10:59:09 -0800187 },
188 }
189
190 for _, test := range tests {
191 matched := p2.BlessingsByName(test.pattern)
192 if len(matched) != len(test.matched) {
193 t.Errorf("BlessingsByName(%s) did not return expected number of matches wanted:%d got:%d", test.pattern, len(test.matched), len(matched))
194 }
195 for _, m := range matched {
196 found := false
197 for _, tm := range test.matched {
198 if reflect.DeepEqual(m, tm) {
199 found = true
200 break
201 }
202 }
203 if !found {
204 t.Errorf("Invalid blessing was returned as a match:%v for pattern:%s", m, test.pattern)
205 }
206 }
207 }
208}