Description
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
ianlancetaylor commentedon Jun 14, 2016
CC @agl
bradfitz commentedon Aug 22, 2016
Ping @agl.
magiconair commentedon Aug 24, 2016
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 totls.Config
and updatedclone()
, the handshake, the test andapi/next.txt
. ~20 lines with comments. The question remains whether this is the right approach.bradfitz commentedon Aug 24, 2016
You need tests too, which I imagine will be more than 20 lines.
magiconair commentedon Aug 24, 2016
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 commentedon Aug 24, 2016
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 commentedon Aug 24, 2016
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 commentedon Sep 7, 2016
@bradfitz Is there a way to run a specific test with
go tool dist test
? Right now I'm runninggo tool dist test -v go_test:crypto/tls
to run the entirecrypto/tls
suite but I'd like to run only myTestClientCAs
test if possible.Also, how can I provide the
-update
parameter as suggested incrypto/tls/handshake_test.go
? Working around this by setting the default totrue
for now.bradfitz commentedon Sep 7, 2016
The same way as normal Go tests:
magiconair commentedon Sep 7, 2016
Works - of course ... I was using
go
from anothergo1.7
directory which then failed :/Thx for the quick reply.
magiconair commentedon Sep 7, 2016
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 containsx509.ExtKeyUsageClientAuth
and replacing the test certificates inhandshake_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:
ClientCAs
GetClientCAs()
GetClientCAs()
overClientCAs
I've generated the updated
testdata/*
files with the homebrew versionOpenSSL 1.0.2h 3 May 2016
ofopenssl
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 commentedon Sep 30, 2016
On the same note: What if the returned
*Config
has aGetCertificate()
function set? Ignore or call?danp commentedon Sep 30, 2016
@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 commentedon Oct 8, 2016
CL https://golang.org/cl/30752 mentions this issue.
magiconair commentedon Oct 8, 2016
@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 commentedon Oct 10, 2016
CL https://golang.org/cl/30790 mentions this issue.
magiconair commentedon Oct 12, 2016
@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
andconfig
incrypto/tls/handshake_server.go
with justc.config
as a separate CL? This is inconsistent in the current code and I found it a bit confusing.bradfitz commentedon Oct 12, 2016
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 commentedon Oct 13, 2016
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.
crypto/tls: add Config.GetConfigForClient
crypto/tls: add Config.GetConfigForClient