question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Proposal

Proposal #: 2 Title: Trust Pinning Author: Evan Cordell, Jake Moshenko, Justin Cappos, Vladimir Diaz, Sebastien Awwad Created: August 18, 2016 Type: Design Status: Draft

Rationale

This is a proposal of a design for pinning trusted keys, which would allow clients to root their trust at a namespace (or lower) delegated set of keys instead of the repository root.

An example use case: I trust django’s published public keys to have signed off on django, but I don’t necessarily trust PyPI to remain uncompromised (and possibly convince me of different public keys for django).

This proposal also addresses the problem of private metadata. In the current TUF spec, there is no way to hide all information about the existence of other metadata in the system. This is a problem in a multi-tenant scenario where knowledge of metametadata could be sensitive (e.g. timing of creating a target, names of targets, etc).

Overview

We introduce a new file, pinned.json, which permits users to pin root files and associate them with a particular namespace prefix. If an entry matches the current package, the pinned root must be used. If it does not match, there is a fallback to the global root.

This constructs two (or more) trust paths for target files, and allows the user to pick between them. Clients that trust the global root (e.g. PyPI) will trust all packages served by it, and those that wish to root trust with a namespace owner (e.g. django project) can pin to those keys. See this diagram for an example.

Because the pinning mechanism uses roots, the “pinned” keys may be rotated according to the standard root rotation scheme. In that sense, you are pinning the root of a tree of keys which can grow over time, rather than pinning a set of keys that must never change.

Pin File

pinned.json maps a prefix to a location where the pinned root can be found and an optional url for updating it. This file is not available from a TUF repository. It is either constructed by explicit actions from the client (e.g. “pin this role’s keys”) or by an out-of-band bootstrap (e.g. “here’s our organization’s pinned.json”).

 {
   "django": {
      "location": "pinned/django",  // default pinned directory structure
      "url": "https://www.djangoproject.com/release/metadata"
   },
   "private-requests-beta": {
      "location": "pinned/requests"
       // no url - can't be updated automatically
   },
   "private-flask-beta": {
      "location": "/usr/local/evan/flask-beta" // metadata can live elsewhere if desired
   }
 }

Pinned Metadata

Pinned metadata lives in a specific default directory, sharing the same layout as a “normal” repo but nested within a prefix namespace, e.g.

pinned
└── django  // prefix
    ├── root.json
    ├── snapshot.json
    ├── targets.json
    └── timestamp.json

This can be changed with the location field of the pinned.json file, which may be useful if e.g. sharing a network drive.

Complex ACLs can be enforced and/or bootstrapped by sending a user an appropriately generated pinned.json, noting that any metadata endpoint (root repo, or any pinned repo) can have its own access control mechanism.

Hiding

A private package can be omitted from the primary hierarchy entirely, having its own snapshot and target files separate from those provided with root. The snapshot.json and target.json could be signed with the same snapshot and target keys used for the public parts of the repository, or they can be managed and signed by the owner of the private delegated role. Access to these private roles is granted by sending the metadata to the appropriate users (further restricted by ACLs if needed). A url pointing to where the snapshot and timestamp can be found is added to the pinned.json file in the case of private roles.

Hard Pinning

Hard pinning, in which a specific set of non-changing keys are used, can be accomplished by creating the a pinned metadata repository and not specifying a url. Without a url, nothing can convince a client to use different keys. This may be useful for priming a box for a one-time initial pull (with the assumption that it will be killed rather than updated directly).

Repository structure

With this pinning structure it makes sense to structure namespaces and/or packages with their own roots. Alternately, a user can generate a root for a given package/target delegation locally if it doesn’t exist, by generating keys locally and signing.

Because a delegation is also a target file, a global root can delegate to target files of other repos. This allows a simple way to provide both global and namespaced target files.

Prior Art

It’s worth mentioning that Notary has a pinning implementation currently. Although this proposal differs and has slightly different goals, the Notary format should be compatible with this through a simple transformation.

Issue Analytics

  • State:closed
  • Created 7 years ago
  • Reactions:1
  • Comments:24 (21 by maintainers)

github_iconTop GitHub Comments

1reaction
trishankkarthikcommented, Oct 6, 2016

@endophage

To try to answer your questions succinctly, there are two different reasons for TAPs 4 and 5. Let me try to briefly recap what they are.

TAP 4 is useful for: (1) getting different targets from different repositories (e.g., company-controlled targets first from a private repository, all other targets second from a public repository), or (2) requiring multiple repositories to sign off on the same targets.

In my opinion, this TAP is trying to do too much. We have a delegation mechanism in TUF already. If somebody wants to trust a different TUF repo for a different target, they should simply specify that other repo, and it should be valid in and of itself. Any sharing of files and keys across repos should be irrelevant to clients, who anchor trust only at the root.

To try to answer your concerns, this is exactly what TAP 4 is trying to do. Using a trust pinning file, users can specify as many repositories as they like, and exactly how they trust each repository. We think it is useful to have a standard way for users to do so.

In regards to @JustinCappos’s use case of requiring a target appears in multiple repos (“under two different roots”), this seems like functionality that should be built on top of TUF but has no need to be in the spec. It’s simply a case of looking up a target in two TUF repos and seeing if it matches. I don’t see a particularly compelling reason to try and address every possible combination of business logic like this in the spec. People are going to come up with other use cases like this and it doesn’t make sense for them all to be in the spec; Notary is already used in Docker UCP in a case where we require a target appears in multiple delegations within a single repo.

I agree that this is not a common use case. However, requiring multiple repositories (with different roots of trust) to sign off on the same targets is useful in some cases. For example, we plan to use this feature in UPTANE. It improves compromise-resilience, because you do not trust only one repository to have the final say. If two different repositories with different roots of trust (and, thus, different keys) sign the same targets metadata, then chances are better that the targets metadata is trustworthy.

In this sense, multi-repository delegations in TAP 4 is similar, but not identical to multi-role delegations in TAP 3. Multi-role delegations are also useful in improving compromise-resilience, but they still share the same root of trust. If the root keys are compromised, then the multi-role delegations can be overwritten. Not so for multi-repository delegations, because that requires compromising multiple roots of trust (which should be significantly more difficult).

Does this answer your question?

I really think it would make sense to focus on pinning just a root key for now. It may also make sense to be able to specify pinned delegation keys, and on the engineering side, a little duplication here seems like a highly acceptable trade off when compared to a high degree of complexity specifying cross repository relationships. In that respect, if the TAP specificed a pinning on root keys to repositories, and a mapping of wildcarded target names to those repositories, I think it would be awesome. The introduction of “delegated” repositories just seems unnecessary.

Precisely as you wish, TAP 5 is useful for pinning (in the root metadata file) the keys and URLs used to verify the top-level roles of a repository. There are two features in TAP 5.

First, the root metadata file can be used to control where the metadata files for top-level roles come from. If the URLs for a top-level role is not specified in the root metadata file, then the mirrors in the trust pinning file (TAP 4) would be used to download the metadata file for the top-level role. Otherwise, if the URLs have been specified in the root metadata file, then the mirrors in the trust pinning file will be ignored, and these URLs will be used instead to download the metadata file for the top-level role.

Second, the root metadata file can be used to control the keys used to verify the top-level roles. Thus, as you surmised, instead of using the root metadata file provided by a remote repository, the user can create her own metadata file to pin the keys used by this remote repository. In this way, the user need not automatically agree to revoke and replace the keys used by the remote repository. She can verify them herself before replacing the keys using her own root metadata file.

These two features allow us to implement at least one interesting use case. Suppose that a user trusts only the Django project on the PyPI repository. She is not worried about the timestamp and snapshot keys being compromised on PyPI, because the resulting attacks are not severe. However, where would she get the keys used to verify the Django project on PyPI? In the normal case, she would read the delegation to the Django project off the top-level targets role on PyPI. However, (as a purely hypothetical example), if attackers somehow compromise this top-level targets role, then attackers can distribute incorrect keys for the Django project.

If the user were so inclined, she can avoid this problem by using TAP 5. Instead of using the PyPI root metadata file, she would craft her own root metadata file. Her root metadata file would look as follows:

  • root URLs: either an empty string (to denote “never update this root metadata file”), or to a file on a repository of her own control
  • root keys: her own root keys
  • targets URLs: the URL to the Django project (i.e., delegated targets role) on PyPI
  • targets keys: the Django targets keys, obtained through an out-of-band mechanism
  • snapshot URLs: the URL to the snapshot metadata file on PyPI
  • snapshot keys: the keys to the snapshot role on PyPI
  • timestamp URLs: the URL to the timestamp metadata file on PyPI
  • timestamp keys: the keys to the timestamp role on PyPI

If that’s all correct, where would I get a snapshot.json that references Django’s root.json and targets.json. Per 4. It seems I would never actually be able to pull the TUF repository directly from Django.

This is a good question. Per TAP 5, the root metadata file is no longer listed in the snapshot metadata. In order to update the metadata file for a top-level role on a repository, one of the following two rules shall be used. If the URLs for the top-level role have been defined in the root metadata file, then that is where the metadata file shall be fetched. Otherwise, it shall be fetched from the mirrors defined in the trust pinning file.

So, to return to the Django example, this is how metadata files would be downloaded. First, the TUF client would either not update the root metadata file (if so instructed), or it would download the latest root metadata file on a repository of the user’s control. Second, the TUF client would download the timestamp metadata file from PyPI. Third, the TUF client would download the snapshot metadata file from PyPI. Fourth, the TUF client would download the Django delegated targets role metadata file from PyPI. It would verify that the Django metadata file is signed by the keys pinned in her root metadata file, and that its version number nevertheless matches the snapshot metadata signed by PyPI. In effect, this root metadata file allows the user to restrict her trust in PyPI to provide metadata about only the Django project.

Does this make sense? If not, please let us know. I might have botched a thing or two in my explanations. If so, I apologize in advance, and I’m sure @JustinCappos can better explain things.

1reaction
JustinCapposcommented, Oct 5, 2016

You can safely ignore TAP 5 for now. It was more a draft from one team member, than something that had been discussed with the intent that I would approve. We will only be adding things that we think are ready to be approved to the repo in the future.

So, TAP 5 will undergo major revisions that will fix this and other issues. We’ll ping you when it has been scrubbed and fixed.

On Wed, Oct 5, 2016 at 6:11 PM, David Lawrence notifications@github.com wrote:

I was only referencing TAP 4, but a couple of comments on 5. Doesn’t the spec already define a mirrors.json? Why not have a per mirror flag in there that specifies if the root.json can be updated from that mirror? What’s the use case for a repo specifying a delegation as the search root? The abstract statement that a client may want to restrict its search space makes total sense, in which case, it shold be specified in client configuration, not in the root.json which is global to all clients.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/theupdateframework/tuf/issues/361#issuecomment-251814734, or mute the thread https://github.com/notifications/unsubscribe-auth/AA0XD-fH47AA1w1OuJoSFKvMLKg93x12ks5qxCCsgaJpZM4Jnvng .

Read more comments on GitHub >

github_iconTop Results From Across the Web

Certificate and Public Key Pinning | OWASP Foundation
Pinning effectively removes the “conference of trust”. An application which pins a certificate or public key no longer needs to depend on others...
Read more >
Stop Certificate Pinning | DigiCert.com
Certificate pinning restricts which certificates are considered valid for a particular website, limiting risk. Instead of allowing any trusted ...
Read more >
What Is Certificate Pinning? SSL Pinning | Sectigo® Official
Certificate pinning is an online application security technique, originally devised as a means of thwarting man-in-the-middle attacks (MITM) ...
Read more >
What is certificate pinning? - tls
Certificate Pinning was where you ignore that whole thing, and say trust this certificate only or perhaps trust only certificates signed by ...
Read more >
What is SSL Pinning? – A Quick Walk Through - Indusface
This security measure pins the identity of trustworthy certificates on mobile apps and blocks unknown documents from the suspicious servers. Applications with ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found