Tizen_4.0 base
[platform/upstream/docker-engine.git] / vendor / github.com / docker / notary / client / helpers.go
1 package client
2
3 import (
4         "encoding/json"
5         "fmt"
6         "net/http"
7         "time"
8
9         "github.com/Sirupsen/logrus"
10         "github.com/docker/notary/client/changelist"
11         store "github.com/docker/notary/storage"
12         "github.com/docker/notary/tuf"
13         "github.com/docker/notary/tuf/data"
14         "github.com/docker/notary/tuf/utils"
15 )
16
17 // Use this to initialize remote HTTPStores from the config settings
18 func getRemoteStore(baseURL, gun string, rt http.RoundTripper) (store.RemoteStore, error) {
19         s, err := store.NewHTTPStore(
20                 baseURL+"/v2/"+gun+"/_trust/tuf/",
21                 "",
22                 "json",
23                 "key",
24                 rt,
25         )
26         if err != nil {
27                 return store.OfflineStore{}, err
28         }
29         return s, err
30 }
31
32 func applyChangelist(repo *tuf.Repo, invalid *tuf.Repo, cl changelist.Changelist) error {
33         it, err := cl.NewIterator()
34         if err != nil {
35                 return err
36         }
37         index := 0
38         for it.HasNext() {
39                 c, err := it.Next()
40                 if err != nil {
41                         return err
42                 }
43                 isDel := data.IsDelegation(c.Scope()) || data.IsWildDelegation(c.Scope())
44                 switch {
45                 case c.Scope() == changelist.ScopeTargets || isDel:
46                         err = applyTargetsChange(repo, invalid, c)
47                 case c.Scope() == changelist.ScopeRoot:
48                         err = applyRootChange(repo, c)
49                 default:
50                         return fmt.Errorf("scope not supported: %s", c.Scope())
51                 }
52                 if err != nil {
53                         logrus.Debugf("error attempting to apply change #%d: %s, on scope: %s path: %s type: %s", index, c.Action(), c.Scope(), c.Path(), c.Type())
54                         return err
55                 }
56                 index++
57         }
58         logrus.Debugf("applied %d change(s)", index)
59         return nil
60 }
61
62 func applyTargetsChange(repo *tuf.Repo, invalid *tuf.Repo, c changelist.Change) error {
63         switch c.Type() {
64         case changelist.TypeTargetsTarget:
65                 return changeTargetMeta(repo, c)
66         case changelist.TypeTargetsDelegation:
67                 return changeTargetsDelegation(repo, c)
68         case changelist.TypeWitness:
69                 return witnessTargets(repo, invalid, c.Scope())
70         default:
71                 return fmt.Errorf("only target meta and delegations changes supported")
72         }
73 }
74
75 func changeTargetsDelegation(repo *tuf.Repo, c changelist.Change) error {
76         switch c.Action() {
77         case changelist.ActionCreate:
78                 td := changelist.TUFDelegation{}
79                 err := json.Unmarshal(c.Content(), &td)
80                 if err != nil {
81                         return err
82                 }
83
84                 // Try to create brand new role or update one
85                 // First add the keys, then the paths.  We can only add keys and paths in this scenario
86                 err = repo.UpdateDelegationKeys(c.Scope(), td.AddKeys, []string{}, td.NewThreshold)
87                 if err != nil {
88                         return err
89                 }
90                 return repo.UpdateDelegationPaths(c.Scope(), td.AddPaths, []string{}, false)
91         case changelist.ActionUpdate:
92                 td := changelist.TUFDelegation{}
93                 err := json.Unmarshal(c.Content(), &td)
94                 if err != nil {
95                         return err
96                 }
97                 if data.IsWildDelegation(c.Scope()) {
98                         return repo.PurgeDelegationKeys(c.Scope(), td.RemoveKeys)
99                 }
100
101                 delgRole, err := repo.GetDelegationRole(c.Scope())
102                 if err != nil {
103                         return err
104                 }
105
106                 // We need to translate the keys from canonical ID to TUF ID for compatibility
107                 canonicalToTUFID := make(map[string]string)
108                 for tufID, pubKey := range delgRole.Keys {
109                         canonicalID, err := utils.CanonicalKeyID(pubKey)
110                         if err != nil {
111                                 return err
112                         }
113                         canonicalToTUFID[canonicalID] = tufID
114                 }
115
116                 removeTUFKeyIDs := []string{}
117                 for _, canonID := range td.RemoveKeys {
118                         removeTUFKeyIDs = append(removeTUFKeyIDs, canonicalToTUFID[canonID])
119                 }
120
121                 err = repo.UpdateDelegationKeys(c.Scope(), td.AddKeys, removeTUFKeyIDs, td.NewThreshold)
122                 if err != nil {
123                         return err
124                 }
125                 return repo.UpdateDelegationPaths(c.Scope(), td.AddPaths, td.RemovePaths, td.ClearAllPaths)
126         case changelist.ActionDelete:
127                 return repo.DeleteDelegation(c.Scope())
128         default:
129                 return fmt.Errorf("unsupported action against delegations: %s", c.Action())
130         }
131
132 }
133
134 func changeTargetMeta(repo *tuf.Repo, c changelist.Change) error {
135         var err error
136         switch c.Action() {
137         case changelist.ActionCreate:
138                 logrus.Debug("changelist add: ", c.Path())
139                 meta := &data.FileMeta{}
140                 err = json.Unmarshal(c.Content(), meta)
141                 if err != nil {
142                         return err
143                 }
144                 files := data.Files{c.Path(): *meta}
145
146                 // Attempt to add the target to this role
147                 if _, err = repo.AddTargets(c.Scope(), files); err != nil {
148                         logrus.Errorf("couldn't add target to %s: %s", c.Scope(), err.Error())
149                 }
150
151         case changelist.ActionDelete:
152                 logrus.Debug("changelist remove: ", c.Path())
153
154                 // Attempt to remove the target from this role
155                 if err = repo.RemoveTargets(c.Scope(), c.Path()); err != nil {
156                         logrus.Errorf("couldn't remove target from %s: %s", c.Scope(), err.Error())
157                 }
158
159         default:
160                 err = fmt.Errorf("action not yet supported: %s", c.Action())
161         }
162         return err
163 }
164
165 func applyRootChange(repo *tuf.Repo, c changelist.Change) error {
166         var err error
167         switch c.Type() {
168         case changelist.TypeRootRole:
169                 err = applyRootRoleChange(repo, c)
170         default:
171                 err = fmt.Errorf("type of root change not yet supported: %s", c.Type())
172         }
173         return err // might be nil
174 }
175
176 func applyRootRoleChange(repo *tuf.Repo, c changelist.Change) error {
177         switch c.Action() {
178         case changelist.ActionCreate:
179                 // replaces all keys for a role
180                 d := &changelist.TUFRootData{}
181                 err := json.Unmarshal(c.Content(), d)
182                 if err != nil {
183                         return err
184                 }
185                 err = repo.ReplaceBaseKeys(d.RoleName, d.Keys...)
186                 if err != nil {
187                         return err
188                 }
189         default:
190                 return fmt.Errorf("action not yet supported for root: %s", c.Action())
191         }
192         return nil
193 }
194
195 func nearExpiry(r data.SignedCommon) bool {
196         plus6mo := time.Now().AddDate(0, 6, 0)
197         return r.Expires.Before(plus6mo)
198 }
199
200 func warnRolesNearExpiry(r *tuf.Repo) {
201         //get every role and its respective signed common and call nearExpiry on it
202         //Root check
203         if nearExpiry(r.Root.Signed.SignedCommon) {
204                 logrus.Warn("root is nearing expiry, you should re-sign the role metadata")
205         }
206         //Targets and delegations check
207         for role, signedTOrD := range r.Targets {
208                 //signedTOrD is of type *data.SignedTargets
209                 if nearExpiry(signedTOrD.Signed.SignedCommon) {
210                         logrus.Warn(role, " metadata is nearing expiry, you should re-sign the role metadata")
211                 }
212         }
213         //Snapshot check
214         if nearExpiry(r.Snapshot.Signed.SignedCommon) {
215                 logrus.Warn("snapshot is nearing expiry, you should re-sign the role metadata")
216         }
217         //do not need to worry about Timestamp, notary signer will re-sign with the timestamp key
218 }
219
220 // Fetches a public key from a remote store, given a gun and role
221 func getRemoteKey(url, gun, role string, rt http.RoundTripper) (data.PublicKey, error) {
222         remote, err := getRemoteStore(url, gun, rt)
223         if err != nil {
224                 return nil, err
225         }
226         rawPubKey, err := remote.GetKey(role)
227         if err != nil {
228                 return nil, err
229         }
230
231         pubKey, err := data.UnmarshalPublicKey(rawPubKey)
232         if err != nil {
233                 return nil, err
234         }
235
236         return pubKey, nil
237 }
238
239 // Rotates a private key in a remote store and returns the public key component
240 func rotateRemoteKey(url, gun, role string, rt http.RoundTripper) (data.PublicKey, error) {
241         remote, err := getRemoteStore(url, gun, rt)
242         if err != nil {
243                 return nil, err
244         }
245         rawPubKey, err := remote.RotateKey(role)
246         if err != nil {
247                 return nil, err
248         }
249
250         pubKey, err := data.UnmarshalPublicKey(rawPubKey)
251         if err != nil {
252                 return nil, err
253         }
254
255         return pubKey, nil
256 }
257
258 // signs and serializes the metadata for a canonical role in a TUF repo to JSON
259 func serializeCanonicalRole(tufRepo *tuf.Repo, role string) (out []byte, err error) {
260         var s *data.Signed
261         switch {
262         case role == data.CanonicalRootRole:
263                 s, err = tufRepo.SignRoot(data.DefaultExpires(role))
264         case role == data.CanonicalSnapshotRole:
265                 s, err = tufRepo.SignSnapshot(data.DefaultExpires(role))
266         case tufRepo.Targets[role] != nil:
267                 s, err = tufRepo.SignTargets(
268                         role, data.DefaultExpires(data.CanonicalTargetsRole))
269         default:
270                 err = fmt.Errorf("%s not supported role to sign on the client", role)
271         }
272
273         if err != nil {
274                 return
275         }
276
277         return json.Marshal(s)
278 }