Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for setting SNI hostname and set for client SSL handler #1698

Closed
wants to merge 8 commits into from

Conversation

lulf
Copy link

@lulf lulf commented Nov 3, 2016

No description provided.

@vietj vietj added the to review label Nov 3, 2016
@lulf lulf force-pushed the support-tls-sni-client-option branch from 4b2f3e5 to 1adc8b6 Compare November 3, 2016 13:03
@lulf
Copy link
Author

lulf commented Nov 3, 2016

I wasn't sure if this should be put in ClientOptionsBase instead, since I think it only makes sense for clients. But I came to the conclusion that I liked it better along with other ssl options.

@lulf lulf force-pushed the support-tls-sni-client-option branch from 1adc8b6 to 6642cc8 Compare November 22, 2016 09:57
@vietj
Copy link
Member

vietj commented Nov 23, 2016

I just checked and it supports only a single host, we want instead to support a mapping of domain->key/cert that is supported by Netty's io.netty.handler.ssl.SniHandler.

so it seems (as far as I understand after a quick look), we should use the SniHandler with a mapping of domain->SslContext to fully implement this feature.

the TCPSSLOptions would have a Map<String, KeyCertOptions> somehow.

@lulf lulf force-pushed the support-tls-sni-client-option branch from 6642cc8 to bc694f0 Compare December 8, 2016 13:34
@lulf
Copy link
Author

lulf commented Dec 8, 2016

@vietj I've updated the PR to use SniHandler for server side mapping of host -> SslContext instead of SNIMatcher directly. The end2end interaction is tested in the SSLEngineTest integration test, where I made it use a different certificate for the sni host.

I haven't paid much attention to how this is exposed in the options, so please comment on how you would like that.

@lulf lulf force-pushed the support-tls-sni-client-option branch from bc694f0 to 3ebf171 Compare December 8, 2016 13:47
@vietj
Copy link
Member

vietj commented Dec 8, 2016

@lulf thanks going to review it next week

@@ -280,6 +281,13 @@ public HttpServerOptions addEnabledCipherSuite(String suite) {
}

@Override
@GenIgnore
Copy link
Member

Choose a reason for hiding this comment

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

I believe we should try to handle Map<String, Options> in codegen to not have GenIgnore

Copy link
Author

Choose a reason for hiding this comment

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

Fixed

@vietj
Copy link
Member

vietj commented Jan 3, 2017

@lulf

  • instructions on how to create server-virt-cert.pem and the key are missing in src/test/resources/tls/ssl.txt
  • there should be test in HttpTLSTest with various formats keystore/pkcs12/pem

@lulf lulf force-pushed the support-tls-sni-client-option branch 2 times, most recently from fe6ce6c to 93fa66d Compare January 3, 2017 18:37
@lulf
Copy link
Author

lulf commented Jan 3, 2017

@vietj

Instructions added, and I added a single test to HttpTLSTest that verifies that the cert is working. It's generated the same way as the server-cert.pem, because for SNI I needed another cert that was not trusted by the default ssl context. I'm not sure if adding more tests to HttpTLSTest is necessary.

Also, there are some test failures I need to look into that I just discovered.

* Allow setting SNI hostname for clients
* Allow adding different key store options for servers

Signed-off-by: Ulf Lilleengen <ulf.lilleengen@gmail.com>
@lulf lulf force-pushed the support-tls-sni-client-option branch from 93fa66d to 53e9bf2 Compare January 4, 2017 18:46
@lulf
Copy link
Author

lulf commented Jan 4, 2017

@vietj

In addition to addressing your comments, I had to add some more functionality to SSLHelper to be able to support listening for handshakes and setting SSLEngine properties as several tests were failing due to that. Now all the unit tests pass here.

@vietj
Copy link
Member

vietj commented Jan 4, 2017

@lulf has it been pushed ? can you update the issue and list all the changes ?

@lulf
Copy link
Author

lulf commented Jan 5, 2017

@vietj

All code is pushed to this branch yes. Not sure what issue you are referring to, but these are the changes I've done:

  • Add option for controller client side SNI host parameter
  • Add option for adding per-domain keyCert options
  • Add SNIhandler with domain -> context mapping that extends the netty SniHandler to support vert.x usage of listening to handshake and setting engine options.
  • Replaced SslHandler with SNIHandler for http and net servers implementations
  • Added another certificate with instructions to be used in SNI tests, added simple unit test to HttpTLSTest to verify cert is working
  • Add unit tests for ssl helper SNI stuff in SSLHelperTest
  • Add integration test for SNI support in SSLEngineTest

@vietj vietj mentioned this pull request Jan 5, 2017
@lulf
Copy link
Author

lulf commented Jan 5, 2017

Ah, that issue :)

@vietj
Copy link
Member

vietj commented Jan 5, 2017

@lulf there are a few things to change but before continuing I would like to focus on the most important part:

The SSL test in HttpTLSTest is incorrect because it only tests the SNI certificate validity as a certificate and does not configure the SNI server. Also the HttpServer does not implement SNI, otherwise the added test in HttpTLSTest would fail and it passes.

Such test can only be added if the *Client supports SNI as well or if we use directly Netty to write the client part of the tests.

So right now we need to have at least the HttpServer implement SNI and to have this tested effectively.

@lulf
Copy link
Author

lulf commented Jan 5, 2017

@vietj

This is tested in src/test/java/io/vertx/test/it/SSLEngineTest.java . It uses HttpServer and I modified it to tests that a client sets SNI and that it works and doesn't work.

@vietj
Copy link
Member

vietj commented Jan 5, 2017

@lulf my bad I did not have the correct version of files I see now createSNIHandler called by HttpServer and client

still the test testTLSCLientTrustVirtServerCertPEM does not seem correct as the caller does not configure SNI in server/client

@lulf
Copy link
Author

lulf commented Jan 5, 2017

@vietj

That is why i was a bit puzzled why I should have to add that test, since I already tested it in SSLEngineTest. I thought it was just to test certificate validity. I can extend that test to use SNI also, although it would still test the same thing.

@vietj
Copy link
Member

vietj commented Jan 5, 2017

@lulf yes, I beleive the Trust / Cert classes should configure the TCPSSLOptions rather with somehting configure(TCPSSLOPtions) which means a bit of refactoring.

* Add a few testcases to test different combinations
@lulf
Copy link
Author

lulf commented Jan 5, 2017

@vietj

I modified the TLSTest to take a SNI parameter for client and for server, and extended with a few testcases.

I'll just create separate commits during the review and squash them at the end to make it easier to see what has changed.

/**
* Custom SNI handler that allows for listening to handshakes and configuring the SSLEngine.
*/
public class SNIHandler extends SniHandler {
Copy link
Member

Choose a reason for hiding this comment

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

Make it a normal class (not inner) and rename VertxSniHandler

@@ -292,6 +292,12 @@ public HttpClientOptions setSsl(boolean ssl) {
}

@Override
public HttpClientOptions setSNIServerName(String serverName) {
Copy link
Member

Choose a reason for hiding this comment

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

rename setSniServerName as the rest of the options tends to use non capital acronyms

@vietj
Copy link
Member

vietj commented Jan 10, 2017

@lulf so here is what we can do : add a setVirtualHost(String) on HttpClientRequest, when this setter is called then the value is used as SNI server name and it overrides the HTTP host value sent to the server, i.e it would call setHost() with the value automatically (but the user might override again the host value after with setHost if he wants to but has to do it explicitely).

@vietj
Copy link
Member

vietj commented Jan 12, 2017

@lulf any news for setVirtualHost ?

@vietj vietj closed this Jan 12, 2017
@vietj vietj reopened this Jan 12, 2017
@vietj vietj added to review and removed to review labels Jan 12, 2017
@lulf
Copy link
Author

lulf commented Jan 12, 2017

@vietj I've added the method to the interface but haven't been able to wire things in the implementation yet. A bit busy the coming days unfortunately.

@vietj
Copy link
Member

vietj commented Jan 12, 2017

@lulf thanks for the headsup

@theoweiss
Copy link
Contributor

Is there any chance to get this feature into 3.4.1?

@theoweiss
Copy link
Contributor

theoweiss commented Mar 27, 2017

Sorry, this feature is really important for our services based on vertx. @lulf @vietj do you have a plan when this PR will be ready to merge?

@lulf
Copy link
Author

lulf commented Mar 28, 2017

@theoweiss Unfortunately I don't have any time left to work on this these days, and there seems to be a lot of code changes in the code that the PR touches, so I don't think this will be merged unless someone else picks up the pieces or restarts the effort.

@vietj
Copy link
Member

vietj commented Mar 28, 2017

the effort is interesting, I would really like to grap well how the SNI configuration side, both on the server and on the client.

for instance it seems possible with Java keystores to map SNI hostname using keystores aliases instead of having a Map<String, KeyCertOptions> / Map<String, TrustOptions> which would get the actual stuff simpler.

@vietj
Copy link
Member

vietj commented Mar 28, 2017

and I would like it to be done soon, perhaps in a Vert.x 3.4.2 release. I believe the technical bits are here, it's only a matter of providing good configuration imho.

@vietj
Copy link
Member

vietj commented Apr 14, 2017

I've started a new branch for SNI (reused a few bits of this PR, thanks) : https://github.com/eclipse/vert.x/tree/sni-support

At the moment it provides NetSocket support only, the main point is the extension of the KeyCertOptions interface that provides a mapper of serverName to Key+CertChain. The ssl context are cached in SSLHelper based on the certificate used for the handshake.

@xkr47 you are probably interested in following this branch

@xkr47
Copy link
Contributor

xkr47 commented Apr 14, 2017

@vietj sure!
Some quick thoughts:

  • It's perfectly possible that a remote client gives our server a SNI hostname that doesn't exist, therefore mgr = keyCertOptions.keyManagerMapper(vertx).apply(serverName); may be null. In my DynamicCertManager solution I provide the option of choosing a default certificate, or to leave the server without a default, in which case the TLS handshake fails when client-speicifed hostname does not match any certificate. The latter is imo a good additional layer of defense agains attackers randomly bombing servers by IP; their attack surface will be a lot smaller if they don't know a valid hostname.
  • As a server implementor I would like to be able to query incoming connections/requests what certificate or hostname was used in the TLS handshake.

@vietj
Copy link
Member

vietj commented Apr 15, 2017

thanks for the feedback, will take it in account

@vietj
Copy link
Member

vietj commented Apr 15, 2017

you can know already the certificate on NetSocket, I believe we should add the same on HttpConnection and both should have the serverName

@vietj
Copy link
Member

vietj commented Apr 20, 2017

I've mostly finished the SNI support (not the docs yet) : you can have a look https://github.com/eclipse/vert.x/tree/sni-support

@vietj
Copy link
Member

vietj commented Apr 20, 2017

@lulf can you have a look at it and how it can be used for your use cases ?

@xkr47
Copy link
Contributor

xkr47 commented Apr 20, 2017

I would propose that DEFAULT_SNI is changed to true as soon as the feature is considered stable; unsupporting servers will simply ignore it.

@vietj
Copy link
Member

vietj commented Apr 24, 2017

the sni-support branch has now a PR opened for review, you might want to have a look and provide feedback #1954

@vietj
Copy link
Member

vietj commented Apr 24, 2017

@xkr47 you mean for HttpClientOptions ?

@xkr47
Copy link
Contributor

xkr47 commented Apr 24, 2017

@xkr47 you mean for HttpClientOptions ?

Yes

@vietj
Copy link
Member

vietj commented Apr 24, 2017

@xkr47 I propose to leave it as false for now for the release 3.4.x and switch it to true when we'll be on 3.5.0-SNAPSHOT

@vietj
Copy link
Member

vietj commented Apr 27, 2017

closing this PR, thanks @lulf for the contribution

@vietj vietj closed this Apr 27, 2017
@vietj vietj removed the to review label Apr 27, 2017
@lulf lulf deleted the support-tls-sni-client-option branch April 27, 2017 13:00
@xkr47
Copy link
Contributor

xkr47 commented Apr 27, 2017

Thanks @lulf!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants