Skip to content

crypto/x509: certificate validation in Windows fails to validate IP in SAN #37176

Description

@ihgann

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

$ go version
go version go1.13.5 darwin/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="/Users/ganni/Library/Caches/go-build"
GOENV="/Users/ganni/Library/Application Support/go/env"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GONOPROXY=""
GONOSUMDB=""
GOOS="darwin"
GOPATH="/Users/ganni/.gvm/pkgsets/go1.13.5/global"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/Users/ganni/.gvm/gos/go1.13.5"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/Users/ganni/.gvm/gos/go1.13.5/pkg/tool/darwin_amd64"
GCCGO="gccgo"
AR="ar"
CC="clang"
CXX="clang++"
CGO_ENABLED="1"
GOMOD=""
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 -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/jk/kkbbm14x25l9hj_xj1rb4scm002zdg/T/go-build540477719=/tmp/go-build -gno-record-gcc-switches -fno-common"

What did you do?

I ran the following quick program to reproduce it:

package main

import (
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"time"
)

func main() {
	client := http.Client{
		Timeout: 5 * time.Second,
	}
	resp, err := client.Get("https://192.168.210.129")
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
		return
	}

	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
		return
	}

	fmt.Printf("Response:\n\n%s", string(body))
}

Where 192.168.210.129 is a custom server using a self-signed certificate. The notable aspects of this cert are that I'm connecting via IP (which is not present in the CN) and it is only present in the IP Address field of the SAN, like so:

IP Address=192.168.210.129

When I compile the binary to run on a Windows box, I run the following:

GOOS=windows GOARCH=386 go build -o quicktest.exe main.go

What did you expect to see?

I expect to see a response from the server. This server is healthy and I can access it from my browser, so I expect to see an HTML output from the last line.

What did you see instead?

I see the following output while running:

PS C:\> C:\quicktest.exe
Get https://192.168.210.129: x509: certificate is valid for 192.168.210.129, not 192.168.210.129

The interesting part is that it that's the same IP address in both notes.

I then ran a modified version of go to add a panic near https://sourcegraph.com/github.com/golang/go@release-branch.go1.11/-/blob/src/crypto/x509/root_windows.go#L129, changing:

  if status.Error != 0 {
    switch status.Error {
    case syscall.CERT_E_EXPIRED:
      return CertificateInvalidError{c, Expired, ""}
    case syscall.CERT_E_CN_NO_MATCH:
      return HostnameError{c, opts.DNSName}

to

  if status.Error != 0 {
    switch status.Error {
    case syscall.CERT_E_EXPIRED:
      return CertificateInvalidError{c, Expired, ""}
    case syscall.CERT_E_CN_NO_MATCH:
      panic("failed here")
      // return HostnameError{c, opts.DNSName}

and see the following stack trace to verify this is indeed where it fails, which is Windows-specific.

Windows PowerShell
Copyright (C) 2016 Microsoft Corporation. All rights reserved.

PS C:\> & 'C:\quicktestcustom.exe'
panic: failed here

goroutine 21 [running]:
crypto/x509.checkChainSSLServerPolicy(0x128cc2c0, 0xb2d7b8, 0x128adb6c, 0xb14850, 0x128adab8)
        /code/github.com/golang/go-darwin-amd64-bootstrap/src/crypto/x509/root_windows.go:130 +0x2c7
crypto/x509.(*Certificate).systemVerify(0x128cc2c0, 0x128adb6c, 0x0, 0x0, 0x0, 0x0, 0x0)
        /code/github.com/golang/go-darwin-amd64-bootstrap/src/crypto/x509/root_windows.go:213 +0x652
crypto/x509.(*Certificate).Verify(0x128cc2c0, 0x1289a280, 0xf, 0x128f65c0, 0x0, 0x526d9c8, 0xbf88e6b7, 0x112bdfd, 0x0, 0
x814560, ...)
        /code/github.com/golang/go-darwin-amd64-bootstrap/src/crypto/x509/verify.go:750 +0x5b6
crypto/tls.(*Conn).verifyServerCertificate(0x128fc000, 0x12892320, 0x1, 0x1, 0x3eb, 0x0)
        /code/github.com/golang/go-darwin-amd64-bootstrap/src/crypto/tls/handshake_client.go:815 +0x1e4
crypto/tls.(*clientHandshakeState).doFullHandshake(0x128adec8, 0x128ba0e0, 0x68)
        /code/github.com/golang/go-darwin-amd64-bootstrap/src/crypto/tls/handshake_client.go:452 +0x136c
crypto/tls.(*clientHandshakeState).handshake(0x128adec8, 0x128a26c0, 0x0)
        /code/github.com/golang/go-darwin-amd64-bootstrap/src/crypto/tls/handshake_client.go:397 +0x343
crypto/tls.(*Conn).clientHandshake(0x128fc000, 0x0, 0x0)
        /code/github.com/golang/go-darwin-amd64-bootstrap/src/crypto/tls/handshake_client.go:206 +0x47a
crypto/tls.(*Conn).Handshake(0x128fc000, 0x0, 0x0)
        /code/github.com/golang/go-darwin-amd64-bootstrap/src/crypto/tls/conn.go:1340 +0xe0
net/http.(*persistConn).addTLS.func2(0x0, 0x128fc000, 0x128f4400, 0x128f43c0)
        /code/github.com/golang/go-darwin-amd64-bootstrap/src/net/http/transport.go:1453 +0x34
created by net/http.(*persistConn).addTLS
        /code/github.com/golang/go-darwin-amd64-bootstrap/src/net/http/transport.go:1449 +0x175

I also further validated I do not see such issues on Linux or Mac machines.

For additional debugging help, I should also mention I only have access to one specific Windows machine that I tested with at the time, so I'm not sure if this is apparent on other Windows versions.

My Windows version is: Windows Server 2012 R2 Standard

Metadata

Metadata

Assignees

No one assigned

    Labels

    NeedsInvestigationSomeone must examine and confirm this is a valid issue and not a duplicate of an existing one.OS-Windows

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions