Notary V2 and Cosign

Dan Lorenc
5 min readNov 8, 2021

This post is to help reduce confusion between the Notary V2/Notation and Cosign projects. This is a common question from end users that I tried to avoid answering directly for a while. Now that Notation has released an alpha, I think it’s time to publish an evaluation of the differences.

The differences right now are in three main parts — Signature Formats, Signature Discovery, and Key Management.

Note: There is a Notary-TUF subproject focused on a standard TUF implementation for OCI registries — this is a separate project, and this document does not apply to it.

Photo by Elena Mozhvilo on Unsplash

Comparisons

Signature Format

Notary V2/Notation uses a custom JWT variant, defined here. In my opinion the JWT layer is overly complex, unnecessary and insecure. JWTs in general have a very bad reputation in the security/cryptography community. While it’s possible to define subsets of JWT that can be used securely, this is still an unnecessary risk that every client library will have to get right.

Cosign uses a simpler (also custom) format defined here. This format was designed to be verifiable using only the Go standard library. There are no full implementations (e.g., time-stamping, transparency log support) in other languages yet.

Both tools support time-stamping and cert chains. Cosign also supports transparency logs, in-toto Attestations, TUF, and SBOMs.

Notation uses an OCI Descriptor as the signing payload, while cosign uses the Red Hat SimpleSigning format. The Descriptor is a better choice, and cosign should switch to it.

Signature Discovery

Right Now

Notation currently uses a new Referrers API defined in the ORAS Artifacts spec. The notation demo requires running a forked version of distribution/distribution, as shown in the tutorial. This spec is not supported by any production registries today.

Cosign uses a tag-based discovery scheme right now, because it’s the only method we’ve come up with that works across all OCI registries today. It’s not great but it works. The current issues with this approach are documented in the cosign README.md, but at a high level they include:

  • Polluting the tag namespace (signatures show up in the UI as images)
  • Race conditions during appending multiple signatures

Future

Notation is currently discussing a “fallback mode” to add support for existing OCI registries. This is probably going to look like the cosign spec. I hope they can coexist rather than conflict, or just use the same exact specification.

When the Referrers API is defined and approved by the OCI and widely supported, cosign is going to move to this method. Note: I don’t actually really care if the eventual API is part of OCI or not. I’m fine using any methods that actually work on ~every registry. I just currently believe that getting this adopted by the OCI is the fastest path to that.

Both tools are going to work exactly the same here in the long run.

Key Management

I don’t think Notation has a real story here. It’s a hard problem but I haven’t read anything convincing about how it might work eventually.

Notation uses PKIX signing keys and X.509 certificates. The certificate semantics are still being specified (acceptable KeyUsages, algorithm types, CAs, etc.) so it’s hard to comment on the exact security semantics. Today notation only really supports self-signed certs. That’s fine for early testing, but adds zero security value. Certificates only make sense if they come from a trusted CA, but I don’t think Notation is planning to operate one.

Leaving aside the Notary-TUF subproject, I see a few options:

  • Notation could require the use of existing Code Signing CAs. These aren’t very common and are typically expensive. This is a non-starter for open source projects IMO.
  • Cloud providers all offer “Private CA” services, these would work fine for internal use cases (signing and verifying your own containers), but wouldn’t work for third-party containers where you need a shared trust root.
  • Notation (or a company involved) could launch their own public CA. I haven’t seen any plans here, but wouldn’t be surprised if Docker or someone wanted to do this.
  • Notation could use Sigstore’s CA: Fulcio. This requires the use of time-stamping and transparency logs to work correctly. At this point notation and cosign would basically be the same tool.

There’s no one-size fits all answer here, and trying to find one will make everyone unhappy. This is why cosign supports basically every key management method possible. Cosign supports just static fixed keys, cloud-based KMS APIs, hardware tokens, X.509 certificates (with or without a free CA), and even full TUF-style key management with delegation and rotation. This adds a lot of options, but supports as many use cases as possible, from internal first-party code to external OSS code.

Revocation

Cosign does not support X.509 certificate revocation. This is by design — revocation is widely acknowledged to be broken. There are better options that address the same use cases, like fast-expiring certificates at the very least, and TUF. Browsers all moved on from revocation 8 years ago. Notation is planning to add support for revocation. I’ve read all the discussion I can find, but I don’t fully understand how this will work yet.

Revocation is tricky to do for many reasons. Lists can grow unbounded over time, making distribution hard. Systems like OSCP work around the size challenges but it’s typically fail-open can leak privacy-related information. OCSP stapling can help mitigate through the use of a TUF-like “heartbeat” protocol, but I’m not sure how that would work for artifacts and just using TUF would make more sense.

In any arrangement, CRL servers and/or OCSP servers become a mandatory production dependency, making air gapped operation difficult. I would strongly recommend not supporting these problematic revocation mechanisms, and instead follow one of the design proposals Marina Moore proposed.

Summary/Conclusion

I can’t think of any way for Notation to move past self-signed certs for open source code without building a new CA or reusing the Sigstore one. Maybe I’m missing something though. Someone can probably figure out how to do it with blockchain.

The signature formats are different, but I think we could converge those somehow or support both if JWTs are really required by end users for some reason. The discussion on why JWTs were chosen is light on details, and seems to hinge on the fact that they are an accepted standard. There are sometimes good reasons to use a worse format (see, ASN.1’s and X.509 in general), but I haven’t seen anything convincing for Notation. I know first-hand that cosign is used in sensitive, regulated environments today and the lack of an IETF standard signature wrapper has never come up.

Disclaimer: This document was reviewed by several Notary project maintainers and contributors, including Marina Moore, Jason Hall, Trishank Karthik Kuppusamy, Brandon Mitchell, and Santiago Torres-Arias. I’m a maintainer of the cosign project.

I’ve been loosely involved in the Notary project for about a year, but don’t have any official affiliation there. This was initially written and revised in a Google document. I want to thank everyone for their help!

--

--