@@ -2,10 +2,12 @@ package trustmanager
22
33import (
44 "crypto/rand"
5+ "encoding/pem"
56 "errors"
67 "fmt"
78 "io/ioutil"
89 "os"
10+ "path"
911 "path/filepath"
1012 "testing"
1113
@@ -167,29 +169,39 @@ func TestGet(t *testing.T) {
167169
168170 gun := "docker.io/notary"
169171
170- // Root role needs to go in the rootKeySubdir to be read.
171- // All other roles can go in the nonRootKeysSubdir, possibly under a GUN
172+ // Root role currently goes into the rootKeySubdir, and all other roles go
173+ // in the nonRootKeysSubdir, possibly under a GUN.
172174 nonRootKeysSubdirWithGUN := filepath .Clean (filepath .Join (notary .NonRootKeysSubdir , gun ))
173-
174- testGetKeyWithRole (t , "" , data .CanonicalRootRole , notary .RootKeysSubdir , true )
175+ testGetKeyWithRole (t , "" , data .CanonicalRootRole , filepath .Join (notary .PrivDir , notary .RootKeysSubdir ), true )
175176 for _ , role := range nonRootRolesToTest {
176- testGetKeyWithRole (t , "" , role , notary .NonRootKeysSubdir , true )
177- testGetKeyWithRole (t , gun , role , nonRootKeysSubdirWithGUN , true )
177+ testGetKeyWithRole (t , "" , role , filepath . Join ( notary .PrivDir , notary . NonRootKeysSubdir ) , true )
178+ testGetKeyWithRole (t , gun , role , filepath . Join ( notary . PrivDir , nonRootKeysSubdirWithGUN ) , true )
178179 }
179180
180- // Root cannot go in the nonRootKeysSubdir, or it won't be able to be read,
181- // and vice versa
182- testGetKeyWithRole (t , "" , data .CanonicalRootRole , notary .NonRootKeysSubdir , false )
183- testGetKeyWithRole (t , gun , data .CanonicalRootRole , nonRootKeysSubdirWithGUN , false )
184- for _ , role := range nonRootRolesToTest {
185- testGetKeyWithRole (t , "" , role , notary .RootKeysSubdir , false )
181+ // However, keys of any role can be read from anywhere in the private dir so long as
182+ // it has the right ID
183+ for _ , expectedSubdir := range []string {
184+ notary .PrivDir ,
185+ filepath .Join (notary .PrivDir , nonRootKeysSubdirWithGUN ),
186+ filepath .Join (notary .PrivDir , notary .RootKeysSubdir ),
187+ filepath .Join (notary .PrivDir , notary .RootKeysSubdir , gun ),
188+ filepath .Join (notary .PrivDir , notary .NonRootKeysSubdir ),
189+ } {
190+ for _ , role := range append (nonRootRolesToTest , data .CanonicalRootRole ) {
191+ testGetKeyWithRole (t , "" , role , expectedSubdir , true )
192+ testGetKeyWithRole (t , gun , role , expectedSubdir , true )
193+ }
186194 }
187- }
188195
189- func testGetKeyWithRole (t * testing.T , gun , role , expectedSubdir string , success bool ) {
190- testData := []byte (fmt .Sprintf (`-----BEGIN RSA PRIVATE KEY-----
191- role: %s
196+ // keys outside of the private dir cannot be read
197+ for _ , role := range append (nonRootRolesToTest , data .CanonicalRootRole ) {
198+ testGetKeyWithRole (t , "" , role , "otherDir" , false )
199+ testGetKeyWithRole (t , gun , role , "otherDir" , false )
200+ }
201+ }
192202
203+ func writeKeyFile (t * testing.T , perms os.FileMode , filename , roleInPEM string ) []byte {
204+ testData := []byte (`-----BEGIN RSA PRIVATE KEY-----
193205MIIEogIBAAKCAQEAyUIXjsrWRrvPa4Bzp3VJ6uOUGPay2fUpSV8XzNxZxIG/Opdr
194206+k3EQi1im6WOqF3Y5AS1UjYRxNuRN+cAZeo3uS1pOTuoSupBXuchVw8s4hZJ5vXn
195207TRmGb+xY7tZ1ZVgPfAZDib9sRSUsL/gC+aSyprAjG/YBdbF06qKbfOfsoCEYW1OQ
@@ -216,7 +228,24 @@ EkqpAoGAJWe8PC0XK2RE9VkbSPg9Ehr939mOLWiHGYTVWPttUcum/rTKu73/X/mj
216228WxnPWGtzM1pHWypSokW90SP4/xedMxludvBvmz+CTYkNJcBGCrJumy11qJhii9xp
217229EMl3eFOJXjIch/wIesRSN+2dGOsl7neercjMh1i9RvpCwHDx/E0=
218230-----END RSA PRIVATE KEY-----
219- ` , role ))
231+ ` )
232+
233+ if roleInPEM != "" {
234+ block , _ := pem .Decode (testData )
235+ require .NotNil (t , block )
236+ block .Headers = map [string ]string {
237+ "role" : roleInPEM ,
238+ }
239+ testData = pem .EncodeToMemory (block )
240+ }
241+
242+ os .MkdirAll (filepath .Dir (filename ), perms )
243+ err := ioutil .WriteFile (filename , testData , perms )
244+ require .NoError (t , err , "failed to write test file" )
245+ return testData
246+ }
247+
248+ func testGetKeyWithRole (t * testing.T , gun , role , expectedSubdir string , success bool ) {
220249 testName := "keyID"
221250 testExt := "key"
222251 perms := os .FileMode (0755 )
@@ -229,18 +258,16 @@ EMl3eFOJXjIch/wIesRSN+2dGOsl7neercjMh1i9RvpCwHDx/E0=
229258 defer os .RemoveAll (tempBaseDir )
230259
231260 // Since we're generating this manually we need to add the extension '.'
232- filePath := filepath .Join (tempBaseDir , notary .PrivDir , expectedSubdir , testName + "." + testExt )
233- os .MkdirAll (filepath .Dir (filePath ), perms )
234- err = ioutil .WriteFile (filePath , testData , perms )
235- require .NoError (t , err , "failed to write test file" )
261+ filePath := filepath .Join (tempBaseDir , expectedSubdir , testName + "." + testExt )
262+ testData := writeKeyFile (t , perms , filePath , role )
236263
237264 // Create our store
238265 store , err := NewKeyFileStore (tempBaseDir , emptyPassphraseRetriever )
239266 require .NoError (t , err , "failed to create new key filestore" )
240267
241268 // Call the GetKey function
242269 if gun != "" {
243- testName = gun + "/ keyID"
270+ testName = path . Join ( gun , " keyID")
244271 }
245272 privKey , _ , err := store .GetKey (testName )
246273 if success {
@@ -263,34 +290,6 @@ EMl3eFOJXjIch/wIesRSN+2dGOsl7neercjMh1i9RvpCwHDx/E0=
263290// TestGetLegacyKey ensures we can still load keys where the role
264291// is stored as part of the filename (i.e. <hexID>_<role>.key
265292func TestGetLegacyKey (t * testing.T ) {
266- testData := []byte (`-----BEGIN RSA PRIVATE KEY-----
267- MIIEogIBAAKCAQEAyUIXjsrWRrvPa4Bzp3VJ6uOUGPay2fUpSV8XzNxZxIG/Opdr
268- +k3EQi1im6WOqF3Y5AS1UjYRxNuRN+cAZeo3uS1pOTuoSupBXuchVw8s4hZJ5vXn
269- TRmGb+xY7tZ1ZVgPfAZDib9sRSUsL/gC+aSyprAjG/YBdbF06qKbfOfsoCEYW1OQ
270- 82JqHzQH514RFYPTnEGpvfxWaqmFQLmv0uMxV/cAYvqtrGkXuP0+a8PknlD2obw5
271- 0rHE56Su1c3Q42S7L51K38tpbgWOSRcTfDUWEj5v9wokkNQvyKBwbS996s4EJaZd
272- 7r6M0h1pHnuRxcSaZLYRwgOe1VNGg2VfWzgd5QIDAQABAoIBAF9LGwpygmj1jm3R
273- YXGd+ITugvYbAW5wRb9G9mb6wspnwNsGTYsz/UR0ZudZyaVw4jx8+jnV/i3e5PC6
274- QRcAgqf8l4EQ/UuThaZg/AlT1yWp9g4UyxNXja87EpTsGKQGwTYxZRM4/xPyWOzR
275- mt8Hm8uPROB9aA2JG9npaoQG8KSUj25G2Qot3ukw/IOtqwN/Sx1EqF0EfCH1K4KU
276- a5TrqlYDFmHbqT1zTRec/BTtVXNsg8xmF94U1HpWf3Lpg0BPYT7JiN2DPoLelRDy
277- a/A+a3ZMRNISL5wbq/jyALLOOyOkIqa+KEOeW3USuePd6RhDMzMm/0ocp5FCwYfo
278- k4DDeaECgYEA0eSMD1dPGo+u8UTD8i7ZsZCS5lmXLNuuAg5f5B/FGghD8ymPROIb
279- dnJL5QSbUpmBsYJ+nnO8RiLrICGBe7BehOitCKi/iiZKJO6edrfNKzhf4XlU0HFl
280- jAOMa975pHjeCoZ1cXJOEO9oW4SWTCyBDBSqH3/ZMgIOiIEk896lSmkCgYEA9Xf5
281- Jqv3HtQVvjugV/axAh9aI8LMjlfFr9SK7iXpY53UdcylOSWKrrDok3UnrSEykjm7
282- UL3eCU5jwtkVnEXesNn6DdYo3r43E6iAiph7IBkB5dh0yv3vhIXPgYqyTnpdz4pg
283- 3yPGBHMPnJUBThg1qM7k6a2BKHWySxEgC1DTMB0CgYAGvdmF0J8Y0k6jLzs/9yNE
284- 4cjmHzCM3016gW2xDRgumt9b2xTf+Ic7SbaIV5qJj6arxe49NqhwdESrFohrKaIP
285- kM2l/o2QaWRuRT/Pvl2Xqsrhmh0QSOQjGCYVfOb10nAHVIRHLY22W4o1jk+piLBo
286- a+1+74NRaOGAnu1J6/fRKQKBgAF180+dmlzemjqFlFCxsR/4G8s2r4zxTMXdF+6O
287- 3zKuj8MbsqgCZy7e8qNeARxwpCJmoYy7dITNqJ5SOGSzrb2Trn9ClP+uVhmR2SH6
288- AlGQlIhPn3JNzI0XVsLIloMNC13ezvDE/7qrDJ677EQQtNEKWiZh1/DrsmHr+irX
289- EkqpAoGAJWe8PC0XK2RE9VkbSPg9Ehr939mOLWiHGYTVWPttUcum/rTKu73/X/mj
290- WxnPWGtzM1pHWypSokW90SP4/xedMxludvBvmz+CTYkNJcBGCrJumy11qJhii9xp
291- EMl3eFOJXjIch/wIesRSN+2dGOsl7neercjMh1i9RvpCwHDx/E0=
292- -----END RSA PRIVATE KEY-----
293- ` )
294293 testName := "docker.com/notary/root"
295294 testExt := "key"
296295 testAlias := "root"
@@ -305,10 +304,7 @@ EMl3eFOJXjIch/wIesRSN+2dGOsl7neercjMh1i9RvpCwHDx/E0=
305304
306305 // Since we're generating this manually we need to add the extension '.'
307306 filePath := filepath .Join (tempBaseDir , notary .PrivDir , notary .RootKeysSubdir , testName + "_" + testAlias + "." + testExt )
308-
309- os .MkdirAll (filepath .Dir (filePath ), perms )
310- err = ioutil .WriteFile (filePath , testData , perms )
311- require .NoError (t , err , "failed to write test file" )
307+ writeKeyFile (t , perms , filePath , "" )
312308
313309 // Create our store
314310 store , err := NewKeyFileStore (tempBaseDir , emptyPassphraseRetriever )
@@ -356,12 +352,6 @@ func TestListKeys(t *testing.T) {
356352 require .Equal (t , role , listedInfo .Role )
357353 }
358354
359- // Write an invalid filename to the directory
360- filePath := filepath .Join (tempBaseDir , notary .PrivDir , notary .RootKeysSubdir , "fakekeyname.key" )
361- err = ioutil .WriteFile (filePath , []byte ("data" ), perms )
362- require .NoError (t , err , "failed to write test file" )
363-
364- // Check to see if the keystore still lists two keys
365355 keyMap := store .ListKeys ()
366356 require .Len (t , keyMap , len (roles ))
367357
@@ -372,6 +362,31 @@ func TestListKeys(t *testing.T) {
372362 _ , err = store .GetKeyInfo (keyID )
373363 require .NoError (t , err )
374364 }
365+
366+ require .Len (t , store .ListKeys (), len (roles ))
367+
368+ // ListKeys() works even if the keys are in non-standard locations
369+ for i , loc := range []string {
370+ filepath .Join (tempBaseDir , notary .PrivDir , notary .RootKeysSubdir ),
371+ filepath .Join (tempBaseDir , notary .PrivDir , notary .NonRootKeysSubdir ),
372+ filepath .Join (tempBaseDir , notary .PrivDir , notary .RootKeysSubdir , testName ),
373+ filepath .Join (tempBaseDir , notary .PrivDir , testName ),
374+ filepath .Join (tempBaseDir , notary .PrivDir ),
375+ tempBaseDir , // this key won't be read
376+ } {
377+ fp := filepath .Join (loc , fmt .Sprintf ("keyID%d.key" , i ))
378+ writeKeyFile (t , perms , fp , "" )
379+
380+ // Ensure file exists
381+ _ , err := ioutil .ReadFile (fp )
382+ require .NoError (t , err , "expected file not found" )
383+ }
384+
385+ // update our store so we read from the FS again
386+ store , err = NewKeyFileStore (tempBaseDir , passphraseRetriever )
387+ require .NoError (t , err , "failed to create new key filestore" )
388+
389+ require .Len (t , store .ListKeys (), len (roles )+ 5 )
375390}
376391
377392func TestAddGetKeyMemStore (t * testing.T ) {
@@ -567,6 +582,42 @@ func TestRemoveKey(t *testing.T) {
567582 testRemoveKeyWithRole (t , data .CanonicalSnapshotRole , filepath .Join (notary .NonRootKeysSubdir , gun ))
568583 testRemoveKeyWithRole (t , "targets/a/b/c" , notary .NonRootKeysSubdir )
569584 testRemoveKeyWithRole (t , "invalidRole" , notary .NonRootKeysSubdir )
585+
586+ // create another store for other testing
587+ tempBaseDir , err := ioutil .TempDir ("" , "notary-test-" )
588+ require .NoError (t , err , "failed to create a temporary directory" )
589+ defer os .RemoveAll (tempBaseDir )
590+
591+ store , err := NewKeyFileStore (tempBaseDir , passphraseRetriever )
592+ require .NoError (t , err , "failed to create new key filestore" )
593+
594+ // write keys to non-standard locations - since we're generating keys manually
595+ // we need to add the extenxion
596+ perms := os .FileMode (0755 )
597+ for i , loc := range []string {
598+ filepath .Join (tempBaseDir , notary .PrivDir , notary .RootKeysSubdir ),
599+ filepath .Join (tempBaseDir , notary .PrivDir , notary .NonRootKeysSubdir ),
600+ filepath .Join (tempBaseDir , notary .PrivDir , notary .RootKeysSubdir , gun ),
601+ filepath .Join (tempBaseDir , notary .PrivDir , gun ),
602+ filepath .Join (tempBaseDir , notary .PrivDir ),
603+ } {
604+ fp := filepath .Join (loc , fmt .Sprintf ("keyID%d.key" , i ))
605+ writeKeyFile (t , perms , fp , "" )
606+
607+ // Ensure file exists
608+ _ , err := ioutil .ReadFile (fp )
609+ require .NoError (t , err , "expected file not found" )
610+
611+ err = store .RemoveKey (fmt .Sprintf ("keyID%d" , i ))
612+ require .NoError (t , err )
613+
614+ // File should no longer exist
615+ _ , err = ioutil .ReadFile (fp )
616+ require .True (t , os .IsNotExist (err ), "file should not exist" )
617+ }
618+
619+ // removing a non-existent key should not error
620+ require .NoError (t , store .RemoveKey ("nope" ))
570621}
571622
572623func testRemoveKeyWithRole (t * testing.T , role , expectedSubdir string ) {
@@ -599,9 +650,9 @@ func testRemoveKeyWithRole(t *testing.T, role, expectedSubdir string) {
599650 err = store .RemoveKey (privKey .ID ())
600651 require .NoError (t , err , "unable to remove key" )
601652
602- // Check to see if file still exists
653+ // File should no longer exist
603654 _ , err = ioutil .ReadFile (expectedFilePath )
604- require .Error (t , err , "file should not exist" )
655+ require .True (t , os . IsNotExist ( err ) , "file should not exist" )
605656}
606657
607658func TestKeysAreCached (t * testing.T ) {
0 commit comments