Skip to content

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

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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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