Browse code

Merge pull request #21046 from cyli/use-notary-cli

Sign all first-level delegation roles when doing a trusted push

Vincent Demeester authored on 2016/03/22 15:42:21
Showing 20 changed files
... ...
@@ -258,6 +258,11 @@ func (cli *DockerCli) trustedReference(ref reference.NamedTagged) (reference.Can
258 258
 	if err != nil {
259 259
 		return nil, err
260 260
 	}
261
+	// Only list tags in the top level targets role or the releases delegation role - ignore
262
+	// all other delegation roles
263
+	if t.Role != releasesRole && t.Role != data.CanonicalTargetsRole {
264
+		return nil, notaryError(repoInfo.FullName(), fmt.Errorf("No trust data for %s", ref.Tag()))
265
+	}
261 266
 	r, err := convertTarget(t.Target)
262 267
 	if err != nil {
263 268
 		return nil, err
... ...
@@ -331,13 +336,28 @@ func (cli *DockerCli) trustedPull(repoInfo *registry.RepositoryInfo, ref registr
331 331
 				fmt.Fprintf(cli.out, "Skipping target for %q\n", repoInfo.Name())
332 332
 				continue
333 333
 			}
334
+			// Only list tags in the top level targets role or the releases delegation role - ignore
335
+			// all other delegation roles
336
+			if tgt.Role != releasesRole && tgt.Role != data.CanonicalTargetsRole {
337
+				continue
338
+			}
334 339
 			refs = append(refs, t)
335 340
 		}
341
+		if len(refs) == 0 {
342
+			return notaryError(repoInfo.FullName(), fmt.Errorf("No trusted tags for %s", repoInfo.FullName()))
343
+		}
336 344
 	} else {
337 345
 		t, err := notaryRepo.GetTargetByName(ref.String(), releasesRole, data.CanonicalTargetsRole)
338 346
 		if err != nil {
339 347
 			return notaryError(repoInfo.FullName(), err)
340 348
 		}
349
+		// Only get the tag if it's in the top level targets role or the releases delegation role
350
+		// ignore it if it's in any other delegation roles
351
+		if t.Role != releasesRole && t.Role != data.CanonicalTargetsRole {
352
+			return notaryError(repoInfo.FullName(), fmt.Errorf("No trust data for %s", ref.String()))
353
+		}
354
+
355
+		logrus.Debugf("retrieving target for %s role\n", t.Role)
341 356
 		r, err := convertTarget(t.Target)
342 357
 		if err != nil {
343 358
 			return err
... ...
@@ -441,39 +461,95 @@ func (cli *DockerCli) trustedPush(repoInfo *registry.RepositoryInfo, tag string,
441 441
 		return err
442 442
 	}
443 443
 
444
-	if err := repo.AddTarget(target, releasesRole); err != nil {
445
-		return err
444
+	// get the latest repository metadata so we can figure out which roles to sign
445
+	_, err = repo.Update(false)
446
+
447
+	switch err.(type) {
448
+	case client.ErrRepoNotInitialized, client.ErrRepositoryNotExist:
449
+		keys := repo.CryptoService.ListKeys(data.CanonicalRootRole)
450
+		var rootKeyID string
451
+		// always select the first root key
452
+		if len(keys) > 0 {
453
+			sort.Strings(keys)
454
+			rootKeyID = keys[0]
455
+		} else {
456
+			rootPublicKey, err := repo.CryptoService.Create(data.CanonicalRootRole, data.ECDSAKey)
457
+			if err != nil {
458
+				return err
459
+			}
460
+			rootKeyID = rootPublicKey.ID()
461
+		}
462
+
463
+		// Initialize the notary repository with a remotely managed snapshot key
464
+		if err := repo.Initialize(rootKeyID, data.CanonicalSnapshotRole); err != nil {
465
+			return notaryError(repoInfo.FullName(), err)
466
+		}
467
+		fmt.Fprintf(cli.out, "Finished initializing %q\n", repoInfo.FullName())
468
+		err = repo.AddTarget(target, data.CanonicalTargetsRole)
469
+	case nil:
470
+		// already initialized and we have successfully downloaded the latest metadata
471
+		err = cli.addTargetToAllSignableRoles(repo, target)
472
+	default:
473
+		return notaryError(repoInfo.FullName(), err)
446 474
 	}
447 475
 
448
-	err = repo.Publish()
449 476
 	if err == nil {
450
-		fmt.Fprintf(cli.out, "Successfully signed %q:%s\n", repoInfo.FullName(), tag)
451
-		return nil
452
-	} else if _, ok := err.(client.ErrRepoNotInitialized); !ok {
477
+		err = repo.Publish()
478
+	}
479
+
480
+	if err != nil {
453 481
 		fmt.Fprintf(cli.out, "Failed to sign %q:%s - %s\n", repoInfo.FullName(), tag, err.Error())
454 482
 		return notaryError(repoInfo.FullName(), err)
455 483
 	}
456 484
 
457
-	keys := repo.CryptoService.ListKeys(data.CanonicalRootRole)
485
+	fmt.Fprintf(cli.out, "Successfully signed %q:%s\n", repoInfo.FullName(), tag)
486
+	return nil
487
+}
458 488
 
459
-	var rootKeyID string
460
-	// always select the first root key
461
-	if len(keys) > 0 {
462
-		sort.Strings(keys)
463
-		rootKeyID = keys[0]
464
-	} else {
465
-		rootPublicKey, err := repo.CryptoService.Create(data.CanonicalRootRole, data.ECDSAKey)
466
-		if err != nil {
467
-			return err
489
+// Attempt to add the image target to all the top level delegation roles we can
490
+// (based on whether we have the signing key and whether the role's path allows
491
+// us to).
492
+// If there are no delegation roles, we add to the targets role.
493
+func (cli *DockerCli) addTargetToAllSignableRoles(repo *client.NotaryRepository, target *client.Target) error {
494
+	var signableRoles []string
495
+
496
+	// translate the full key names, which includes the GUN, into just the key IDs
497
+	allCanonicalKeyIDs := make(map[string]struct{})
498
+	for fullKeyID := range repo.CryptoService.ListAllKeys() {
499
+		allCanonicalKeyIDs[path.Base(fullKeyID)] = struct{}{}
500
+	}
501
+
502
+	allDelegationRoles, err := repo.GetDelegationRoles()
503
+	if err != nil {
504
+		return err
505
+	}
506
+
507
+	// if there are no delegation roles, then just try to sign it into the targets role
508
+	if len(allDelegationRoles) == 0 {
509
+		return repo.AddTarget(target, data.CanonicalTargetsRole)
510
+	}
511
+
512
+	// there are delegation roles, find every delegation role we have a key for, and
513
+	// attempt to sign into into all those roles.
514
+	for _, delegationRole := range allDelegationRoles {
515
+		// We do not support signing any delegation role that isn't a direct child of the targets role.
516
+		// Also don't bother checking the keys if we can't add the target
517
+		// to this role due to path restrictions
518
+		if path.Dir(delegationRole.Name) != data.CanonicalTargetsRole || !delegationRole.CheckPaths(target.Name) {
519
+			continue
520
+		}
521
+
522
+		for _, canonicalKeyID := range delegationRole.KeyIDs {
523
+			if _, ok := allCanonicalKeyIDs[canonicalKeyID]; ok {
524
+				signableRoles = append(signableRoles, delegationRole.Name)
525
+				break
526
+			}
468 527
 		}
469
-		rootKeyID = rootPublicKey.ID()
470 528
 	}
471 529
 
472
-	// Initialize the notary repository with a remotely managed snapshot key
473
-	if err := repo.Initialize(rootKeyID, data.CanonicalSnapshotRole); err != nil {
474
-		return notaryError(repoInfo.FullName(), err)
530
+	if len(signableRoles) == 0 {
531
+		return fmt.Errorf("no valid signing keys for delegation roles")
475 532
 	}
476
-	fmt.Fprintf(cli.out, "Finished initializing %q\n", repoInfo.FullName())
477 533
 
478
-	return notaryError(repoInfo.FullName(), repo.Publish())
534
+	return repo.AddTarget(target, signableRoles...)
479 535
 }
... ...
@@ -108,19 +108,13 @@ $ docker pull someimage@sha256:d149ab53f8718e987c3a3024bb8aa0e2caadf6c0328f1d9d8
108 108
 ```
109 109
 
110 110
 Trust for an image tag is managed through the use of signing keys. A key set is
111
-created when an operation using content trust is first invoked. Docker's content
112
-trust makes use of four different keys:
111
+created when an operation using content trust is first invoked. A key set consists
112
+of the following classes of keys:
113 113
 
114
-| Key                 | Description                                                                                                                                                                                                                                                                                                                                                                         |
115
-|---------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------|
116
-| root key         | Root of content trust for a image tag. When content trust is enabled, you create the root key once. |
117
-| target and snapshot | These two keys are known together as the "repository" key. When content trust is enabled, you create this key when you add a new image repository. If you have the root key, you can export the repository key and allow other publishers to sign the image tags.    |
118
-| timestamp           | This key applies to a repository. It allows Docker repositories to have freshness security guarantees without requiring periodic content refreshes on the client's side.                                                                                                              |
119
-
120
-With the exception of the timestamp, all the keys are generated and stored locally
121
-client-side. The timestamp is safely generated and stored in a signing server that
122
-is deployed alongside the Docker registry. All keys are generated in a backend
123
-service that isn't directly exposed to the internet and are encrypted at rest.
114
+- an offline key that is the root of content trust for a image tag
115
+- repository or tagging keys that sign tags
116
+- server-managed keys such as the timestamp key, which provides freshness
117
+	security guarantees for your repository
124 118
 
125 119
 The following image depicts the various signing keys and their relationships:
126 120
 
... ...
@@ -133,9 +127,9 @@ The following image depicts the various signing keys and their relationships:
133 133
 >tag from this repository prior to the loss.
134 134
 
135 135
 You should backup the root key somewhere safe. Given that it is only required
136
-to create new repositories, it is a good idea to store it offline. Make sure you
137
-read [Manage keys for content trust](trust_key_mng.md) information
138
-for details on securing, and backing up your keys. 
136
+to create new repositories, it is a good idea to store it offline.
137
+For details on securing, and backing up your keys, make sure you
138
+read how to [manage keys for content trust](trust_key_mng.md).
139 139
 
140 140
 ## Survey of typical content trust operations
141 141
 
... ...
@@ -302,4 +296,5 @@ $  docker push --disable-content-trust docker/trusttest:untrusted
302 302
 
303 303
 * [Manage keys for content trust](trust_key_mng.md)
304 304
 * [Automation with content trust](trust_automation.md)
305
+* [Delegations for content trust](trust_delegation.md)
305 306
 * [Play in a content trust sandbox](trust_sandbox.md)
... ...
@@ -17,4 +17,5 @@ The following topics are available:
17 17
 * [Content trust in Docker](content_trust.md)
18 18
 * [Manage keys for content trust](trust_key_mng.md)
19 19
 * [Automation with content trust](trust_automation.md)
20
+* [Delegations for content trust](trust_delegation.md)
20 21
 * [Play in a content trust sandbox](trust_sandbox.md)
... ...
@@ -73,7 +73,8 @@ unable to process Dockerfile: No trust data for notrust
73 73
 
74 74
 ## Related information
75 75
 
76
-* [Content trust in Docker](content_trust.md) 
76
+* [Content trust in Docker](content_trust.md)
77 77
 * [Manage keys for content trust](trust_key_mng.md)
78
+* [Delegations for content trust](trust_delegation.md)
78 79
 * [Play in a content trust sandbox](trust_sandbox.md)
79 80
 
80 81
new file mode 100644
... ...
@@ -0,0 +1,226 @@
0
+<!--[metadata]>
1
+title = "Delegations for content trust"
2
+description = "Delegations for content trust"
3
+keywords = ["trust, security, delegations, keys, repository"]
4
+[menu.main]
5
+parent= "smn_content_trust"
6
+<![end-metadata]-->
7
+
8
+# Delegations for content trust
9
+
10
+Docker Engine supports the usage of the `targets/releases` delegation as the
11
+canonical source of a trusted image tag.
12
+
13
+Using this delegation allows you to collaborate with other publishers without
14
+sharing your repository key (a combination of your targets and snapshot keys -
15
+please see "[Manage keys for content trust](trust_key_mng.md)" for more information).
16
+A collaborator can keep their own delegation key private.
17
+
18
+The `targest/releases` delegation is currently an optional feature - in order
19
+to set up delegations, you must use the Notary CLI:
20
+
21
+1. [Download the client](https://github.com/docker/notary/releases) and ensure that it is
22
+available on your path
23
+
24
+2. Create a configuration file at `~/.notary/config.json` with the following content:
25
+
26
+	```
27
+	{
28
+	  "trust_dir" : "~/.docker/trust",
29
+	  "remote_server": {
30
+	    "url": "https://notary.docker.io"
31
+	  }
32
+	}
33
+	```
34
+
35
+	This tells Notary where the Docker Content Trust data is stored, and to use the
36
+	Notary server used for images in Docker Hub.
37
+
38
+For more detailed information about how to use Notary outside of the default
39
+Docker Content Trust use cases, please refer to the
40
+[the Notary CLI documentation](https://docs.docker.com/notary/getting_started/).
41
+
42
+Note that when publishing and listing delegation changes using the Notary client,
43
+your Docker Hub credentials are required.
44
+
45
+## Generating delegation keys
46
+
47
+Your collaborator needs to generate a private key (either RSA or ECDSA)
48
+and give you the public key so that you can add it to the `targets/releases`
49
+delegation.
50
+
51
+The easiest way to for them to generate these keys is with OpenSSL.
52
+Here is an example of how to generate a 2048-bit RSA portion key (all RSA keys
53
+must be at least 2048 bits):
54
+
55
+```
56
+$ opensl genrsa -out delegation.key 2048
57
+Generating RSA private key, 2048 bit long modulus
58
+....................................................+++
59
+............+++
60
+e is 65537 (0x10001)
61
+
62
+```
63
+
64
+They should keep `delegation.key` private - this is what they will use to sign
65
+tags.
66
+
67
+Then they need to generate a x509 certificate containing the public key, which is
68
+what they will give to you.  Here is the command to generate a CSR (certificate
69
+signing request):
70
+
71
+```
72
+$ openssl req -new -sha256 -key delegation.key -out delegation.csr
73
+```
74
+
75
+Then they can send it to whichever CA you trust to sign certificates, or they
76
+can self-sign the certificate (in this example, creating a certificate that is
77
+valid for 1 year):
78
+
79
+```
80
+$ openssl x509 -req -days 365 -in delegation.csr -signkey delegation.key -out delegation.crt
81
+```
82
+
83
+Then they need to give you `delegation.crt`, whether it is self-signed or signed
84
+by a CA.
85
+
86
+## Adding a delegation key to an existing repository
87
+
88
+If your repository was created using a version of Docker Engine prior to 1.11,
89
+then before adding any delegations, you should rotate the snapshot key to the server
90
+so that collaborators will not require your snapshot key to sign and publish tags:
91
+
92
+```
93
+$ notary key rotate docker.io/<username>/<imagename> snapshot -r
94
+```
95
+
96
+This tells Notary to rotate a key for your particular image repository - note that
97
+you must include the `docker.io/` prefix.  `snapshot -r` specifies that you want
98
+to rotate the snapshot key specifically, and you want the server to manage it (`-r`
99
+stands for "remote").
100
+
101
+When adding a delegation, your must acquire
102
+[the PEM-encoded x509 certificate with the public key](#generating-delegation-keys)
103
+of the collaborator you wish to delegate to.
104
+
105
+Assuming you have the certificate `delegation.crt`, you can add a delegation
106
+for this user and then publish the delegation change:
107
+
108
+```
109
+$ notary delegation add docker.io/<username>/<imagename> targets/releases delegation.crt --all-paths
110
+$ notary publish docker.io/<username>/<imagename>
111
+```
112
+
113
+The preceding example illustrates a request to add the delegation
114
+`targets/releases` to the image repository, if it doesn't exist.  Be sure to use
115
+`targets/releases` - Notary supports multiple delegation roles, so if you mistype
116
+the delegation name, the Notary CLI will not error.  However, Docker Engine
117
+supports reading only from `targets/releases`.
118
+
119
+It also adds the collaborator's public key to the delegation, enabling them to sign
120
+the `targets/releases` delegation so long as they have the private key corresponding
121
+to this public key.  The `--all-paths` flags tells Notary not to restrict the tag
122
+names that can be signed into `targets/releases`, which we highly recommend for
123
+`targets/releases`.
124
+
125
+Publishing the changes tells the server about the changes to the `targets/releases`
126
+delegation.
127
+
128
+After publishing, view the delegation information to ensure that you correctly added
129
+the keys to `targets/releases`:
130
+
131
+```
132
+$ notary delegation list docker.io/<username>/<imagename>
133
+
134
+      ROLE               PATHS                                   KEY IDS                                THRESHOLD
135
+---------------------------------------------------------------------------------------------------------------
136
+  targets/releases   "" <all paths>  729c7094a8210fd1e780e7b17b7bb55c9a28a48b871b07f65d97baf93898523a   1
137
+```
138
+
139
+You can see the `targets/releases` with its paths and the key ID you just added.
140
+
141
+Notary currently does not map collaborators names to keys, so we recommend
142
+that you add and list delegation keys one at a time, and keep a mapping of the key
143
+IDs to collaborators yourself should you need to remove a collaborator.
144
+
145
+## Removing a delegation key from an existing repository
146
+
147
+To revoke a collaborator's permission to sign tags for your image repository, you must
148
+know the IDs of their keys, because you need to remove their keys from the
149
+`targets/releases` delegation.
150
+
151
+```
152
+$ notary delegation remove docker.io/<username>/<imagename> targets/releases 729c7094a8210fd1e780e7b17b7bb55c9a28a48b871b07f65d97baf93898523a
153
+
154
+Removal of delegation role targets/releases with keys [729c7094a8210fd1e780e7b17b7bb55c9a28a48b871b07f65d97baf93898523a], to repository "docker.io/<username>/<imagename>" staged for next publish.
155
+```
156
+
157
+The revocation will take effect as soon as you publish:
158
+
159
+```
160
+$ notary publish docker.io/<username>/<imagename>
161
+```
162
+
163
+Note that by removing all the keys from the `targets/releases` delegation, the
164
+delegation (and any tags that are signed into it) is removed.  That means that
165
+these tags will all be deleted, and you may end up with older, legacy tags that
166
+were signed directly by the targets key.
167
+
168
+## Removing the `targets/releases` delegation entirely from a repository
169
+
170
+If you've decided that delegations aren't for you, you can delete the
171
+`targets/releases` delegation entirely. This also removes all the tags that
172
+are currently in `targets/releases`, however, and you may end up with older,
173
+legacy tags that were signed directly by the targets key.
174
+
175
+To delete the `targets/releases` delegation:
176
+
177
+```
178
+$ notary delegation remove docker.io/<username>/<imagename> targets/releases
179
+
180
+Are you sure you want to remove all data for this delegation? (yes/no)
181
+yes
182
+
183
+Forced removal (including all keys and paths) of delegation role targets/releases to repository "docker.io/<username>/<imagename>" staged for next publish.
184
+
185
+$ notary publish docker.io/<username>/<imagename>
186
+```
187
+
188
+## Pushing trusted data as a collaborator
189
+
190
+As a collaborator with a private key that has been added to a repository's
191
+`targets/releases` delegation, you need to import the private key that you
192
+generated into Content Trust.
193
+
194
+To do so, you can run:
195
+
196
+```
197
+$ notary key import delegation.key --role user
198
+```
199
+
200
+where `delegation.key` is the file containing your PEM-encoded private key.
201
+
202
+After you have done so, running `docker push` on any repository that
203
+includes your key in the `targets/releases` delegation will automatically sign
204
+tags using this imported key.
205
+
206
+## `docker push` behavior
207
+
208
+When running `docker push` with Docker Content Trust, Docker Engine
209
+will attempt to sign and push with the `targets/releases` delegation if it exists.
210
+If it does not, the targets key will be used to sign the tag, if the key is available.
211
+
212
+## `docker pull` and `docker build` behavior
213
+
214
+When running `docker pull` or `docker build` with Docker Content Trust, Docker
215
+Engine will pull tags only signed by the `targets/releases` delegation role or
216
+the legacy tags that were signed directly with the `targets` key.
217
+
218
+## Related information
219
+
220
+* [Content trust in Docker](content_trust.md)
221
+* [Manage keys for content trust](trust_key_mng.md)
222
+* [Automation with content trust](trust_automation.md)
223
+* [Play in a content trust sandbox](trust_sandbox.md)
... ...
@@ -11,18 +11,34 @@ parent= "smn_content_trust"
11 11
 # Manage keys for content trust
12 12
 
13 13
 Trust for an image tag is managed through the use of keys. Docker's content
14
-trust makes use four different keys:
14
+trust makes use of five different types of keys:
15 15
 
16 16
 | Key                 | Description                                                                                                                                                                                                                                                                                                                                                                         |
17 17
 |---------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------|
18
-| root key         | Root of content trust for a image tag. When content trust is enabled, you create the root key once. |
19
-| target and snapshot | These two keys are known together as the "repository" key. When content trust is enabled, you create this key when you add a new image repository. If you have the root key, you can export the repository key and allow other publishers to sign the image tags.    |
20
-| timestamp           | This key applies to a repository. It allows Docker repositories to have freshness security guarantees without requiring periodic content refreshes on the client's side.                                                                                                              |
18
+| root key         | Root of content trust for a image tag. When content trust is enabled, you create the root key once. Also known as the offline key, because it should be kept offline. |
19
+| targets          | This key allows you to sign image tags, to manage delegations including delegated keys or permitted delegation paths. Also known as the repository key, since this key determines what tags can be signed into an image repository. |
20
+| snapshot         | This key signs the current collection of image tags, preventing mix and match attacks.
21
+| timestamp        | This key allows Docker image repositories to have freshness security guarantees without requiring periodic content refreshes on the client's side. |
22
+| delegation       | Delegation keys are optional tagging keys and allow you to delegate signing image tags to other publishers without having to share your targets key. |
21 23
 
22
-With the exception of the timestamp, all the keys are generated and stored locally
23
-client-side. The timestamp is safely generated and stored in a signing server that
24
-is deployed alongside the Docker registry. All keys are generated in a backend
25
-service that isn't directly exposed to the internet and are encrypted at rest.
24
+When doing a `docker push` with Content Trust enabled for the first time, the
25
+root, targets, snapshot, and timestamp keys are generated automatically for
26
+the image repository:
27
+
28
+- The root and targets key are generated and stored locally client-side.
29
+
30
+- The timestamp and snapshot keys are safely generated and stored in a signing server
31
+	that is deployed alongside the Docker registry. These keys are generated in a backend
32
+	service that isn't directly exposed to the internet and are encrypted at rest.
33
+
34
+Delegation keys are optional, and not generated as part of the normal `docker`
35
+workflow.  They need to be
36
+[manually generated and added to the repository](trust_delegation.md#generating-delegation-keys).
37
+
38
+Note: Prior to Docker Engine 1.11, the snapshot key was also generated and stored
39
+locally client-side. [Use the Notary CLI to manage your snapshot key locally
40
+again](https://docs.docker.com/notary/advanced_usage/#rotate-keys) for
41
+repositories created with newer versions of Docker.
26 42
 
27 43
 ## Choosing a passphrase
28 44
 
... ...
@@ -68,6 +84,7 @@ the new key.
68 68
 
69 69
 ## Related information
70 70
 
71
-* [Content trust in Docker](content_trust.md) 
71
+* [Content trust in Docker](content_trust.md)
72 72
 * [Automation with content trust](trust_automation.md)
73
+* [Delegations for content trust](trust_delegation.md)
73 74
 * [Play in a content trust sandbox](trust_sandbox.md)
... ...
@@ -2,8 +2,11 @@ package main
2 2
 
3 3
 import (
4 4
 	"fmt"
5
+	"os"
6
+	"path/filepath"
5 7
 	"testing"
6 8
 
9
+	"github.com/docker/docker/cliconfig"
7 10
 	"github.com/docker/docker/pkg/reexec"
8 11
 	"github.com/go-check/check"
9 12
 )
... ...
@@ -206,5 +209,8 @@ func (s *DockerTrustSuite) TearDownTest(c *check.C) {
206 206
 	if s.not != nil {
207 207
 		s.not.Close()
208 208
 	}
209
+
210
+	// Remove trusted keys and metadata after test
211
+	os.RemoveAll(filepath.Join(cliconfig.ConfigDir(), "trust"))
209 212
 	s.ds.TearDownTest(c)
210 213
 }
... ...
@@ -5799,6 +5799,83 @@ func (s *DockerTrustSuite) TestBuildContextDirIsSymlink(c *check.C) {
5799 5799
 	}
5800 5800
 }
5801 5801
 
5802
+func (s *DockerTrustSuite) TestTrustedBuildTagFromReleasesRole(c *check.C) {
5803
+	testRequires(c, NotaryHosting)
5804
+
5805
+	latestTag := s.setupTrustedImage(c, "trusted-build-releases-role")
5806
+	repoName := strings.TrimSuffix(latestTag, ":latest")
5807
+
5808
+	// Now create the releases role
5809
+	s.notaryCreateDelegation(c, repoName, "targets/releases", s.not.keys[0].Public)
5810
+	s.notaryImportKey(c, repoName, "targets/releases", s.not.keys[0].Private)
5811
+	s.notaryPublish(c, repoName)
5812
+
5813
+	// push a different tag to the releases role
5814
+	otherTag := fmt.Sprintf("%s:other", repoName)
5815
+	dockerCmd(c, "tag", "busybox", otherTag)
5816
+
5817
+	pushCmd := exec.Command(dockerBinary, "push", otherTag)
5818
+	s.trustedCmd(pushCmd)
5819
+	out, _, err := runCommandWithOutput(pushCmd)
5820
+	c.Assert(err, check.IsNil, check.Commentf("Trusted push failed: %s", out))
5821
+	s.assertTargetInRoles(c, repoName, "other", "targets/releases")
5822
+	s.assertTargetNotInRoles(c, repoName, "other", "targets")
5823
+
5824
+	out, status := dockerCmd(c, "rmi", otherTag)
5825
+	c.Assert(status, check.Equals, 0, check.Commentf("docker rmi failed: %s", out))
5826
+
5827
+	dockerFile := fmt.Sprintf(`
5828
+  FROM %s
5829
+  RUN []
5830
+    `, otherTag)
5831
+
5832
+	name := "testtrustedbuildreleasesrole"
5833
+
5834
+	buildCmd := buildImageCmd(name, dockerFile, true)
5835
+	s.trustedCmd(buildCmd)
5836
+	out, _, err = runCommandWithOutput(buildCmd)
5837
+	c.Assert(err, check.IsNil, check.Commentf("Trusted build failed: %s", out))
5838
+	c.Assert(out, checker.Contains, fmt.Sprintf("FROM %s@sha", repoName))
5839
+}
5840
+
5841
+func (s *DockerTrustSuite) TestTrustedBuildTagIgnoresOtherDelegationRoles(c *check.C) {
5842
+	testRequires(c, NotaryHosting)
5843
+
5844
+	latestTag := s.setupTrustedImage(c, "trusted-build-releases-role")
5845
+	repoName := strings.TrimSuffix(latestTag, ":latest")
5846
+
5847
+	// Now create a non-releases delegation role
5848
+	s.notaryCreateDelegation(c, repoName, "targets/other", s.not.keys[0].Public)
5849
+	s.notaryImportKey(c, repoName, "targets/other", s.not.keys[0].Private)
5850
+	s.notaryPublish(c, repoName)
5851
+
5852
+	// push a different tag to the other role
5853
+	otherTag := fmt.Sprintf("%s:other", repoName)
5854
+	dockerCmd(c, "tag", "busybox", otherTag)
5855
+
5856
+	pushCmd := exec.Command(dockerBinary, "push", otherTag)
5857
+	s.trustedCmd(pushCmd)
5858
+	out, _, err := runCommandWithOutput(pushCmd)
5859
+	c.Assert(err, check.IsNil, check.Commentf("Trusted push failed: %s", out))
5860
+	s.assertTargetInRoles(c, repoName, "other", "targets/other")
5861
+	s.assertTargetNotInRoles(c, repoName, "other", "targets")
5862
+
5863
+	out, status := dockerCmd(c, "rmi", otherTag)
5864
+	c.Assert(status, check.Equals, 0, check.Commentf("docker rmi failed: %s", out))
5865
+
5866
+	dockerFile := fmt.Sprintf(`
5867
+  FROM %s
5868
+  RUN []
5869
+    `, otherTag)
5870
+
5871
+	name := "testtrustedbuildotherrole"
5872
+
5873
+	buildCmd := buildImageCmd(name, dockerFile, true)
5874
+	s.trustedCmd(buildCmd)
5875
+	out, _, err = runCommandWithOutput(buildCmd)
5876
+	c.Assert(err, check.NotNil, check.Commentf("Trusted build expected to fail: %s", out))
5877
+}
5878
+
5802 5879
 // Issue #15634: COPY fails when path starts with "null"
5803 5880
 func (s *DockerSuite) TestBuildNullStringInAddCopyVolume(c *check.C) {
5804 5881
 	name := "testbuildnullstringinaddcopyvolume"
... ...
@@ -254,3 +254,112 @@ func (s *DockerTrustSuite) TestTrustedPullDelete(c *check.C) {
254 254
 	_, err = inspectFieldWithError(imageID, "Id")
255 255
 	c.Assert(err, checker.NotNil, check.Commentf("image should have been deleted"))
256 256
 }
257
+
258
+func (s *DockerTrustSuite) TestTrustedPullReadsFromReleasesRole(c *check.C) {
259
+	testRequires(c, NotaryHosting)
260
+	repoName := fmt.Sprintf("%v/dockerclireleasesdelegationpulling/trusted", privateRegistryURL)
261
+	targetName := fmt.Sprintf("%s:latest", repoName)
262
+
263
+	// Push with targets first, initializing the repo
264
+	dockerCmd(c, "tag", "busybox", targetName)
265
+	pushCmd := exec.Command(dockerBinary, "push", targetName)
266
+	s.trustedCmd(pushCmd)
267
+	out, _, err := runCommandWithOutput(pushCmd)
268
+	c.Assert(err, check.IsNil, check.Commentf(out))
269
+	s.assertTargetInRoles(c, repoName, "latest", "targets")
270
+
271
+	// Try pull, check we retrieve from targets role
272
+	pullCmd := exec.Command(dockerBinary, "-D", "pull", repoName)
273
+	s.trustedCmd(pullCmd)
274
+	out, _, err = runCommandWithOutput(pullCmd)
275
+	c.Assert(err, check.IsNil, check.Commentf(out))
276
+	c.Assert(out, checker.Contains, "retrieving target for targets role")
277
+
278
+	// Now we'll create the releases role, and try pushing and pulling
279
+	s.notaryCreateDelegation(c, repoName, "targets/releases", s.not.keys[0].Public)
280
+	s.notaryImportKey(c, repoName, "targets/releases", s.not.keys[0].Private)
281
+	s.notaryPublish(c, repoName)
282
+
283
+	// try a pull, check that we can still pull because we can still read the
284
+	// old tag in the targets role
285
+	pullCmd = exec.Command(dockerBinary, "-D", "pull", repoName)
286
+	s.trustedCmd(pullCmd)
287
+	out, _, err = runCommandWithOutput(pullCmd)
288
+	c.Assert(err, check.IsNil, check.Commentf(out))
289
+	c.Assert(out, checker.Contains, "retrieving target for targets role")
290
+
291
+	// try a pull -a, check that it succeeds because we can still pull from the
292
+	// targets role
293
+	pullCmd = exec.Command(dockerBinary, "-D", "pull", "-a", repoName)
294
+	s.trustedCmd(pullCmd)
295
+	out, _, err = runCommandWithOutput(pullCmd)
296
+	c.Assert(err, check.IsNil, check.Commentf(out))
297
+
298
+	// Push, should sign with targets/releases
299
+	dockerCmd(c, "tag", "busybox", targetName)
300
+	pushCmd = exec.Command(dockerBinary, "push", targetName)
301
+	s.trustedCmd(pushCmd)
302
+	out, _, err = runCommandWithOutput(pushCmd)
303
+	s.assertTargetInRoles(c, repoName, "latest", "targets", "targets/releases")
304
+
305
+	// Try pull, check we retrieve from targets/releases role
306
+	pullCmd = exec.Command(dockerBinary, "-D", "pull", repoName)
307
+	s.trustedCmd(pullCmd)
308
+	out, _, err = runCommandWithOutput(pullCmd)
309
+	c.Assert(out, checker.Contains, "retrieving target for targets/releases role")
310
+
311
+	// Create another delegation that we'll sign with
312
+	s.notaryCreateDelegation(c, repoName, "targets/other", s.not.keys[1].Public)
313
+	s.notaryImportKey(c, repoName, "targets/other", s.not.keys[1].Private)
314
+	s.notaryPublish(c, repoName)
315
+
316
+	dockerCmd(c, "tag", "busybox", targetName)
317
+	pushCmd = exec.Command(dockerBinary, "push", targetName)
318
+	s.trustedCmd(pushCmd)
319
+	out, _, err = runCommandWithOutput(pushCmd)
320
+	s.assertTargetInRoles(c, repoName, "latest", "targets", "targets/releases", "targets/other")
321
+
322
+	// Try pull, check we retrieve from targets/releases role
323
+	pullCmd = exec.Command(dockerBinary, "-D", "pull", repoName)
324
+	s.trustedCmd(pullCmd)
325
+	out, _, err = runCommandWithOutput(pullCmd)
326
+	c.Assert(out, checker.Contains, "retrieving target for targets/releases role")
327
+}
328
+
329
+func (s *DockerTrustSuite) TestTrustedPullIgnoresOtherDelegationRoles(c *check.C) {
330
+	testRequires(c, NotaryHosting)
331
+	repoName := fmt.Sprintf("%v/dockerclipullotherdelegation/trusted", privateRegistryURL)
332
+	targetName := fmt.Sprintf("%s:latest", repoName)
333
+
334
+	// We'll create a repo first with a non-release delegation role, so that when we
335
+	// push we'll sign it into the delegation role
336
+	s.notaryInitRepo(c, repoName)
337
+	s.notaryCreateDelegation(c, repoName, "targets/other", s.not.keys[0].Public)
338
+	s.notaryImportKey(c, repoName, "targets/other", s.not.keys[0].Private)
339
+	s.notaryPublish(c, repoName)
340
+
341
+	// Push should write to the delegation role, not targets
342
+	dockerCmd(c, "tag", "busybox", targetName)
343
+	pushCmd := exec.Command(dockerBinary, "push", targetName)
344
+	s.trustedCmd(pushCmd)
345
+	out, _, err := runCommandWithOutput(pushCmd)
346
+	c.Assert(err, check.IsNil, check.Commentf(out))
347
+	s.assertTargetInRoles(c, repoName, "latest", "targets/other")
348
+	s.assertTargetNotInRoles(c, repoName, "latest", "targets")
349
+
350
+	// Try pull - we should fail, since pull will only pull from the targets/releases
351
+	// role or the targets role
352
+	pullCmd := exec.Command(dockerBinary, "-D", "pull", repoName)
353
+	s.trustedCmd(pullCmd)
354
+	out, _, err = runCommandWithOutput(pullCmd)
355
+	c.Assert(err, check.NotNil, check.Commentf(out))
356
+	c.Assert(out, checker.Contains, "No trust data for")
357
+
358
+	// try a pull -a: we should fail since pull will only pull from the targets/releases
359
+	// role or the targets role
360
+	pullCmd = exec.Command(dockerBinary, "-D", "pull", "-a", repoName)
361
+	s.trustedCmd(pullCmd)
362
+	out, _, err = runCommandWithOutput(pullCmd)
363
+	c.Assert(err, check.NotNil, check.Commentf(out))
364
+	c.Assert(out, checker.Contains, "No trusted tags for")
365
+}
... ...
@@ -497,37 +497,143 @@ func (s *DockerTrustSuite) TestTrustedPushWithExpiredTimestamp(c *check.C) {
497 497
 	})
498 498
 }
499 499
 
500
-func (s *DockerTrustSuite) TestTrustedPushWithReleasesDelegation(c *check.C) {
500
+func (s *DockerTrustSuite) TestTrustedPushWithReleasesDelegationOnly(c *check.C) {
501 501
 	testRequires(c, NotaryHosting)
502
-	repoName := fmt.Sprintf("%v/dockerclireleasedelegation/trusted", privateRegistryURL)
502
+	repoName := fmt.Sprintf("%v/dockerclireleasedelegationinitfirst/trusted", privateRegistryURL)
503 503
 	targetName := fmt.Sprintf("%s:latest", repoName)
504
-	pwd := "12345678"
505
-	s.setupDelegations(c, repoName, pwd)
504
+	s.notaryInitRepo(c, repoName)
505
+	s.notaryCreateDelegation(c, repoName, "targets/releases", s.not.keys[0].Public)
506
+	s.notaryPublish(c, repoName)
507
+
508
+	s.notaryImportKey(c, repoName, "targets/releases", s.not.keys[0].Private)
506 509
 
507 510
 	// tag the image and upload it to the private registry
508 511
 	dockerCmd(c, "tag", "busybox", targetName)
509 512
 
510
-	pushCmd := exec.Command(dockerBinary, "-D", "push", targetName)
511
-	s.trustedCmdWithPassphrases(pushCmd, pwd, pwd)
513
+	pushCmd := exec.Command(dockerBinary, "push", targetName)
514
+	s.trustedCmd(pushCmd)
512 515
 	out, _, err := runCommandWithOutput(pushCmd)
513 516
 	c.Assert(err, check.IsNil, check.Commentf("trusted push failed: %s\n%s", err, out))
514 517
 	c.Assert(out, checker.Contains, "Signing and pushing trust metadata", check.Commentf("Missing expected output on trusted push with existing tag"))
518
+	// check to make sure that the target has been added to targets/releases and not targets
519
+	s.assertTargetInRoles(c, repoName, "latest", "targets/releases")
520
+	s.assertTargetNotInRoles(c, repoName, "latest", "targets")
515 521
 
516 522
 	// Try pull after push
523
+	os.RemoveAll(filepath.Join(cliconfig.ConfigDir(), "trust"))
524
+
517 525
 	pullCmd := exec.Command(dockerBinary, "pull", targetName)
518 526
 	s.trustedCmd(pullCmd)
519 527
 	out, _, err = runCommandWithOutput(pullCmd)
520 528
 	c.Assert(err, check.IsNil, check.Commentf(out))
521 529
 	c.Assert(string(out), checker.Contains, "Status: Downloaded", check.Commentf(out))
530
+}
522 531
 
523
-	// check to make sure that the target has been added to targets/releases and not targets
524
-	contents, err := ioutil.ReadFile(filepath.Join(cliconfig.ConfigDir(), "trust/tuf", repoName, "metadata/targets.json"))
525
-	c.Assert(err, check.IsNil, check.Commentf("Unable to read targets metadata"))
526
-	c.Assert(strings.Contains(string(contents), `"latest"`), checker.False, check.Commentf(string(contents)))
532
+func (s *DockerTrustSuite) TestTrustedPushSignsAllFirstLevelRolesWeHaveKeysFor(c *check.C) {
533
+	testRequires(c, NotaryHosting)
534
+	repoName := fmt.Sprintf("%v/dockerclimanyroles/trusted", privateRegistryURL)
535
+	targetName := fmt.Sprintf("%s:latest", repoName)
536
+	s.notaryInitRepo(c, repoName)
537
+	s.notaryCreateDelegation(c, repoName, "targets/role1", s.not.keys[0].Public)
538
+	s.notaryCreateDelegation(c, repoName, "targets/role2", s.not.keys[1].Public)
539
+	s.notaryCreateDelegation(c, repoName, "targets/role3", s.not.keys[2].Public)
540
+
541
+	// import everything except the third key
542
+	s.notaryImportKey(c, repoName, "targets/role1", s.not.keys[0].Private)
543
+	s.notaryImportKey(c, repoName, "targets/role2", s.not.keys[1].Private)
544
+
545
+	s.notaryCreateDelegation(c, repoName, "targets/role1/subrole", s.not.keys[3].Public)
546
+	s.notaryImportKey(c, repoName, "targets/role1/subrole", s.not.keys[3].Private)
547
+
548
+	s.notaryPublish(c, repoName)
549
+
550
+	// tag the image and upload it to the private registry
551
+	dockerCmd(c, "tag", "busybox", targetName)
552
+
553
+	pushCmd := exec.Command(dockerBinary, "push", targetName)
554
+	s.trustedCmd(pushCmd)
555
+	out, _, err := runCommandWithOutput(pushCmd)
556
+	c.Assert(err, check.IsNil, check.Commentf("trusted push failed: %s\n%s", err, out))
557
+	c.Assert(out, checker.Contains, "Signing and pushing trust metadata", check.Commentf("Missing expected output on trusted push with existing tag"))
558
+
559
+	// check to make sure that the target has been added to targets/role1 and targets/role2, and
560
+	// not targets (because there are delegations) or targets/role3 (due to missing key) or
561
+	// targets/role1/subrole (due to it being a second level delegation)
562
+	s.assertTargetInRoles(c, repoName, "latest", "targets/role1", "targets/role2")
563
+	s.assertTargetNotInRoles(c, repoName, "latest", "targets")
564
+
565
+	// Try pull after push
566
+	os.RemoveAll(filepath.Join(cliconfig.ConfigDir(), "trust"))
567
+
568
+	// pull should fail because none of these are the releases role
569
+	pullCmd := exec.Command(dockerBinary, "pull", targetName)
570
+	s.trustedCmd(pullCmd)
571
+	out, _, err = runCommandWithOutput(pullCmd)
572
+	c.Assert(err, check.NotNil, check.Commentf(out))
573
+}
574
+
575
+func (s *DockerTrustSuite) TestTrustedPushSignsForRolesWithKeysAndValidPaths(c *check.C) {
576
+	repoName := fmt.Sprintf("%v/dockerclirolesbykeysandpaths/trusted", privateRegistryURL)
577
+	targetName := fmt.Sprintf("%s:latest", repoName)
578
+	s.notaryInitRepo(c, repoName)
579
+	s.notaryCreateDelegation(c, repoName, "targets/role1", s.not.keys[0].Public, "l", "z")
580
+	s.notaryCreateDelegation(c, repoName, "targets/role2", s.not.keys[1].Public, "x", "y")
581
+	s.notaryCreateDelegation(c, repoName, "targets/role3", s.not.keys[2].Public, "latest")
582
+	s.notaryCreateDelegation(c, repoName, "targets/role4", s.not.keys[3].Public, "latest")
583
+
584
+	// import everything except the third key
585
+	s.notaryImportKey(c, repoName, "targets/role1", s.not.keys[0].Private)
586
+	s.notaryImportKey(c, repoName, "targets/role2", s.not.keys[1].Private)
587
+	s.notaryImportKey(c, repoName, "targets/role4", s.not.keys[3].Private)
588
+
589
+	s.notaryPublish(c, repoName)
590
+
591
+	// tag the image and upload it to the private registry
592
+	dockerCmd(c, "tag", "busybox", targetName)
593
+
594
+	pushCmd := exec.Command(dockerBinary, "push", targetName)
595
+	s.trustedCmd(pushCmd)
596
+	out, _, err := runCommandWithOutput(pushCmd)
597
+	c.Assert(err, check.IsNil, check.Commentf("trusted push failed: %s\n%s", err, out))
598
+	c.Assert(out, checker.Contains, "Signing and pushing trust metadata", check.Commentf("Missing expected output on trusted push with existing tag"))
599
+
600
+	// check to make sure that the target has been added to targets/role1 and targets/role4, and
601
+	// not targets (because there are delegations) or targets/role2 (due to path restrictions) or
602
+	// targets/role3 (due to missing key)
603
+	s.assertTargetInRoles(c, repoName, "latest", "targets/role1", "targets/role4")
604
+	s.assertTargetNotInRoles(c, repoName, "latest", "targets")
605
+
606
+	// Try pull after push
607
+	os.RemoveAll(filepath.Join(cliconfig.ConfigDir(), "trust"))
608
+
609
+	// pull should fail because none of these are the releases role
610
+	pullCmd := exec.Command(dockerBinary, "pull", targetName)
611
+	s.trustedCmd(pullCmd)
612
+	out, _, err = runCommandWithOutput(pullCmd)
613
+	c.Assert(err, check.NotNil, check.Commentf(out))
614
+}
615
+
616
+func (s *DockerTrustSuite) TestTrustedPushDoesntSignTargetsIfDelegationsExist(c *check.C) {
617
+	testRequires(c, NotaryHosting)
618
+	repoName := fmt.Sprintf("%v/dockerclireleasedelegationnotsignable/trusted", privateRegistryURL)
619
+	targetName := fmt.Sprintf("%s:latest", repoName)
620
+	s.notaryInitRepo(c, repoName)
621
+	s.notaryCreateDelegation(c, repoName, "targets/role1", s.not.keys[0].Public)
622
+	s.notaryPublish(c, repoName)
623
+
624
+	// do not import any delegations key
625
+
626
+	// tag the image and upload it to the private registry
627
+	dockerCmd(c, "tag", "busybox", targetName)
628
+
629
+	pushCmd := exec.Command(dockerBinary, "push", targetName)
630
+	s.trustedCmd(pushCmd)
631
+	out, _, err := runCommandWithOutput(pushCmd)
632
+	c.Assert(err, check.NotNil, check.Commentf("trusted push succeeded but should have failed:\n%s", out))
633
+	c.Assert(out, checker.Contains, "no valid signing keys",
634
+		check.Commentf("Missing expected output on trusted push without keys"))
527 635
 
528
-	contents, err = ioutil.ReadFile(filepath.Join(cliconfig.ConfigDir(), "trust/tuf", repoName, "metadata/targets/releases.json"))
529
-	c.Assert(err, check.IsNil, check.Commentf("Unable to read targets/releases metadata"))
530
-	c.Assert(string(contents), checker.Contains, `"latest"`, check.Commentf(string(contents)))
636
+	s.assertTargetNotInRoles(c, repoName, "latest", "targets", "targets/role1")
531 637
 }
532 638
 
533 639
 func (s *DockerRegistryAuthHtpasswdSuite) TestPushNoCredentialsNoRetry(c *check.C) {
534 640
new file mode 100644
... ...
@@ -0,0 +1,24 @@
0
+-----BEGIN CERTIFICATE-----
1
+MIID8jCCAtqgAwIBAgIJAJkxr+7rAgXbMA0GCSqGSIb3DQEBBQUAMFgxCzAJBgNV
2
+BAYTAlVTMQswCQYDVQQIEwJDQTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzEPMA0G
3
+A1UEChMGRG9ja2VyMRMwEQYDVQQDEwpkZWxlZ2F0aW9uMCAXDTE2MDMwODAyNDEy
4
+MFoYDzIxMTYwMjEzMDI0MTIwWjBYMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0Ex
5
+FjAUBgNVBAcTDVNhbiBGcmFuY2lzY28xDzANBgNVBAoTBkRvY2tlcjETMBEGA1UE
6
+AxMKZGVsZWdhdGlvbjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJuz
7
+To1qoL/RY5pNxdPkP/jiO3f/RTvz20C90EweaKgRdIV/vTUUE+mMRQulpf1vpCP9
8
+uidGfEoJcq4jM1H59XTYUoUvGbAMP3Iu7Uz0rF5v+Glm82Z0WGI+PkOnwRN2bJi4
9
+LhAch6QlA/48IOFH/O9jnHYMb45lQFpm+gOvatRyGkPZCftD3ntkhVMk1OJ7EZC4
10
+LYiwzmuPEYusO/qVgcHkGtIxLWAjGmDzrV3Q5orPVwwUOxNQdRRU1L2bhfUsodcb
11
+Fgi/LCz4xnGx4YpF0O24Y7/0SPotSyaT0RYyj/j/bIKvYB20g4P7469klde1Ariz
12
+UEIf12PlaJ/H/PaIlEcCAwEAAaOBvDCBuTAdBgNVHQ4EFgQUXZK4ZGswIq54W4VZ
13
+OJY7zXvvndwwgYkGA1UdIwSBgTB/gBRdkrhkazAirnhbhVk4ljvNe++d3KFcpFow
14
+WDELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRYwFAYDVQQHEw1TYW4gRnJhbmNp
15
+c2NvMQ8wDQYDVQQKEwZEb2NrZXIxEzARBgNVBAMTCmRlbGVnYXRpb26CCQCZMa/u
16
+6wIF2zAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQA2ktnjxB2lXF+g
17
+lTc2qp9LhjofgCWKwLgWEeCwXI2nUBNE4n00hA9or2wer2viWC4IJnG0kTyMzzYT
18
+m1lBpZ8BP6S3sSkvhohaqS+gBIUVB7U65tAof/SY2UHpeVJ1YpTE4F1GAUfqSY7V
19
+6IGHZAGiLeUS5kC6pzZA4siBhyCoYKRKEb9R82jSCHeFYS3ntwY1/gqcO/uIidVE
20
+2hLHlx6vBx9BEfXv31AGLoB3YocSTZLATwlrDHUQG1+oNh5ejQU1x/z+Y62EG5Jb
21
+u0yLDdJeSgup/DzPEoNpSihtdQZytKMK+KBmh22gDA5h+a6620zTZwCvJYxH9kkM
22
+IClUWwuD
23
+-----END CERTIFICATE-----
0 24
new file mode 100644
... ...
@@ -0,0 +1,27 @@
0
+-----BEGIN RSA PRIVATE KEY-----
1
+MIIEowIBAAKCAQEAm7NOjWqgv9Fjmk3F0+Q/+OI7d/9FO/PbQL3QTB5oqBF0hX+9
2
+NRQT6YxFC6Wl/W+kI/26J0Z8SglyriMzUfn1dNhShS8ZsAw/ci7tTPSsXm/4aWbz
3
+ZnRYYj4+Q6fBE3ZsmLguEByHpCUD/jwg4Uf872OcdgxvjmVAWmb6A69q1HIaQ9kJ
4
++0Pee2SFUyTU4nsRkLgtiLDOa48Ri6w7+pWBweQa0jEtYCMaYPOtXdDmis9XDBQ7
5
+E1B1FFTUvZuF9Syh1xsWCL8sLPjGcbHhikXQ7bhjv/RI+i1LJpPRFjKP+P9sgq9g
6
+HbSDg/vjr2SV17UCuLNQQh/XY+Von8f89oiURwIDAQABAoIBAB7DhfDRMaPU5n41
7
+gbIFNlKhuKhUCsT2wMqA9qgjlgAnOsOp4qObLPgHXBkaCLsTlPX7iw15ktM6HKul
8
+jt1SqxoEKAHitYugT+Tqur5q1afvLcD9s3f54wC+VaUefzquOnTOZ2ONj4tyOODB
9
+1qlMhQBzyRVWDbCv9tAl6p5RyaTh+8IULctlER6w9m3upT9NxoRi1PrPBCRiEKKo
10
+4zDRvfbT/0ucLD20GS6trPv4ihTCTU7ydFujioDkFyNzCzYNGBnImpQ9/xeT5/Ys
11
+IJQy9Tdn6V0rXMBBb1EhyBQYw5Oxy6d6tzhjvva6LaJBGo9yzX0NHt58Ymhgm1q/
12
+vscj1pECgYEAyegQFP7dkmUdXdNpdrIdCvKlvni3r/hwB/9H0sJHIJbfTusfzeLL
13
+5Q8QSZAsaR7tSgJfr9GMdOjntvefYjKLfl3SnG/wF91m05eYfkeiZXc9RGe+XXGu
14
+wv5u2m/G7a05XpW1JFX+1ORyj2x5KsvF7KDtWJyR5ryIsOwHZNGQpJ8CgYEAxWoo
15
+r2eJBc9Xj5bhhS0VxUFODXImfeQF2aG2rSeuWMY7k4vmVkJwhBZiPW/dHBu1aMPh
16
+/SY1W7cgzdVIf2RIF5MgzzkmoisEApZTiSwmP6A2bTx6miXwFCLTCHIDfiXJ0tQA
17
+Nb+Ln+exks4BfCgKHOqWTcWizKNE/8Gb6SnhB1kCgYAgM1Z9QrhrpJyuXg0v1PA0
18
+0sYEPpRtCB416Ey4HCvj0qwClhUYbNc/zMs4MDok+b22U/KWw8C21H4/+/X7XzxI
19
+BwaT1HZiF/lSPZcgbKRFsmKfCjyeAodwqctcIv+C4GGJ6C5fgSeHJHfwz8fzP1Rt
20
+jKzNuQq71c2nCb2UIqgC2QKBgEieoJDFmVYVy7P6YMNIrnV9bGTt1NMCilRgdH6F
21
+1lC5uzivge/BSPqN8V2AROoOF1GOnRcucvpmBx8wkhaqoQprCOqxr1CAWl1JRzly
22
+kC9flCXi1YbW5dXCabb1metRo0h2zAz5hTcxV9UVCt7NK8svUFMTnKuCc+NRKTVA
23
+PpMhAoGBAJ9rFgZpWHRVuzsangbGslq3fDYGENLJ2fPNjLgfgVLi+YotG9jfgQPW
24
+QCvoSA1CChxzEJEB5hzEOEv9pThnBNg1LWNj+a3N5anW2UBHMEWeCrVFZwJMVdSd
25
+srUFtap7da8iUddc+sHC5hHHFDBdqG4pDck/uTs3CNWRF/ZqzE/G
26
+-----END RSA PRIVATE KEY-----
0 27
new file mode 100644
... ...
@@ -0,0 +1,24 @@
0
+-----BEGIN CERTIFICATE-----
1
+MIID8jCCAtqgAwIBAgIJAMi/AxlwFquJMA0GCSqGSIb3DQEBBQUAMFgxCzAJBgNV
2
+BAYTAlVTMQswCQYDVQQIEwJDQTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzEPMA0G
3
+A1UEChMGRG9ja2VyMRMwEQYDVQQDEwpkZWxlZ2F0aW9uMCAXDTE2MDMwODAyNDEy
4
+MloYDzIxMTYwMjEzMDI0MTIyWjBYMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0Ex
5
+FjAUBgNVBAcTDVNhbiBGcmFuY2lzY28xDzANBgNVBAoTBkRvY2tlcjETMBEGA1UE
6
+AxMKZGVsZWdhdGlvbjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL/a
7
+1GO+02jt1p0sME+YGaK4+uZ9jezrpkCXKMsMfItgqCKRTX7YVuR7tnRt/Y1DNVqR
8
+nMeGc77soDag6eW4xrYrv9LwylUsOLanvK1d/8hDxZhzJjqlJBmz6BvLWDZUF9uu
9
+OjULL8yuP2cmRogjn0bqmdeKztrZtDQqQiwsG02nVjfuvVi3rP4G4DhL5fUoHB0R
10
+E6L9Su3/2OWGpdxZqkT7GAbjgLl4/4CXs00493m8xZIHXQ9559PiVlLfk6p6FjEV
11
+7irZp7XXSe1My/0HGebFXkYqEL9+My2od4w+qJmBT23aTduGTo8IZC7g9lwKEykA
12
+hWrYhR5tjkLvOsQIE7ECAwEAAaOBvDCBuTAdBgNVHQ4EFgQUHtEAVcwI3k7W5B6c
13
+L3w+eKQRsIYwgYkGA1UdIwSBgTB/gBQe0QBVzAjeTtbkHpwvfD54pBGwhqFcpFow
14
+WDELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRYwFAYDVQQHEw1TYW4gRnJhbmNp
15
+c2NvMQ8wDQYDVQQKEwZEb2NrZXIxEzARBgNVBAMTCmRlbGVnYXRpb26CCQDIvwMZ
16
+cBariTAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQAfjsMtZ+nJ7y5t
17
+rH9xPwWMLmtC5MwzDRvTUAGbNbFwwm8AncfvsDmmERqsr8L2qhY8CZ9vsN4NjjBn
18
+QRmM/ynYA8JTbf/5ZNDnD4D6qTXLgGFqyHcBaorcB9uQ8eiMOFAbhxLYfPrKaYdV
19
+qj+MejcFa3HmzmYCSqsvxRhSje5b4sORe9/3jNheXsX8VZUpWtCHc3k4GiCU6KyS
20
+gpnXkShU4sG92cK72L8pxmGTz8ynNMj/9WKkLxpNIv5u0/D01a3z4wx5k1zfRZiz
21
+IQS+xqxV/ztY844MDknxENlYzcqGj0Fd6hE5OKZxnGaH83A5adldMLlnhG1rscGP
22
+as9uwPYP
23
+-----END CERTIFICATE-----
0 24
new file mode 100644
... ...
@@ -0,0 +1,27 @@
0
+-----BEGIN RSA PRIVATE KEY-----
1
+MIIEpAIBAAKCAQEAv9rUY77TaO3WnSwwT5gZorj65n2N7OumQJcoywx8i2CoIpFN
2
+fthW5Hu2dG39jUM1WpGcx4ZzvuygNqDp5bjGtiu/0vDKVSw4tqe8rV3/yEPFmHMm
3
+OqUkGbPoG8tYNlQX2646NQsvzK4/ZyZGiCOfRuqZ14rO2tm0NCpCLCwbTadWN+69
4
+WLes/gbgOEvl9SgcHRETov1K7f/Y5Yal3FmqRPsYBuOAuXj/gJezTTj3ebzFkgdd
5
+D3nn0+JWUt+TqnoWMRXuKtmntddJ7UzL/QcZ5sVeRioQv34zLah3jD6omYFPbdpN
6
+24ZOjwhkLuD2XAoTKQCFatiFHm2OQu86xAgTsQIDAQABAoIBAQCDdASic1WXR58N
7
+AgH4B1dJT0VaOBzOgIfhKbEhruSG+ys4xCY9Cy4+TyWskNBxweMEs1CgxVb5Mlh0
8
+Fb0tUXWVzFQazDFWOn6BaFy2zPk81nLFCeDfvdcGZWZb5PAECYpvUuk+/vM5Ywq+
9
+OlOJZB72EDhonwssmI4IUAwXCAGNKjLfC4L+3ZgA3+I1xgxisJ2XWNYSLwHzIDRh
10
+U3zO2NpJi1edTNPltDBTb4iFhajX0SFgbARc+XVTpA3pgQujWo6CNB5YKCPuzIqr
11
+GFsvGSZDVzOUnfOlitaYNW+QIWAQf8VLWULwyFrS5Cb2WR/k7AmojZVuDHvzWrtg
12
+ZMG6b1mBAoGBAOV+3SiX8+khKBpxnOJLq0XlGjFNDWNNB34UIMVkFehRxpUr2261
13
+HDp4YiC9n7l47sjeFBk4IQf2vG/5MPpuqIixsk2W3siCASdMQypVZMG+zj6xDFfH
14
+8rwQSeZhwjmk2a+A7qgnhqvd/qa7EYOnsn1tLf2iBB2EaHV9lWBJFX0lAoGBANYD
15
+GbAPEiwh4Fns8pf59T3Lp0Q9XvAN3uh4DUU0mFrQ1HQHeXIw1IDCJ9JiRjLX7aHu
16
+79EtDssVPQ9dv0MN5rRULtrutCfRLsomm385PLLBIgBdVApnVvJJIWhQkFFMrhFt
17
+UP+483utiDOcCVXMxAy+1jx23EiWvl2H0xGIwsSdAoGBAMIcM+OJ4vxk1w7G2fNu
18
+HUfZJ/ZbPd+n35Z8X9uVdBI0WMsDdW6GMYIjIJygxuCRsSak8EsEdqvNvkTXeN3Z
19
+iyNTaYTG/1iI3YDnuEeuQrK9OKU+CzqUHHOFM3xxY15uWNFhNHt2MypbcnCD+aRp
20
+y0bbefL1fpWY0OHPfvEZ39shAoGAPbVdJc/irIkEGMni1YGEflIHo/ySMGO/f4aG
21
+RQs6Vw1aBS7WjN+ZlprlQpuFpElwwr2TttvoJRS1q4WbjakneZ3AeO5VUhnWBQIG
22
+2jNV1jEsLbC7d9h+UJRXpq18P4T9uBauQV5CDspluIPoiS3m5cntGjgnomKc93kf
23
+mjG1/10CgYA7kgOOva64sjWakL/IgDRiwr0YrJkAfPUZYwxYLHuiW9izUgngpqWd
24
+1wtq+YCsc4l7t8u9Tahb8OE0KSN5RC6QM6b8yW9qFDZ68QAX00+sN6di4qyAZlm+
25
+rK05W/3JmyvQbvO+JVRQtegZ1ExCj7LGuGOQ5KIpWsBEM3ic9ZP9gw==
26
+-----END RSA PRIVATE KEY-----
0 27
new file mode 100644
... ...
@@ -0,0 +1,24 @@
0
+-----BEGIN CERTIFICATE-----
1
+MIID8jCCAtqgAwIBAgIJAI3uONxeFQJtMA0GCSqGSIb3DQEBBQUAMFgxCzAJBgNV
2
+BAYTAlVTMQswCQYDVQQIEwJDQTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzEPMA0G
3
+A1UEChMGRG9ja2VyMRMwEQYDVQQDEwpkZWxlZ2F0aW9uMCAXDTE2MDMwODAyNDEy
4
+NFoYDzIxMTYwMjEzMDI0MTI0WjBYMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0Ex
5
+FjAUBgNVBAcTDVNhbiBGcmFuY2lzY28xDzANBgNVBAoTBkRvY2tlcjETMBEGA1UE
6
+AxMKZGVsZWdhdGlvbjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOii
7
+Ij01MkSExgurs5owUNxNgRvrZFxNSNGfnscYZiaT/wNcocrOz40vvY29SOBEbCSW
8
+oBlCi0rYu/7LZBqvsP3YItmifpJHGfRiZ6xEQ4rKznY8+8E3FHVChlmVv9x6QPhA
9
+9OpATlSLvcdiXHbohdc+kQsl9qM93+QadRQLmtZ6H5Sv90d1MHNViX+8d/k2WyT0
10
+8u6fNv0ZHeltnZFYruF82YKJCOPdAJnCLUOXWRSG6xDhhvSewjxz6gFla5n8m+D9
11
+jvmIUUjoMEhjORUIVeA/lXT0AT3Lx0xE8uyhJQbp+hGtcPCcwYFZdz3yLcrxKO47
12
+nh6qOygf7I2fiR1ogqECAwEAAaOBvDCBuTAdBgNVHQ4EFgQUUqsFJdVoos2aewDh
13
+m1r66zyXeI4wgYkGA1UdIwSBgTB/gBRSqwUl1WiizZp7AOGbWvrrPJd4jqFcpFow
14
+WDELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRYwFAYDVQQHEw1TYW4gRnJhbmNp
15
+c2NvMQ8wDQYDVQQKEwZEb2NrZXIxEzARBgNVBAMTCmRlbGVnYXRpb26CCQCN7jjc
16
+XhUCbTAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQADcyno8/AwNatf
17
+pjgILCZl1DVrqaKEVbp6ciNgVRCF4cM0bE5W4mjd5tO8d3/yTilry2FPicqxiMps
18
+oGroMFR+X1cZbOf0U32FyEW4EyWm2jjbiuEpnM5J/EeB/QfckqP6whS/QAM7PxDV
19
+Sxd8sKDb9SOGZiickFU4QpG1fdmY/knrrtbzRl7Nk/3tBgRaq+Brg7YNZZKlpUNB
20
+Hp3q0E+MFgVAojpcL7w1oSgoNev+cUNaBdPEmWIEi7F5rosCzmAIhuIY+ghmo9Qg
21
+zy+byAcxLpujl8vZvE1nZKMKZ7oJayOOgjB2Ztk6bO1r+GPtK5VfqEPhKTRDbBlo
22
+xS3tSCDJ
23
+-----END CERTIFICATE-----
0 24
new file mode 100644
... ...
@@ -0,0 +1,27 @@
0
+-----BEGIN RSA PRIVATE KEY-----
1
+MIIEpAIBAAKCAQEA6KIiPTUyRITGC6uzmjBQ3E2BG+tkXE1I0Z+exxhmJpP/A1yh
2
+ys7PjS+9jb1I4ERsJJagGUKLSti7/stkGq+w/dgi2aJ+kkcZ9GJnrERDisrOdjz7
3
+wTcUdUKGWZW/3HpA+ED06kBOVIu9x2JcduiF1z6RCyX2oz3f5Bp1FAua1noflK/3
4
+R3Uwc1WJf7x3+TZbJPTy7p82/Rkd6W2dkViu4XzZgokI490AmcItQ5dZFIbrEOGG
5
+9J7CPHPqAWVrmfyb4P2O+YhRSOgwSGM5FQhV4D+VdPQBPcvHTETy7KElBun6Ea1w
6
+8JzBgVl3PfItyvEo7jueHqo7KB/sjZ+JHWiCoQIDAQABAoIBADvh8HpdBTGKFAjR
7
+DAx2v3nWIZP0RgNUiZgcRJzvdOwdUJmm8KbqEZdAYMTpoqbINiY8971I2d5MaCgw
8
+ZvZPn3nYdzAamgZBczbrVdCMSe6iQf9Bt3SHHycIFtlcqOSyO6Mr5V+fagptZk66
9
+zR52wG0l1+RMw25F8SogfV7JlfP7Qh5Bob0lEN2xpbhwLiNaaB+IHNe0FelmRvmJ
10
+VUonoD0xaos25EXUES7J/9coiBqgRlDVHdUM0oaa/94UnxNPJnoNfte0yd+mC4LZ
11
+JVHo0Zti3x/8SiCYMbLQs5L8AL8VtPu9OPfur/J8+9Rv0Rh+L1Ben+JWzCzUw1Cj
12
+abH1zvkCgYEA9Q06Lu69ZLD31fTv46CphN+dGS/VgvMELkob6VQOhbV3RPhe6vqL
13
+p7D67J53iq4rZY5KX3zuXZ+A5s48atc8gz+hTsrE022QVXmO2ZrE22bEpL+mwpsB
14
+8//ul1UG51XTw6YR9CmLLD3Y4BgMjhSllx4Wwr9e9+PKl+DuSreqhxMCgYEA8wbf
15
+P3zh85jPN92gBG8+VIbVlXYOTK0OllYUoLt4URmLRllmrB6LyRlpODCyb9+JymMg
16
+WvAq5Bc0h8gMbSQEkYaAUq2CfSbyExASUHA+/nZglsTZhPkg5PJImntK6S58KAM7
17
+RJzyz20gxYA5H4KXFSiF+ONOE9X/cFUPxzF1AfsCgYBfgUY54GYEBkyxIIMWDhnD
18
+ZXtOw6vNG3V3rP5v04jNZ8oSIVKs9fTT6FADREeGzxauv+QQjxo/dtjAG4TEhxpY
19
+dMYjdTd8x2jHR1b7TCyI7eaZ5u/RTKRYOlj8tfC43GRqDiFVLZPGLFyIChdqkHVx
20
+DhME15zls+vTgaCdkjNt7QKBgQCfwDywNx8wSZqtVnoBcD7AwYFUpi3wKTIVkLAu
21
+mA0XAnuS2uGq8slgf9uynBAvifnBmDeEj6siFD7roozIkYyPPKLNtlC4hAlMjpv7
22
+VE2UZ6xGb0+tITaGSN2A7trnPS9P/g/PonvZ7hpEuWzTUbyOo/ytBn4ke99VsBSX
23
+E+OeUQKBgQCgmcwCj2/IH+GOpe9qAG6MTMKK7k22O8fBCrcDybL1pMWIesJEbzpv
24
+T5Atcx9L5ff6Q4Ysghb8ebXsErv4oZ72xyAwWJmbIaPllWn2ffUikzL3grSriWZy
25
+0bz6P9sRqYpbdmX3oVvTfBP5kbv+mtDXOB3h5rGfczKWNMyuZmxDOg==
26
+-----END RSA PRIVATE KEY-----
0 27
new file mode 100644
... ...
@@ -0,0 +1,24 @@
0
+-----BEGIN CERTIFICATE-----
1
+MIID8jCCAtqgAwIBAgIJAKKDRMrryBRKMA0GCSqGSIb3DQEBBQUAMFgxCzAJBgNV
2
+BAYTAlVTMQswCQYDVQQIEwJDQTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzEPMA0G
3
+A1UEChMGRG9ja2VyMRMwEQYDVQQDEwpkZWxlZ2F0aW9uMCAXDTE2MDMwODAyNDEy
4
+N1oYDzIxMTYwMjEzMDI0MTI3WjBYMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0Ex
5
+FjAUBgNVBAcTDVNhbiBGcmFuY2lzY28xDzANBgNVBAoTBkRvY2tlcjETMBEGA1UE
6
+AxMKZGVsZWdhdGlvbjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOCf
7
+Wfff5mX/ko/Y790O04eR7h8/4YtZU3LFItcjhkphMf2V2BRlhWwwW6v96gTN1xsZ
8
+1il6/YXjviWiLjhrtOVLQBE2yK0A7Wwdh9KJg3QgNqwtFrR1MA1LgWto1F7NyEMC
9
+9H6Hc95+bgWx1jN0IflfPh1C1m/sA5xGqHDl+8YzJJUOoa5bh04Yk3aIeecatso/
10
+z7P5c6KicPcZIjhgjxHYB95It/oj8ZuY0hQZb7B5HEGNyBbT2F0vuElWtp+mXexr
11
+6mzgzvHgaKG36bNCTLxr8BxGA/sbVn01LyI3wpk2uqWzyUFk21M4g2X46OPgKrh7
12
+2h5b+C0X8DUPi45djHcCAwEAAaOBvDCBuTAdBgNVHQ4EFgQUKcrfRFg+6o2l4xbt
13
+Ll6hV9pjJh8wgYkGA1UdIwSBgTB/gBQpyt9EWD7qjaXjFu0uXqFX2mMmH6FcpFow
14
+WDELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRYwFAYDVQQHEw1TYW4gRnJhbmNp
15
+c2NvMQ8wDQYDVQQKEwZEb2NrZXIxEzARBgNVBAMTCmRlbGVnYXRpb26CCQCig0TK
16
+68gUSjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQAhdKgYUQ36JSPS
17
+f3Dws09pM5hzSsSae4+nG9XckX6dVQ7sLKmjeeeLrXuzjfygir/+h9cHyShgXFH4
18
+ZbGpdzf6APG1KRag3/njqEWi+kKZZduxZKvI2EHJhj1xBtf8Qru0TgS7bHPlp9bl
19
+1/61+aIrtj05LQhqzWzehuJFrmSdWP9cnNbvlPdOdgfgkKakAiLGwwGNvMQbqxaO
20
+FIB4UPuPdQgm5bpimd5/CThKbpK9/0nr9K4po/m519nvEKxZzsDw5tefGp9Xqly3
21
+4pk9uyAxO/E2cL0cVA/WHTVTsHPbO7lXxBi6/EjiTUi0Nj1X+btO8+jCLkJyNY0m
22
+qaiL5k9h
23
+-----END CERTIFICATE-----
0 24
new file mode 100644
... ...
@@ -0,0 +1,27 @@
0
+-----BEGIN RSA PRIVATE KEY-----
1
+MIIEpAIBAAKCAQEA4J9Z99/mZf+Sj9jv3Q7Th5HuHz/hi1lTcsUi1yOGSmEx/ZXY
2
+FGWFbDBbq/3qBM3XGxnWKXr9heO+JaIuOGu05UtAETbIrQDtbB2H0omDdCA2rC0W
3
+tHUwDUuBa2jUXs3IQwL0fodz3n5uBbHWM3Qh+V8+HULWb+wDnEaocOX7xjMklQ6h
4
+rluHThiTdoh55xq2yj/Ps/lzoqJw9xkiOGCPEdgH3ki3+iPxm5jSFBlvsHkcQY3I
5
+FtPYXS+4SVa2n6Zd7GvqbODO8eBoobfps0JMvGvwHEYD+xtWfTUvIjfCmTa6pbPJ
6
+QWTbUziDZfjo4+AquHvaHlv4LRfwNQ+Ljl2MdwIDAQABAoIBAQCrN2wZsFZr2zK5
7
+aS/0/Y8poIe01Dm0wWMFcdULzm1XltzHIgfyDCx2ein2YPaXsNtNMhV3yuMiwqU3
8
+BHdc1GSv/vsX4/11Oea/6YaVafKEeuWRulC7PzRgffRpjh+LICqNQdxh8hfVOePd
9
+fV/8GoKnFf0/yqmv6GQcJBPS8stGmFmjo4rkBGvBBMoiUtMYllQqdfH0DtpI24Jh
10
+nR3lZKAPECkAciV7/Lx6+CUEaNOML2XPbLv6EyRh+J/r80jwE8myzpO7R6I+KCzo
11
+R/xuBb/hrUh5Sd5YmuBMa6WfF9yqawTgmVvkpD9fkRusSPSQCq3oe+AugYWu6Fht
12
+XBiZlvjJAoGBAPPBuUaagaUgHyjIzjbRPBHDhSYJpgYR4l/jcypfrl+m0OFC5acA
13
+QG7Hr8AbStIPGtaJRn2pm8dNVPtFecPoi5jVWux2n5RqYlOnwY0tziuxbhU9GQ/W
14
+oCp+99TJSMHFep0E7IoDk8YSxyA/86qk/Tx7KkUUlXv4sjJts17ZHxstAoGBAOvn
15
+mF9rm8Y+Og17WlUQyf5j7g4soWG/4zMnoGpjocDfHVms/pASKbIBp5aFtDgWCmM5
16
+H7InptvBUInROHlooK6paJRDLbDgzVa/m+NLHoct7N25J4NiG8xV6Wv7hlrRp+XK
17
+zyWL8iL95GnB21HJKvEiVBWvOuZnqfVcnzhbmzyzAoGAYT46jMkcyWRMKfgaFFJa
18
+lXebybX1rtw5pClYC2KKbQxerk8C0SHPkqJFIe2BZtWxzj6LiZw9UkAuk+N+lUJT
19
+VpBfKpCUTyA1w8vb8leAtXueQAjU07W6xdlLQ29dgDgpFzUcrF6K+G0LVXlN2xjh
20
+EdzM2yxACmoHpQiQk1kpCK0CgYAz640Fs1FdmGR+gx+miUNr0eKbDAeY0/rVT2tm
21
+/vai1HhJPGHqo5S5sNOJtXOsxG0U2YW4WDHJPArVyk57qiNzTaXOu9pai5+l8BYH
22
+OIlHhzwSsKWZrQYhOudc9MblRi+Fy9U7lkl8mhSjkh8LKRNibwPCogZ8n2QwtGn2
23
+pXLNMQKBgQDxvs46CA0M9lGvpl0ggnC7bIYYUEvIlszlBh+o2CgF3IOFlGVcvCia
24
+r18i7hTM5wbcct9OWDzZG4ejBIhtE+gMQ333ofQ64PPJOcfuHxT3Z/fMWfv/yDEj
25
+4e4ZPK44ktcTvuusxAoSe5C5dbcNX2ymAhlRg/F0LyMkhw+qGh4xOQ==
26
+-----END RSA PRIVATE KEY-----
... ...
@@ -92,10 +92,10 @@ var (
92 92
 			// for now notary binary is built only if we're running inside
93 93
 			// container through `make test`. Figure that out by testing if
94 94
 			// notary-server binary is in PATH.
95
-			_, err := exec.LookPath(notaryBinary)
95
+			_, err := exec.LookPath(notaryServerBinary)
96 96
 			return err == nil
97 97
 		},
98
-		fmt.Sprintf("Test requires an environment that can host %s in the same host", notaryBinary),
98
+		fmt.Sprintf("Test requires an environment that can host %s in the same host", notaryServerBinary),
99 99
 	}
100 100
 	NotaryServerHosting = testRequirement{
101 101
 		func() bool {
... ...
@@ -12,19 +12,23 @@ import (
12 12
 	"time"
13 13
 
14 14
 	"github.com/docker/docker/cliconfig"
15
+	"github.com/docker/docker/pkg/integration/checker"
15 16
 	"github.com/docker/docker/pkg/tlsconfig"
16
-	"github.com/docker/notary/client"
17
-	"github.com/docker/notary/passphrase"
18
-	"github.com/docker/notary/tuf/data"
19 17
 	"github.com/go-check/check"
20 18
 )
21 19
 
22 20
 var notaryBinary = "notary"
23 21
 var notaryServerBinary = "notary-server"
24 22
 
23
+type keyPair struct {
24
+	Public  string
25
+	Private string
26
+}
27
+
25 28
 type testNotary struct {
26
-	cmd *exec.Cmd
27
-	dir string
29
+	cmd  *exec.Cmd
30
+	dir  string
31
+	keys []keyPair
28 32
 }
29 33
 
30 34
 const notaryHost = "localhost:4443"
... ...
@@ -90,6 +94,15 @@ func newTestNotary(c *check.C) (*testNotary, error) {
90 90
 		return nil, err
91 91
 	}
92 92
 
93
+	// load key fixture filenames
94
+	var keys []keyPair
95
+	for i := 1; i < 5; i++ {
96
+		keys = append(keys, keyPair{
97
+			Public:  filepath.Join(workingDir, fmt.Sprintf("fixtures/notary/delgkey%v.crt", i)),
98
+			Private: filepath.Join(workingDir, fmt.Sprintf("fixtures/notary/delgkey%v.key", i)),
99
+		})
100
+	}
101
+
93 102
 	// run notary-server
94 103
 	cmd := exec.Command(notaryServerBinary, "-config", confPath)
95 104
 	if err := cmd.Start(); err != nil {
... ...
@@ -101,8 +114,9 @@ func newTestNotary(c *check.C) (*testNotary, error) {
101 101
 	}
102 102
 
103 103
 	testNotary := &testNotary{
104
-		cmd: cmd,
105
-		dir: tmp,
104
+		cmd:  cmd,
105
+		dir:  tmp,
106
+		keys: keys,
106 107
 	}
107 108
 
108 109
 	// Wait for notary to be ready to serve requests.
... ...
@@ -197,6 +211,7 @@ func (s *DockerTrustSuite) setupTrustedImage(c *check.C, name string) string {
197 197
 	pushCmd := exec.Command(dockerBinary, "push", repoName)
198 198
 	s.trustedCmd(pushCmd)
199 199
 	out, _, err := runCommandWithOutput(pushCmd)
200
+
200 201
 	if err != nil {
201 202
 		c.Fatalf("Error running trusted push: %s\n%s", err, out)
202 203
 	}
... ...
@@ -211,42 +226,110 @@ func (s *DockerTrustSuite) setupTrustedImage(c *check.C, name string) string {
211 211
 	return repoName
212 212
 }
213 213
 
214
-func notaryClientEnv(cmd *exec.Cmd, rootPwd, repositoryPwd string) {
214
+func notaryClientEnv(cmd *exec.Cmd) {
215
+	pwd := "12345678"
215 216
 	env := []string{
216
-		fmt.Sprintf("NOTARY_ROOT_PASSPHRASE=%s", rootPwd),
217
-		fmt.Sprintf("NOTARY_TARGETS_PASSPHRASE=%s", repositoryPwd),
218
-		fmt.Sprintf("NOTARY_SNAPSHOT_PASSPHRASE=%s", repositoryPwd),
217
+		fmt.Sprintf("NOTARY_ROOT_PASSPHRASE=%s", pwd),
218
+		fmt.Sprintf("NOTARY_TARGETS_PASSPHRASE=%s", pwd),
219
+		fmt.Sprintf("NOTARY_SNAPSHOT_PASSPHRASE=%s", pwd),
219 220
 	}
220 221
 	cmd.Env = append(os.Environ(), env...)
221 222
 }
222 223
 
223
-func (s *DockerTrustSuite) setupDelegations(c *check.C, repoName, pwd string) {
224
+func (s *DockerTrustSuite) notaryInitRepo(c *check.C, repoName string) {
224 225
 	initCmd := exec.Command(notaryBinary, "-c", filepath.Join(s.not.dir, "client-config.json"), "init", repoName)
225
-	notaryClientEnv(initCmd, pwd, pwd)
226
+	notaryClientEnv(initCmd)
226 227
 	out, _, err := runCommandWithOutput(initCmd)
227 228
 	if err != nil {
228 229
 		c.Fatalf("Error initializing notary repository: %s\n", out)
229 230
 	}
231
+}
232
+
233
+func (s *DockerTrustSuite) notaryCreateDelegation(c *check.C, repoName, role string, pubKey string, paths ...string) {
234
+	pathsArg := "--all-paths"
235
+	if len(paths) > 0 {
236
+		pathsArg = "--paths=" + strings.Join(paths, ",")
237
+	}
230 238
 
231
-	// no command line for this, so build by hand
232
-	nRepo, err := client.NewNotaryRepository(filepath.Join(cliconfig.ConfigDir(), "trust"), repoName, notaryURL, nil, passphrase.ConstantRetriever(pwd))
239
+	delgCmd := exec.Command(notaryBinary, "-c", filepath.Join(s.not.dir, "client-config.json"),
240
+		"delegation", "add", repoName, role, pubKey, pathsArg)
241
+	notaryClientEnv(delgCmd)
242
+	out, _, err := runCommandWithOutput(delgCmd)
233 243
 	if err != nil {
234
-		c.Fatalf("Error creating notary repository: %s\n", err)
244
+		c.Fatalf("Error adding %s role to notary repository: %s\n", role, out)
235 245
 	}
236
-	delgKey, err := nRepo.CryptoService.Create("targets/releases", data.ECDSAKey)
246
+}
247
+
248
+func (s *DockerTrustSuite) notaryPublish(c *check.C, repoName string) {
249
+	pubCmd := exec.Command(notaryBinary, "-c", filepath.Join(s.not.dir, "client-config.json"), "publish", repoName)
250
+	notaryClientEnv(pubCmd)
251
+	out, _, err := runCommandWithOutput(pubCmd)
237 252
 	if err != nil {
238
-		c.Fatalf("Error creating delegation key: %s\n", err)
253
+		c.Fatalf("Error publishing notary repository: %s\n", out)
239 254
 	}
240
-	err = nRepo.AddDelegation("targets/releases", []data.PublicKey{delgKey}, []string{""})
255
+}
256
+
257
+func (s *DockerTrustSuite) notaryImportKey(c *check.C, repoName, role string, privKey string) {
258
+	impCmd := exec.Command(notaryBinary, "-c", filepath.Join(s.not.dir, "client-config.json"), "key",
259
+		"import", privKey, "-g", repoName, "-r", role)
260
+	notaryClientEnv(impCmd)
261
+	out, _, err := runCommandWithOutput(impCmd)
241 262
 	if err != nil {
242
-		c.Fatalf("Error creating delegation: %s\n", err)
263
+		c.Fatalf("Error importing key to notary repository: %s\n", out)
243 264
 	}
265
+}
244 266
 
245
-	// publishing first simulates the client pushing to a repo that they have been given delegated access to
246
-	pubCmd := exec.Command(notaryBinary, "-c", filepath.Join(s.not.dir, "client-config.json"), "publish", repoName)
247
-	notaryClientEnv(pubCmd, pwd, pwd)
248
-	out, _, err = runCommandWithOutput(pubCmd)
267
+func (s *DockerTrustSuite) notaryListTargetsInRole(c *check.C, repoName, role string) map[string]string {
268
+	listCmd := exec.Command(notaryBinary, "-c", filepath.Join(s.not.dir, "client-config.json"), "list",
269
+		repoName, "-r", role)
270
+	notaryClientEnv(listCmd)
271
+	out, _, err := runCommandWithOutput(listCmd)
249 272
 	if err != nil {
250
-		c.Fatalf("Error publishing notary repository: %s\n", out)
273
+		c.Fatalf("Error listing targets in notary repository: %s\n", out)
274
+	}
275
+
276
+	// should look something like:
277
+	//    NAME                                 DIGEST                                SIZE (BYTES)    ROLE
278
+	// ------------------------------------------------------------------------------------------------------
279
+	//   latest   24a36bbc059b1345b7e8be0df20f1b23caa3602e85d42fff7ecd9d0bd255de56   1377           targets
280
+
281
+	targets := make(map[string]string)
282
+
283
+	// no target
284
+	lines := strings.Split(strings.TrimSpace(out), "\n")
285
+	if len(lines) == 1 && strings.Contains(out, "No targets present in this repository.") {
286
+		return targets
287
+	}
288
+
289
+	// otherwise, there is at least one target
290
+	c.Assert(len(lines), checker.GreaterOrEqualThan, 3)
291
+
292
+	for _, line := range lines[2:] {
293
+		tokens := strings.Fields(line)
294
+		c.Assert(tokens, checker.HasLen, 4)
295
+		targets[tokens[0]] = tokens[3]
296
+	}
297
+
298
+	return targets
299
+}
300
+
301
+func (s *DockerTrustSuite) assertTargetInRoles(c *check.C, repoName, target string, roles ...string) {
302
+	// check all the roles
303
+	for _, role := range roles {
304
+		targets := s.notaryListTargetsInRole(c, repoName, role)
305
+		roleName, ok := targets[target]
306
+		c.Assert(ok, checker.True)
307
+		c.Assert(roleName, checker.Equals, role)
308
+	}
309
+}
310
+
311
+func (s *DockerTrustSuite) assertTargetNotInRoles(c *check.C, repoName, target string, roles ...string) {
312
+	targets := s.notaryListTargetsInRole(c, repoName, "targets")
313
+
314
+	roleName, ok := targets[target]
315
+	if ok {
316
+		for _, role := range roles {
317
+			c.Assert(roleName, checker.Not(checker.Equals), role)
318
+		}
251 319
 	}
252 320
 }