caddyserver / caddy

Fast and extensible multi-platform HTTP/1-2-3 web server with automatic HTTPS
https://caddyserver.com
Apache License 2.0
56.83k stars 3.98k forks source link

Current state of support for CHACHA20-POLY1305? #798

Closed fourstring closed 7 years ago

fourstring commented 8 years ago

Hello, Thanks for the server software,it is great!And it really simplified my website building. But I think on the platform without AES-NI,AES-GCM will be slow.On such platform,chacha20 is better. So could you support CHACHA20? By the way,BoringSSL support 'Equivalent encryption algorithm group',which can choose between AES and CHACHA20 automaticly according to users' platform.The cipher suites like follow: ECDHE-ECDSA-CHACHA20-POLY1305-SHA384|ECDHE-ECDSA-AES-128-GCM-SHA384:.... When you open the site on PC,cipher suite will use AES,if you use mobilephone,it will use chacha20. Would you support this feature? Thank you!

mark-kubacki commented 8 years ago

I will address only CHACHA20, everything else belongs in a separate ticket:

We use Golang's tls library. When CHACHA20 and POLY1305 land there, they will be usable in Caddy. Please file a ticket with golang/go. (I guess there already is one.)

Update, here it is: https://github.com/golang/go/issues/6914

captncraig commented 8 years ago

Regarding cipher suite selection per platform, that is why the tls handshake exists. It is up to the client to give ciphers they want in order of preference, and the server selects from that list, taking their own preference into account. Caddy's tls does this according to the spec, again using golang's tls library. You can specify cipher for the server to use, but any more complicated requests should go through the go team.

On Sat, Apr 30, 2016 at 7:40 AM, W. Mark Kubacki notifications@github.com wrote:

Closed #798 https://github.com/mholt/caddy/issues/798.

— You are receiving this because you are subscribed to this thread. Reply to this email directly or view it on GitHub https://github.com/mholt/caddy/issues/798#event-646524390

mark-kubacki commented 8 years ago

Reopening this because we're toying around with alternate TLS stacks.

This ticket is not meant for feedback or questions on this or other alternate versions. Email, or start a chat on Gitter for that. We track what's in or not in the official version here.

mholt commented 8 years ago

Thanks for experimenting with it Mark! I'm going to close this now since there's not much actionable for us to do right now. I suppose the best thing to do right now is wait and see when CHACHA20 will be implemented in the Go standard library.

mark-kubacki commented 8 years ago

I've a builder ready in case the need arises. Builds my toy versions of Caddy: https://hub.blitznote.com/mark/caddy/builds

bigtan commented 7 years ago

chacha20 is available in go standard library.

https://github.com/golang/go/commit/67d8226b4862f0f8deb4dc6fa8617017ecb0f32b

mholt commented 7 years ago

Yep, so Caddy will be able to support it when it's built with the next version of Go.

elcore commented 7 years ago

@mholt I will update Caddy :smile: together with the available curves

mark-kubacki commented 7 years ago

Put X25519 first. ;-)

wendigo commented 7 years ago

@elcore I already did that while hacking caddy's code. I can send PR :)

elcore commented 7 years ago

Put X25519 first. ;-)

@wmark I don't need to -- It already is :) -- Caddy changes the curves just on preference

https://github.com/golang/go/blob/cff3e7587a516933d842c11b68bdd346ae6fc9be/src/crypto/tls/common.go#L598

diff --git a/caddytls/config.go b/caddytls/config.go
index 92e5729..7c2b692 100644
--- a/caddytls/config.go
+++ b/caddytls/config.go
@@ -456,9 +456,10 @@ var defaultCiphers = []uint16{
 // Map of supported curves
 // https://golang.org/pkg/crypto/tls/#CurveID
 var supportedCurvesMap = map[string]tls.CurveID{
-       "P256": tls.CurveP256,
-       "P384": tls.CurveP384,
-       "P521": tls.CurveP521,
+       "X25519": tls.X25519,
+       "P256":   tls.CurveP256,
+       "P384":   tls.CurveP384,
+       "P521":   tls.CurveP521,
 }

 const (

diff --git a/caddytls/setup_test.go b/caddytls/setup_test.go
index b630e74..e5445c5 100644
--- a/caddytls/setup_test.go
+++ b/caddytls/setup_test.go
@@ -283,7 +283,7 @@ func TestSetupParseWithKeyType(t *testing.T) {

 func TestSetupParseWithCurves(t *testing.T) {
        params := `tls {
-            curves p256 p384 p521
+            curves x25519 p256 p384 p521
         }`
        cfg := new(Config)
        RegisterConfigGetter("", func(c *caddy.Controller) *Config { return cfg })
@@ -294,11 +294,11 @@ func TestSetupParseWithCurves(t *testing.T) {
                t.Errorf("Expected no errors, got: %v", err)
        }

-       if len(cfg.CurvePreferences) != 3 {
-               t.Errorf("Expected 3 curves, got %v", len(cfg.CurvePreferences))
+       if len(cfg.CurvePreferences) != 4 {
+               t.Errorf("Expected 4 curves, got %v", len(cfg.CurvePreferences))
        }

-       expectedCurves := []tls.CurveID{tls.CurveP256, tls.CurveP384, tls.CurveP521}
+       expectedCurves := []tls.CurveID{tls.X25519, tls.CurveP256, tls.CurveP384, tls.CurveP521}

        // Ensure ordering is correct
        for i, actual := range cfg.CurvePreferences {
elcore commented 7 years ago

@elcore I already did that while hacking caddy's code. I can send PR :)

@wendigo I did the same :) -- You don't need to

elcore commented 7 years ago

POLL:

Should TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY130 - TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305 be before (Mozilla - 1) or after (Go - 2):

[here - 2 ]
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
[here - 1]
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
wendigo commented 7 years ago

Refering to crypto/tls/cipher_suites.go:

// Ciphersuite order is chosen so that ECDHE comes before plain RSA and
// AEADs are the top preference.

So order should be consistent with: https://github.com/golang/go/blob/master/src/crypto/tls/cipher_suites.go#L80

elcore commented 7 years ago

Refering to crypto/tls/cipher_suites.go

@wendigo Thank you, forgot to add it :)

So order should be consistent with: https://github.com/golang/go/blob/master/src/crypto/tls/cipher_suites.go#L80

Okay 👍

mark-kubacki commented 7 years ago

A server with AES-NI can serve more connections at a decreased load with AES-NI ciphers than with CHACHA20*. So suites with AES should go first, unless a client sends a CHACHA20 variant as the first in its list.

With Golang 1.8 you'd reorder suites accordingly. https://go-review.googlesource.com/#/c/30790/ https://github.com/wmark/caddy/blob/bf477ab1cce80b908f4593b9310a26c79f1684fe/caddy/https/settings_alttls.go#L139-L153

// isChaCha returns true if the cipher suite uses Salsa/ChaCha20 as cipher.
func isChaCha(suiteID uint16) bool {
    switch suiteID {
    case 0xcc13, 0xcc14, 0xcca8, 0xcca9, 0xccac:
        return true
    default:
        return false
    }
}

// GetConfigForClient =
func PreferChaChaIfFirst(clientHello *tls.ClientHelloInfo) (*tls.Config, error) {
    if !isChaCha(clientHello.CipherSuites[0]) {
        return nil // first copy of tls.Config, with AES suites at the top
    }
    // Return the second copy of tls.Config, with CHACHA suites at the top.
    // It's safe to set TLSv1.2 as the minimum version here.
}
elcore commented 7 years ago

@wmark It is your code, literally :) -- I give you the honour to implement it

Edit: I could not resist 😄, sorry! -- A virtual 🍰 for you!

elcore commented 7 years ago

Please take a look at https://github.com/elcore/caddy/tree/GetConfigForClient-CHACHA20-POLY1305 -- Especially you @wmark

screenshot 11 screenshot 12

mark-kubacki commented 7 years ago

@elcore That warrants a separate PR. Iff mholt wants you to move this forward, that is.

Keep in mind that:

Then:

elcore commented 7 years ago

@wmark

Not all suites are on by default (for example, CHACHA_OLD if vanilla Go has it, is off by default).

Golang does not support CHACHA_OLD -- So, I do not need it

Some suites are TLSv1.2+ only and won't show when you artificially limit TLS to v1.1.

Just a test to show that the code works 😄

tlsConfig.MaxVersion = tlsConfig.MinVersion only iff max < min (not in the screenshot, but your branch). You don't want to touch that code again when tls.VersionTLS13 is in.

Okay 😄

Hit win+R, type gpedit.msc. Go to Computer… → Admin… → System… → Internet… → Internet… and go through the settings.

I do not want to -- I want to keep everything "vanilla"

Edit: Go to https://github.com/elcore/caddy/tree/GetConfigForClient-CHACHA20-POLY1305 to review

bigtan commented 7 years ago

Any progress ?

elcore commented 7 years ago

Yes @bigtan -- We just need to wait for Go 1.8

https://twitter.com/eldinhadzic_/status/802290920314040320

wendigo commented 7 years ago

Let's hope go1.8 will land on Feb 1 :)

lhecker commented 7 years ago

We should btw make sure that as soon as we add CHACHA20 with Go 1.8, we also add proper, sane defaults for cfg.CurvePreferences (it should be [tls.X25519, tls.CurveP256]) and possibly reorder the defaultCiphers (some RSA ciphers are ordered before their respective ECDSA ones).

mholt commented 7 years ago

@lhecker Take a look at https://github.com/elcore/caddy/commit/eea4e0eeec7497482ee9a7498ca9bc08957a7cf4 - we might do something like this (but I haven't looked in detail yet, it'll probably change a little bit).

reorder the defaultCiphers (some RSA ciphers are ordered before their respective ECDSA ones).

Really? Which ones? I see ECDSA first for otherwise-equivalent cipher suites.

@elcore How are we doing with curve preferences? They're only used in the config.go and setup.go files of the caddytls package. Does that mean we just use Go's default curve preferences unless the user specifies them?

lhecker commented 7 years ago

@mholt @elcore's fork seems to be interesting, but unfortunately I don't quite understand the purpose of it. In my understanding during the TLS handshake the client sends a list of supported ciphers and the server may choose one. And what his fork does is to basically view CHACHA20 as equally good as the best server provided cipher right? So in effect it's the same as if CHACHA20 would simply be the topmost preferred cipher: If the client supports it it's chosen and if not it's not. Or is there otherwise (without the fork's optimization) an additional roundtrip involved?

I see ECDSA first for otherwise-equivalent cipher suites.

Here you can see that AES128 is ordered before AES256 as well as RSA before ECDSA.

Does that mean we just use Go's default curve preferences unless the user specifies them?

Yep.

mholt commented 7 years ago

@lhecker

Here you can see that AES128 is ordered before AES256 as well as RSA before ECDSA.

That's a map, the order there is irrelevant. The ordering in the defaultCiphers list below it is much more important.

As for the rest of @elcore's changes i have yet to look at them -- will do when I'm done with work for the day.

lhecker commented 7 years ago

@mholt Ah yes sorry. Let's note this as a coding style issue to save me from the disgrace. 😂 Is the ordering of the defaultCiphers list okay though?

mholt commented 7 years ago

Oh, right, those could probably be switched now.

elcore commented 7 years ago

@mholt

How are we doing with curve preferences? They're only used in the config.go and setup.go files of the caddytls package. Does that mean we just use Go's default curve preferences unless the user specifies them?

Yes :) (https://golang.org/src/crypto/tls/common.go)

< Go 1.8

var defaultCurvePreferences = []CurveID{CurveP256, CurveP384, CurveP521}

> Go 1.8

var defaultCurvePreferences = []CurveID{X25519, CurveP256, CurveP384, CurveP521}
elcore commented 7 years ago

@lhecker

In my understanding during the TLS handshake the client sends a list of supported ciphers and the server may choose one. And what his fork does is to basically view CHACHA20 as equally good as the best server provided cipher right? So in effect it's the same as if CHACHA20 would simply be the topmost preferred cipher: If the client supports it it's chosen and if not it's not. Or is there otherwise (without the fork's optimization) an additional roundtrip involved?

"A server with AES-NI can serve more connections at a decreased load with AES-NI ciphers than with CHACHA20*. So suites with AES should go first, unless a client sends a CHACHA20 variant as the first in its list." @wmark

TLS Client -> Call PreferChaChaIfFirst(ClientHelloInfo)

If the client prefers CHACHA20 e.g. Android devices then move it to the front.

tls_elcore

https://blog.cloudflare.com/do-the-chacha-better-mobile-performance-with-cryptography/

emansom commented 7 years ago

Please take into account that until 6th generation chips (Skylake) Intel only enabled AES-NI on high end CPU's.

Thus most consumers nowadays browse the web with a machine that isn't AES-NI capable and doesn't do the reordering trick Android uses. Such clients benefit from ChaCha20, but prefer AES instead.

In order to get around this I propose advertising the ChaCha20 cipher as first one. Like Mozilla recommends.[1]

1: "ChaCha20 is prefered as the fastest and safest in-software cipher, followed by AES128. Unlike the modern configuration, we do not assume clients support AESNI and thus do not prioritize AES256 above 128 and ChaCha20."

mholt commented 7 years ago

@emansom That's already being considered, see https://github.com/mholt/caddy/issues/1375:

Ensure ChaCha20-Poly1305 is prioritized unless there is hardware support for AES-GCM suites

Go 1.8 will also be using this strategy.

In fact, I think I'll close this issue in favor of the other one for tracking this.

elcore commented 7 years ago

@mholt @emansom

Thus most consumers nowadays browse the web with a machine that isn't AES-NI capable and doesn't do the reordering trick Android uses. Such clients benefit from ChaCha20, but prefer AES instead.

It is not easy to balance this out.

On the one hand, you want to reduce the load on the server, on the other hand, you want to reduce the load on the client.

There is no clean solution:

mholt commented 7 years ago

I think I misread some of the earlier comments.

Some major CDNs do server preference, but will use ChaCha if it is first in the client's list. TLS 1.3 implementations will tend toward whichever of the two the client wants first. Most/all desktop (and server) hardware has AES-NI (my cheapo DO droplet has it), but most mobile doesn't.

So, to optimize server performance, prefer AES, since it probably has AES-NI support. I wouldn't be opposed to that.

Or we could cater to mobile clients.

I think there are good arguments to both sides. I also think the difference is probably not too much for most people. Let's just stick with preferring AES for now and give the busy server a little breathing room. We can always change this later.