Skip to content

crypto/tls: client did not fail when lack of a certificate and server requires one #59012

@codemaker219

Description

@codemaker219

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

$ go version
go version go1.20.2 linux/amd64

Does this issue reproduce with the latest release?

Yes

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

go env Output
$ go env
GO111MODULE=""
GOARCH="amd64"
GOBIN=""
GOCACHE="/root/.cache/go-build"
GOENV="/root/.config/go/env"
GOEXE=""
GOEXPERIMENT=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOINSECURE=""
GOMODCACHE="/go/pkg/mod"
GONOPROXY=""
GONOSUMDB=""
GOOS="linux"
GOPATH="/go"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/usr/local/go"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/usr/local/go/pkg/tool/linux_amd64"
GOVCS=""
GOVERSION="go1.20.2"
GCCGO="gccgo"
GOAMD64="v1"
AR="ar"
CC="gcc"
CXX="g++"
CGO_ENABLED="0"
GOMOD="/dev/null"
GOWORK=""
CGO_CFLAGS="-O2 -g"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-O2 -g"
CGO_FFLAGS="-O2 -g"
CGO_LDFLAGS="-O2 -g"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -fno-caret-diagnostics -Qunused-arguments -Wl,--no-gc-sections -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build2979227275=/tmp/go-build -gno-record-gcc-switches"

What did you do?

I was playing around with mtls in golang. During testing error cases I am not sure if golang behaves correctly.
If I configure the server to force client authentication with RequireAndVerifyClientCert the client seems not to get the info, that the tls handshake was not successful.
Try this:

package main

import (
	"crypto/tls"
	"crypto/x509"
	"fmt"
	"strconv"
	"sync"
)

const CRT = "-----BEGIN CERTIFICATE-----\nMIIDHzCCAgegAwIBAgIGAYbbjzNfMA0GCSqGSIb3DQEBCwUAMBQxEjAQBgNVBAMM\nCTEyNy4wLjAuMTAeFw0yMzAzMTMxNTIwNDBaFw0yNDAzMTMxNTIwNDBaMBQxEjAQ\nBgNVBAMMCTEyNy4wLjAuMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB\nAIlfhPzb31DD3ntWPLU2HSqb0z0dkns5hNQt3EN907wT2H+wnhPu9W21nOrQNk6D\nRPfs+2qzpuzMzbC1AAEz/YFrgctUgc7IDlMWOhmKusROb/VA4596jtIQpu35gUnO\niZ16V4ufUEGMn2ZNOB1FTlp+vTOjDvcEgXyEvwTrHjBAKf7/h8Ab8yQrEMZJLjNy\nUrC8IBtUKGr0qcYSBnbT35Y6weT0prZUi21trBQNtQQtegKnN3AssZnkUar3oc1M\nPSfEO385QbTj5P0RV6lYCdNNzlzZiyf89qdK1GwqjWIC5NMEfhgCWBmdwo4SHUUo\nPELmFekxNF1CC1fqARHke/ECAwEAAaN3MHUwDwYDVR0TAQH/BAUwAwEB/zAfBgNV\nHSMEGDAWgBQFgC5rEruxtIhgyck1mfJWlgnYVzAdBgNVHQ4EFgQUBYAuaxK7sbSI\nYMnJNZnyVpYJ2FcwDgYDVR0PAQH/BAQDAgGGMBIGA1UdEQEB/wQIMAaHBH8AAAEw\nDQYJKoZIhvcNAQELBQADggEBAHPFf7OJxMHuc7NpIR/qY9gWVyICwsDVN/V92ZDm\ng4IVhiQSyTYmtjQwbN848WRtihw3aR4FX1nvaDggHoHgdH2ug1pcdUUV4CjGTqaH\nCH5IRkg7SrlC2GimPS1LKGlB9a+nruFMevPez1Cn5OyFJ87mjcVsg+iHdhOXJD6M\ng3aN+UuslneYeLhmnupjJw4c7hZtQM8TfiuZ5ck+nGMupDXFZo5iBCS+fx9l8e3b\ntJUsmov2OmEDC+7lqkds4nBAj7GCvaD7vJr2bmwj3tNY1VURugQSIhuzWTAxohry\nM+GhLnsX+JNAU2e8E9cxCcceC8IaPAbX8y1teGCt9ukIxhE=\n-----END CERTIFICATE-----\n"
const KEY = "-----BEGIN RSA PRIVATE KEY-----\nMIIEogIBAAKCAQEAiV+E/NvfUMPee1Y8tTYdKpvTPR2SezmE1C3cQ33TvBPYf7Ce\nE+71bbWc6tA2ToNE9+z7arOm7MzNsLUAATP9gWuBy1SBzsgOUxY6GYq6xE5v9UDj\nn3qO0hCm7fmBSc6JnXpXi59QQYyfZk04HUVOWn69M6MO9wSBfIS/BOseMEAp/v+H\nwBvzJCsQxkkuM3JSsLwgG1QoavSpxhIGdtPfljrB5PSmtlSLbW2sFA21BC16Aqc3\ncCyxmeRRqvehzUw9J8Q7fzlBtOPk/RFXqVgJ003OXNmLJ/z2p0rUbCqNYgLk0wR+\nGAJYGZ3CjhIdRSg8QuYV6TE0XUILV+oBEeR78QIDAQABAoIBACYEJaD2VgwbUGAQ\ngvdhFNw8SE6S9v0b81rmoBybXzOeyFy561031Xq5dkXzPfwnTrhPwFoMgobovImI\n5YnvsdmVf1NePRgU/AXZUlXMMxhtXoVgIj35pDmU+yVDVZivzBylBUIx4ftp55jf\niMZs7hyUE1cNanBIsm7bq6M4T9/pEf41Ayf0XgkMOkjn2RpZCTdwvDASw2L0hzVv\nf9lZow1LecARdwD8dMvQ0oI7P4hSCzfTCi6JLioxLuu+8yw20Rn9/r2xV2UErPhe\nxhgxAUBLwVMlArb1c+ZVXFZpx+e1tmwmqTeAKptmFQNQkljwAEQB+6GEKhV01sQ9\nCG94SlMCgYEAwWMqdGX/KkXcCkjLbuu7qMspbI9zwoXdKc2eqp5sS6jex/gzS/Y6\nx0yMTq3wUIbHfDcVlRu9cmadW483I7DZCnRX7R0GFcW6YKA/Uog+8nykd5zA/aG8\na5tALJEd3JRNihHchxHwYpQEdklzfksN/i20CxRTehlyAQMs+jJBEz8CgYEAtdmi\ntR6YbwwxhRn7/kX/H39sEsb00sFRbSCTv8TR6nuBfmjISLY949PJ4TELj7PW7vgT\n1Rut6lsR7dSyqv6+p0J6pNfu90BUni+HRDtQyI60qiMhXqfHxpEUofkK6/er0yxN\no+Wp0NQa0788rGhNR7deTGrvQAwAl+tX2MX7FM8CgYBhrMGLqtyXMFO0ChJeAsh0\nt7BDea0BKfWLoKQsDvopuLBVFeJq0oHbmakgMDA5q+ljrrrC5hDokDWYQhyadT8a\nTar/QvKI2qaJGUcCW3hXp2a2V0EOmbr+KpreJ6mKeIk1XFIjEod0cshSKkUgG66E\nm/bcxbZn7CQtqLn14J4HpwKBgDIqQn9SXFyt8W81VtWzO4jV3ttjNSB6odrH1Npf\nEkVsIrHbd/zPAU27HALaQ8U1qEIt/1KXmyd+Tfjc5xjSw4diiHC2/L4Kag1lMRx6\nfHOHIoGYxVjWUf8OALIaAJBNt4G+xABFl8365ReqtrMc5sy04feUvEFfzj4adxZe\nrz/zAoGAU502B+/HvgdodBzdw2iQJseEG1eNaUoA1co2OxHUHlaPukt5RjOwuXrP\nobVdqbtBb9aa4ZbRl9Y1yvllJMTSzrWvWra1eV3czQOVS34FwaJ06AzaUCR7ht7D\nVOObYItn69ougXDjKwHR9t/q02fLVMmUAYBKEqaVWErMzJnssrQ=\n-----END RSA PRIVATE KEY-----\n"

const PORT = 1555

var wg sync.WaitGroup

func main() {
	startServer()

	config := &tls.Config{
		RootCAs: x509.NewCertPool(),
	}
	config.RootCAs.AppendCertsFromPEM([]byte(CRT))

	con, err := tls.Dial("tcp", "127.0.0.1:"+strconv.Itoa(1555), config)
	if err != nil {
		fmt.Println("I do not have a client cert, I should reach here")
		panic(err)
	}
	defer con.Close()

	n, err := con.Write([]byte("msg"))
	if err != nil {
		fmt.Println("At least here should be a error")
		panic(err)
	}
	fmt.Printf("Wrote %d bytes\n", n)
	wg.Wait()

}

func startServer() {
	wg.Add(1)
	cert, _ := tls.X509KeyPair([]byte(CRT), []byte(KEY))
	config := &tls.Config{
		Certificates: []tls.Certificate{cert},
		ClientAuth:   tls.RequireAndVerifyClientCert,
		ClientCAs:    x509.NewCertPool(),
	}
	config.ClientCAs.AppendCertsFromPEM([]byte(CRT))

	socket, _ := tls.Listen("tcp", ":"+strconv.Itoa(PORT), config)
	buffer := make([]byte, 1024)

	go func() {
		defer wg.Done()
		defer socket.Close()
		conn, _ := socket.Accept()

		n, _ := conn.Read(buffer)
		fmt.Println(string(buffer[:n]))
		fmt.Printf("Read %d bytes\n", n)
		conn.Close()

	}()
}



What did you expect to see?

On tls.Dial or at least on n, err := con.Write([]byte("msg")) an error should be returned since the client was not able to authenticate (Dint send any client certificate). It seems like the client thinks that everything is going well...

What did you see instead?

You will see Wrote 3 bytes produced by the client part, but the server part didnt received the message msg

Metadata

Metadata

Assignees

No one assigned

    Labels

    FrozenDueToAgeNeedsInvestigationSomeone must examine and confirm this is a valid issue and not a duplicate of an existing one.

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions