Skip to content

proposal: Add GetClientCAs to tls.Config #16066

Closed
@magiconair

Description

@magiconair

tls.Config provides a GetCertificate function for providing TLS certificates dynamically. I suggest to add a GetClientCAs function to provide the same for the ClientCAs field.

Rationale: On a server the ClientCAs field is used for client certificate authentication but to my knowledge it isn't possible to extend the list of client certificates at runtime without interruption of existing connections (restart service or listener) since x509.CertPool is a struct and not safe for use by multiple go routines. A GetClientCAs function would also mirror the GetCertificate function.

I have written a reverse proxy http://github.com/eBay/fabio for which I've added the dynamic reloading of TLS certificates without restart and would like to provide the same functionality for the client cert authentication.

I'm willing to write the change if this is something that could be accepted. Target would be Go 1.8 obviously.

Activity

added this to the Proposal milestone on Jun 14, 2016
ianlancetaylor

ianlancetaylor commented on Jun 14, 2016

@ianlancetaylor
Contributor

CC @agl

added
NeedsDecisionFeedback is required from experts, contributors, and/or the community before a change can be made.
on Aug 22, 2016
bradfitz

bradfitz commented on Aug 22, 2016

@bradfitz
Contributor

Ping @agl.

magiconair

magiconair commented on Aug 24, 2016

@magiconair
ContributorAuthor

FWIW, I've implemented the patch yesterday to see how difficult it would be and it looks like it is simple. In essence, I've added a GetClientCAs func() *x509.CertPool function to tls.Config and updated clone(), the handshake, the test and api/next.txt. ~20 lines with comments. The question remains whether this is the right approach.

bradfitz

bradfitz commented on Aug 24, 2016

@bradfitz
Contributor

You need tests too, which I imagine will be more than 20 lines.

magiconair

magiconair commented on Aug 24, 2016

@magiconair
ContributorAuthor

True. So far I've only updated the clone() test. But I could factor the new decision logic out into a separate function and write a simple test for that instead of writing a full integration test. Not sure what the preferred approach is.

bradfitz

bradfitz commented on Aug 24, 2016

@bradfitz
Contributor

You'll probably want something closer to an integration test than a single unit test. For things like this, it's too easy for a unit test to be misleading.

magiconair

magiconair commented on Aug 24, 2016

@magiconair
ContributorAuthor

OK, so far I was not successful finding a test for the ClientCAs field and its current behavior in the server handshake which I could mimic/enhance but I'll keep digging. Otherwise, I'll create one.

magiconair

magiconair commented on Sep 7, 2016

@magiconair
ContributorAuthor

@bradfitz Is there a way to run a specific test with go tool dist test ? Right now I'm running go tool dist test -v go_test:crypto/tls to run the entire crypto/tls suite but I'd like to run only my TestClientCAs test if possible.

Also, how can I provide the -update parameter as suggested in crypto/tls/handshake_test.go? Working around this by setting the default to true for now.

bradfitz

bradfitz commented on Sep 7, 2016

@bradfitz
Contributor

The same way as normal Go tests:

$ go test -v -run=YourNewTest crypto/tls
magiconair

magiconair commented on Sep 7, 2016

@magiconair
ContributorAuthor

Works - of course ... I was using go from another go1.7 directory which then failed :/

Thx for the quick reply.

magiconair

magiconair commented on Sep 7, 2016

@magiconair
ContributorAuthor

OK, so I have a patch with the changes and a full integration test which is an addition to the existing tests. This involved adding a new option to generate_cert.go to create a cert which contains x509.ExtKeyUsageClientAuth and replacing the test certificates in handshake_server_test.go since the new test needs to verify the client certificate and the old test certificates do not support that. Since I'm not a crypto expert a review would be nice :)

The tests check three cases:

  • Only ClientCAs
  • Only GetClientCAs()
  • Prefer GetClientCAs() over ClientCAs

I've generated the updated testdata/* files with the homebrew version OpenSSL 1.0.2h 3 May 2016 of openssl on OSX but I don't imagine that this is the reference implementation that the crytpo/tls test refers to.

@bradfitz @agl How do we proceed?

15 remaining items

magiconair

magiconair commented on Sep 30, 2016

@magiconair
ContributorAuthor

On the same note: What if the returned *Config has a GetCertificate() function set? Ignore or call?

danp

danp commented on Sep 30, 2016

@danp
Contributor

@magiconair as @bradfitz said I think it would be good to make clear that only certain items on the Config returned by GetConfig will be respected. Then the recursion and ordering issues can be avoided.

Maybe having ALPN info on the ClientHello isn't absolutely necessary for what I'm trying to do. I could offer h2 or not and the client can accept it or not if it wants. Hopefully I'm thinking that through correctly.

Also, @bradfitz, my last comment went out too quickly and ended up sounding short. That wasn't what I intended, sorry about that. Thanks for helping move this along!

gopherbot

gopherbot commented on Oct 8, 2016

@gopherbot
Contributor

CL https://golang.org/cl/30752 mentions this issue.

magiconair

magiconair commented on Oct 8, 2016

@magiconair
ContributorAuthor

@bradfitz @danp I've added an implementation for the suggested GetClientConfig approach in https://golang.org/cl/30752. Since it takes a different approach I've created a separate change. See big comment on approach for patch set 3.

/cc @dpiddy @FiloSottile

gopherbot

gopherbot commented on Oct 10, 2016

@gopherbot
Contributor

CL https://golang.org/cl/30790 mentions this issue.

magiconair

magiconair commented on Oct 12, 2016

@magiconair
ContributorAuthor

@agl @bradfitz Shall I submit the patch I've added in the comment of https://golang.org/cl/30790 for replacing hs.c.config, c.config and config in crypto/tls/handshake_server.go with just c.config as a separate CL? This is inconsistent in the current code and I found it a bit confusing.

bradfitz

bradfitz commented on Oct 12, 2016

@bradfitz
Contributor

If you left a comment on that CL and @agl hasn't submitted it yet, he'll probably just address it before he submits.

FiloSottile

FiloSottile commented on Oct 13, 2016

@FiloSottile
Contributor

This (the CL 30790 approach) is exactly what we've been experimenting with at Cloudflare in our fork, and seems to work.

Agreed with @danp that we'll need a few more fields in the CHI, but it should be another issue/proposal/CL.

locked and limited conversation to collaborators on Oct 18, 2017
added 2 commits that reference this issue on Oct 12, 2018
0b98d05
826c39c
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    FrozenDueToAgeNeedsDecisionFeedback is required from experts, contributors, and/or the community before a change can be made.Proposal

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @danp@bradfitz@agl@magiconair@FiloSottile

        Issue actions

          proposal: Add GetClientCAs to tls.Config · Issue #16066 · golang/go