func (r *Repo) GenKeyWithExpires(keyRole string, expires time.Time) (string, error) { if !keys.ValidRole(keyRole) { return "", ErrInvalidRole{keyRole} } if !validExpires(expires) { return "", ErrInvalidExpires{expires} } root, err := r.root() if err != nil { return "", err } key, err := keys.NewKey() if err != nil { return "", err } if err := r.local.SaveKey(keyRole, key.SerializePrivate()); err != nil { return "", err } role, ok := root.Roles[keyRole] if !ok { role = &data.Role{KeyIDs: []string{}, Threshold: 1} root.Roles[keyRole] = role } role.KeyIDs = append(role.KeyIDs, key.ID) root.Keys[key.ID] = key.Serialize() root.Expires = expires.Round(time.Second) root.Version++ return key.ID, r.setMeta("root.json", root) }
func (RepoSuite) TestSign(c *C) { meta := map[string]json.RawMessage{"root.json": []byte(`{"signed":{},"signatures":[]}`)} local := MemoryStore(meta, nil) r, err := NewRepo(local) c.Assert(err, IsNil) // signing with no keys returns ErrInsufficientKeys c.Assert(r.Sign("root.json"), Equals, ErrInsufficientKeys{"root.json"}) checkSigIDs := func(keyIDs ...string) { rootJSON, ok := meta["root.json"] if !ok { c.Fatal("missing root.json") } s := &data.Signed{} c.Assert(json.Unmarshal(rootJSON, s), IsNil) c.Assert(s.Signatures, HasLen, len(keyIDs)) for i, id := range keyIDs { c.Assert(s.Signatures[i].KeyID, Equals, id) } } // signing with an available key generates a signature key, err := keys.NewKey() c.Assert(err, IsNil) c.Assert(local.SaveKey("root", key.SerializePrivate()), IsNil) c.Assert(r.Sign("root.json"), IsNil) checkSigIDs(key.ID) // signing again does not generate a duplicate signature c.Assert(r.Sign("root.json"), IsNil) checkSigIDs(key.ID) // signing with a new available key generates another signature newKey, err := keys.NewKey() c.Assert(err, IsNil) c.Assert(local.SaveKey("root", newKey.SerializePrivate()), IsNil) c.Assert(r.Sign("root.json"), IsNil) checkSigIDs(key.ID, newKey.ID) }
func (RepoSuite) TestKeyPersistence(c *C) { tmp := newTmpDir(c) passphrase := []byte("s3cr3t") store := FileSystemStore(tmp.path, testPassphraseFunc(passphrase)) assertEqual := func(actual []*data.Key, expected []*keys.Key) { c.Assert(actual, HasLen, len(expected)) for i, key := range expected { c.Assert(actual[i].ID(), Equals, key.ID) c.Assert(actual[i].Value.Public, DeepEquals, data.HexBytes(key.Public[:])) c.Assert(actual[i].Value.Private, DeepEquals, data.HexBytes(key.Private[:])) } } assertKeys := func(role string, enc bool, expected []*keys.Key) { keysJSON := tmp.readFile("keys/" + role + ".json") pk := &persistedKeys{} c.Assert(json.Unmarshal(keysJSON, pk), IsNil) // check the persisted keys are correct var actual []*data.Key if enc { c.Assert(pk.Encrypted, Equals, true) decrypted, err := encrypted.Decrypt(pk.Data, passphrase) c.Assert(err, IsNil) c.Assert(json.Unmarshal(decrypted, &actual), IsNil) } else { c.Assert(pk.Encrypted, Equals, false) c.Assert(json.Unmarshal(pk.Data, &actual), IsNil) } assertEqual(actual, expected) // check GetKeys is correct actual, err := store.GetKeys(role) c.Assert(err, IsNil) assertEqual(actual, expected) } // save a key and check it gets encrypted key, err := keys.NewKey() c.Assert(err, IsNil) c.Assert(store.SaveKey("root", key.SerializePrivate()), IsNil) assertKeys("root", true, []*keys.Key{key}) // save another key and check it gets added to the existing keys newKey, err := keys.NewKey() c.Assert(err, IsNil) c.Assert(store.SaveKey("root", newKey.SerializePrivate()), IsNil) assertKeys("root", true, []*keys.Key{key, newKey}) // check saving a key to an encrypted file without a passphrase fails insecureStore := FileSystemStore(tmp.path, nil) key, err = keys.NewKey() c.Assert(err, IsNil) c.Assert(insecureStore.SaveKey("root", key.SerializePrivate()), Equals, ErrPassphraseRequired{"root"}) // save a key to an insecure store and check it is not encrypted key, err = keys.NewKey() c.Assert(err, IsNil) c.Assert(insecureStore.SaveKey("targets", key.SerializePrivate()), IsNil) assertKeys("targets", false, []*keys.Key{key}) }
func (VerifySuite) Test(c *C) { type test struct { name string keys []*data.Key roles map[string]*data.Role s *data.Signed ver int exp *time.Time typ string role string err error mut func(*test) } expiredTime := time.Now().Add(-time.Hour) minVer := 10 tests := []test{ { name: "no signatures", mut: func(t *test) { t.s.Signatures = []data.Signature{} }, err: ErrNoSignatures, }, { name: "unknown role", role: "foo", err: ErrUnknownRole, }, { name: "wrong signature method", mut: func(t *test) { t.s.Signatures[0].Method = "foo" }, err: ErrWrongMethod, }, { name: "signature wrong length", mut: func(t *test) { t.s.Signatures[0].Signature = []byte{0} }, err: ErrInvalid, }, { name: "key missing from role", mut: func(t *test) { t.roles["root"].KeyIDs = nil }, err: ErrRoleThreshold, }, { name: "invalid signature", mut: func(t *test) { t.s.Signatures[0].Signature = make([]byte, ed25519.SignatureSize) }, err: ErrInvalid, }, { name: "not enough signatures", mut: func(t *test) { t.roles["root"].Threshold = 2 }, err: ErrRoleThreshold, }, { name: "exactly enough signatures", }, { name: "more than enough signatures", mut: func(t *test) { k, _ := keys.NewKey() Sign(t.s, k.SerializePrivate()) t.keys = append(t.keys, k.Serialize()) t.roles["root"].KeyIDs = append(t.roles["root"].KeyIDs, k.ID) }, }, { name: "duplicate key id", mut: func(t *test) { t.roles["root"].Threshold = 2 t.s.Signatures = append(t.s.Signatures, t.s.Signatures[0]) }, err: ErrRoleThreshold, }, { name: "unknown key", mut: func(t *test) { k, _ := keys.NewKey() Sign(t.s, k.Serialize()) }, }, { name: "unknown key below threshold", mut: func(t *test) { k, _ := keys.NewKey() Sign(t.s, k.Serialize()) t.roles["root"].Threshold = 2 }, err: ErrRoleThreshold, }, { name: "unknown keys in db", mut: func(t *test) { k, _ := keys.NewKey() Sign(t.s, k.Serialize()) t.keys = append(t.keys, k.Serialize()) }, }, { name: "unknown keys in db below threshold", mut: func(t *test) { k, _ := keys.NewKey() Sign(t.s, k.Serialize()) t.keys = append(t.keys, k.Serialize()) t.roles["root"].Threshold = 2 }, err: ErrRoleThreshold, }, { name: "wrong type", typ: "bar", err: ErrWrongType, }, { name: "low version", ver: minVer - 1, err: ErrLowVersion{minVer - 1, minVer}, }, { name: "expired", exp: &expiredTime, err: ErrExpired{expiredTime}, }, } for _, t := range tests { if t.role == "" { t.role = "root" } if t.ver == 0 { t.ver = minVer } if t.exp == nil { expires := time.Now().Add(time.Hour) t.exp = &expires } if t.typ == "" { t.typ = t.role } if t.keys == nil && t.s == nil { k, _ := keys.NewKey() t.s, _ = Marshal(&signedMeta{Type: t.typ, Version: t.ver, Expires: *t.exp}, k.SerializePrivate()) t.keys = []*data.Key{k.Serialize()} } if t.roles == nil { t.roles = map[string]*data.Role{ "root": &data.Role{ KeyIDs: []string{t.keys[0].ID()}, Threshold: 1, }, } } if t.mut != nil { t.mut(&t) } db := keys.NewDB() for _, k := range t.keys { err := db.AddKey(k.ID(), k) c.Assert(err, IsNil) } for n, r := range t.roles { err := db.AddRole(n, r) c.Assert(err, IsNil) } err := Verify(t.s, t.role, minVer, db) if e, ok := t.err.(ErrExpired); ok { assertErrExpired(c, err, e) } else { c.Assert(err, DeepEquals, t.err, Commentf("name = %s", t.name)) } } }