golang / go

The Go programming language
https://go.dev
BSD 3-Clause "New" or "Revised" License
124.06k stars 17.68k forks source link

crypto/tls: error with client certificate and X448 and X25519 curves #33577

Open cromefire opened 5 years ago

cromefire commented 5 years ago

What version of Go are you using (go version)?

$ go version
go version go1.12.7 linux/amd64

Does this issue reproduce with the latest release?

Yes (1.12.7)

What operating system and processor architecture are you using (go env)?

go env Output ``` $ go env GOARCH="amd64" GOBIN="" GOCACHE="/home//.cache/go-build" GOEXE="" GOFLAGS="" GOHOSTARCH="amd64" GOHOSTOS="linux" GOOS="linux" GOPATH="/home//go" GOPROXY="direct" GORACE="" GOROOT="/usr/local/go" GOTMPDIR="" GOTOOLDIR="/usr/local/go/pkg/tool/linux_amd64" GCCGO="gccgo" CC="gcc" CXX="g++" CGO_ENABLED="1" GOMOD="/home//go/src/test/go.mod" CGO_CFLAGS="-g -O2" CGO_CPPFLAGS="" CGO_CXXFLAGS="-g -O2" CGO_FFLAGS="-g -O2" CGO_LDFLAGS="-g -O2" PKG_CONFIG="pkg-config" GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build069598509=/tmp/go-build -gno-record-gcc-switches" ```

What did you do?

As far as I've been able to reproduce it it only happens with an ecc client certificate and a rsa server certificate.

https://gist.github.com/cromefire/590eb9743dbadeca89c213b0aa1a2d58 (play.golang.org doesn't work with tcp it seems)

The same thing using curl works:

curl -vk --cert ecccert.pem --key ecckey.pem https://go-issue.cromefire.myds.me

The backend server (Apache/2.4.39 (Ubuntu), with OpenSSL 1.1.1c) is using no special config:

<VirtualHost *:443>
    # Skipped Name, logging and DocumentRoot

    Include includes/ssl.conf  # TLS certs, rsa ones
    SSLProtocol TLSv1.2
    SSLVerifyClient optional_no_ca
</VirtualHost>

For debugging purposes the program creates /tmp/keylog.txt which can be imported into wireshark

What did you expect to see?

The expected result are no errors

What did you see instead?

rsa-ecc: ok
ecc-ecc: ok
nocert-ecc: ok
rsa-rsa: ok
ecc-rsa: Get https://go-issue.cromefire.myds.me: remote error: tls: illegal parameter
nocert-rsa: ok
cromefire commented 5 years ago

Some packets captured with wireshark (of the broken request): pkts.txt

cromefire commented 5 years ago

It seems to work with nginx, but before anyone starts marking this as apache issue: It works with curl and apache

cromefire commented 5 years ago

The underlying issue seems that it rejects X448 and X25519 which are the only curves allowed by the server currently

calmh commented 5 years ago

AFAIK, you need to allow the curve in use by the certificate in order to be able to verify it. That's P384 or P256. For what it's worth, your server also does not work for me with curl and a Syncthing-generated certificate:

jb@kvin:~/foo $ syncthing -generate .
16:06:52 INFO: Device ID: UAXNKTY-34GLUSN-EZYFR4M-PKLSFHQ-32ZWHXZ-TR7WXSN-6UO44VY-OI55LQR
16:06:52 INFO: Default folder created and/or linked to new config
jb@kvin:~/foo $ curl -vk --cert cert.pem --key key.pem https://go-issue.cromefire.myds.me
* Rebuilt URL to: https://go-issue.cromefire.myds.me/
*   Trying 91.63.83.36...
...
* error:1401E417:SSL routines:CONNECT_CR_FINISHED:sslv3 alert illegal parameter
* stopped the pause stream!
* Closing connection 0
curl: (35) error:1401E417:SSL routines:CONNECT_CR_FINISHED:sslv3 alert illegal parameter
cromefire commented 5 years ago

you need to allow the curve in use by the certificate in order to be able to verify it

Verification should be fine, it should only block it from being used to negotiate a shared key

I have no problem using curl:

~$ syncthing -generate .
16:20:00 INFO: Device ID: KTXYHRS-FZGLNVC-X4QQWNY-3UONW33-H3GZJLT-2JVKXW7-IJM4OYW-P5BB7AP
16:20:00 INFO: Default folder created and/or linked to new config
~$ curl -vk --cert cert.pem --key key.pem https://go-issue.cromefire.myds.me --tlsv1.2
* Rebuilt URL to: https://go-issue.cromefire.myds.me/
*   Trying 91.63.83.36...
[...]
<address>Cromefire Web Frontend Server at go-issue.cromefire.myds.me Port 443</address>
</body></html>
* Connection #0 to host go-issue.cromefire.myds.me left intact

Version:

curl 7.58.0 (x86_64-pc-linux-gnu) libcurl/7.58.0 OpenSSL/1.1.1 zlib/1.2.11 libidn2/2.0.4 libpsl/0.19.1 (+libidn2/2.0.4) nghttp2/1.30.0 librtmp/2.3
Release-Date: 2018-01-24
Protocols: dict file ftp ftps gopher http https imap imaps ldap ldaps pop3 pop3s rtmp rtsp smb smbs smtp smtps telnet tftp 
Features: AsynchDNS IDN IPv6 Largefile GSS-API Kerberos SPNEGO NTLM NTLM_WB SSL libz TLS-SRP HTTP2 UnixSockets HTTPS-proxy PSL
calmh commented 5 years ago

Okay, I’ve clearly misunderstood something on that point. Regardless, why don’t you allow the more common curves, is this really the out of the box config in your Ubuntu?

cromefire commented 5 years ago

why don’t you allow the more common curves, is this really the out of the box config in your Ubuntu

No there is apparently (still) a bug in apache that makes the ssl configuration for vhosts on the same port be kind of shared and all my other vhosts are restricted to those 2 curves

calmh commented 5 years ago

Right. So I'll leave this issue for the Go team to decide, but from my point of view after troubleshooting this with your for literally hours -- where you claim a default config, "no special config", and a bug in our code or Go -- only to discover you've disabled a major swath of the relevant cipher stuff in a very unusual way and declined to mention it... I find that disrespectful and a huge waste of time. Over and out.

cromefire commented 5 years ago

where you claim a default config, "no special config"

I didn't know about this bug in apache either and as curl worked fine, I wasn't thinking that the config some how applied to that vhost and it still seems like there is a bug, just a different one than what I thought (2 bug coming together and one disguising the other)