Skip to content
This repository was archived by the owner on Jul 31, 2025. It is now read-only.

Conversation

@ecordell
Copy link
Contributor

@ecordell ecordell commented Jan 26, 2017

This adds support for explicit wildcard suffixes in root (leaf) certificates of the form prefix*.

I considered doing something more flexible using filepath.Match but I think this more conservative form is safer and (probably) just as useful. It would be easy to change in the future if more flexibility (e.g. docker.io/*/test) is needed.

Note the wildcard * indicator is required to avoid accidentally using wildcard certs (e.g. docker.io/test and docker.io/test2).

Fixes #883
Possibly addresses #914 as well?

@ecordell ecordell force-pushed the wildcard-certs branch 3 times, most recently from b481fb3 to fb428da Compare January 26, 2017 18:42
// MatchCNToGun checks that the common name in a cert is valid for the given gun.
// This allows wildcards as suffixes, e.g. `namespace/*`
func MatchCNToGun(commonName, gun string) bool {
wildcard := "*"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should this be a const?

@endophage
Copy link
Contributor

Glad you avoided filepath.Match, it has weird behaviour. It doesn't support ** and a single * matches exactly one and only one path segment. (it also probably wouldn't be consistent on windows).

One thought, should we require the * comes after a /? I don't have any instinct either way, just throwing it out there.

// MatchCNToGun checks that the common name in a cert is valid for the given gun.
// This allows wildcards as suffixes, e.g. `namespace/*`
func MatchCNToGun(commonName, gun string) bool {
const wildcard = "*"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I figured a const at probably package scope :-P This works too as far as giving us immutability though.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

figured the go compiler would do what I wanted here, didn't really verify though

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It probably will as far as optimization, I was thinking more along code organization.

@ecordell
Copy link
Contributor Author

ecordell commented Jan 26, 2017

One thought, should we require the * comes after a /? I don't have any instinct either way, just throwing it out there.

Personally I think that's a little too restrictive; I was considering an organization using a wildcard cert for a subset of their packages, e.g. docker/notary* to cover docker/notary, docker/notary-server, and docker/notary-signer

{"test/*/wild", "test/test/wild", false},
{"*/all", "test/all", false},
{"docker.com/*/*", "docker.com/notary/test", false},
{"*", "docker.com/any", true},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we add the following test cases:

CN: "", gun: *, out: false
CN: *, gun: "", out: true
CN: *abc*, gun: "abc", out: false (since we check against *abc, no longer wildcarded)
CN: test/*/wild*, gun: "test/test/wild", out: false (since we check against test/*/wild, no longer wildcarded)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Out of curiosity, if the common name is **, should we treat that as *? If not, can we also add one more test?

CN: **, gun: "docker.com/any", out: false

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Non-blocking: Since we're not actually checking any trust pinning here, do we need a CA+intermediate+leaf for this test? Might make the test a little shorter to just include the leaf.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@cyli: good idea - I like treating ** as * for now to keep things simple so that test would be great 👍

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I went ahead and switched TrimSuffix to TrimRight so that any number of trailing *s will collapse down to 1.

func MatchCNToGun(commonName, gun string) bool {
const wildcard = "*"
if strings.HasSuffix(commonName, wildcard) {
prefix := commonName[:len(commonName)-len(wildcard)]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit style: I'd prefer using strings.TrimSuffix instead of indexing directly

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, could we add a log debug to display which prefix we're comparing against?

My concern is if folks use something like prefix** and expect matching against prefix instead of prefix*

require.Error(t, err, "failed to invalidate expired intermediate certificate")
}

func TestCheckingWilcardCert(t *testing.T) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: "TestCheckingWildcartCert"

@ecordell ecordell force-pushed the wildcard-certs branch 2 times, most recently from d474056 to 764e056 Compare January 27, 2017 12:10
Signed-off-by: Evan Cordell <cordell.evan@gmail.com>
Copy link
Contributor

@riyazdf riyazdf left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, thank you for picking this up @ecordell!

Copy link
Contributor

@cyli cyli left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! Thanks for adding this support, @ecordell!

@endophage endophage merged commit 3f8c34e into notaryproject:master Jan 27, 2017
@ecordell ecordell deleted the wildcard-certs branch February 23, 2017 12:39
@lewiada-zz
Copy link

How do I enable this feature? Today the root public key in the root.json file is a self-signed cert with CN == GUN. How do I use this such that the CN is a wildcard such as www.example.com/* ?

@endophage
Copy link
Contributor

The functionality to leverage it hasn't been added yet :-( #821 was part of the work on that but I guess @dnwake has been otherwise engaged. I pinged him a few weeks ago checking if he'd get back around to it and he said he would.

@lewiada-zz
Copy link

@endophage - we are making the changes (actually already done, just testing now) as well as some others that you and I discussed. You should see a pull request in the next few days. Once this is in place, we are planning to work on CA pinning, and then moving trust pinning into DCT. Once that's all finished, we can work on getting generalizing the pkcs11 interface to support HSMs other than Yubikey :-)

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support wildcard root certs

5 participants