Skip to content

crypto/x509: Certificate.Verify on darwin no longer returns UnknownAuthorityError when the system verifier is used #53401

@dnephin

Description

@dnephin

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

1.18.2

I'm pretty sure this is a regression from https://go-review.googlesource.com/c/go/+/353132 (#46287).

Does this issue reproduce with the latest release?

Yes

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

The bug reproduces on darwin/arm64 (and I suspect darwin/amd64 as well). I tested that the bug does not exist on linux/amd64.

What did you do?

Below is a minimal reproduction.

package main

import (
	"crypto/x509"
	"errors"
	"fmt"
	"net/http"
	"net/http/httptest"
	"time"
)

func main() {
	handler := func(w http.ResponseWriter, req *http.Request) {
		w.WriteHeader(200)
	}
	srv := httptest.NewTLSServer(http.HandlerFunc(handler))
	defer srv.Close()

	req, _ := http.NewRequest("GET", srv.URL, nil)
	c := http.Client{Timeout: time.Second}
	_, err := c.Do(req)

	fmt.Println(err)
	var uaErr x509.UnknownAuthorityError
	ok := errors.As(err, &uaErr)
	fmt.Println("should be true", ok)
}

The problem can be seen in libraries as well. For example this commit hashicorp/go-retryablehttp@bff1f16 is someone trying to work around the problem in hashicorp/go-retryablehttp.

What did you expect to see?

I expected the underlying error (url.Error.Err) to be x509.UnknownAuthorityError on all platforms regardless of what value I used for tls.Config.RootCAs.

In most cases:

  • on linux/amd64 with all versions of Go
  • on darwin with Go <= 1.17.x
  • when using non-system roots (i.e. any non-default value for tls.Config.RootCAs)

the errors.As(err, &uaErr) line correctly returns true, and the caller is able to inspect the certificate.

I did not test on windows, but from a quick read of root_windows.go it seems there is some effort made to create an UnknownAuthorityError in a number of cases, so it is likely that it works correctly on windows as well.

What did you see instead?

On darwin with Go 1.18.x , errors.As(err, &uaErr) returns false. The error is something like this:

url.Error{Op: "GET", Err: fmt.Errorf("x509: “ServerName” certificate is not trusted")}

url.Error.Err has a type of errors.errorString instead of x509.UnknownAuthorityError.

TestPlatformVerifier in crypto/x509/root_darwin_test.go is the only place I can find this error message, so I guess it must come from Certificate.systemVerify in root_darwin.go.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions