Golang certificate validation

I'm using Go to perform HTTPS requests with a custom root CA. The root CA is the only certificate I have on my side.

My code looks like this:

// performRequest sets up the HTTPS Client we'll use for communication and handle the actual requesting to the external
// end point. It is used by the auth and collect adapters who set their response data up first.
func performRequest(rawData []byte, soapHeader string) (*http.Response, error) {
  conf := config.GetConfig()

  // Set up the certificate handler and the HTTP client.
  certPool := x509.NewCertPool()
  certPool.AppendCertsFromPEM(certificate)
  client := &http.Client{
    Transport: &http.Transport{
      TLSClientConfig: &tls.Config{
        RootCAs:            certPool,
        InsecureSkipVerify: false,
      },
    },
  }

  req, err := http.NewRequest(http.MethodPost, baseURL, bytes.NewBuffer(rawData))
  if err != nil {
    return nil, err
  }

  // Sets the SOAPAction and Content-Type headers to the request.
  req.Header.Set("SOAPAction", soapHeader)
  req.Header.Set("Content-Type", "text/xml; charset=UTF-8")

  // Send request as our custom client, return response
  return client.Do(req)
}

The error I get back is this:

2017/12/09 21:06:13 Post https://secure.site: x509: certificate is not valid for any names, but wanted to match secure.site

I've been unable to find out exactly what the cause is of this. When checking the SANs of the CA cert, I don't have secure.site in there (no names at all, as the error states), but I can't see how I've done this wrong.

What should I do to troubleshoot this?

Upvotes: 1

Views: 13704

Answers (1)

Marc
Marc

Reputation: 21055

You need to do two things:

  1. add the CA certificate on the server side as well, the CA needs to be known by all parties.
  2. generate and use a server certificate (with the hostname in the certificate) on the server. The server cert needs to be signed by the CA.

You can find an example of this at here (first google example)

Edit: to clarify, the error is due to the fact that you are trying to connect securely to a remote host. By default, the go client will look for a valid certificate returned by the server.

Valid means (among other things):

  1. it is signed by a known CA
  2. it contains the ip/dns of the server (the one you passed to http.NewRequest) in the CommonName or Subject Alternative Name: DNS/IP fields.

final edit:

The server certificate contained the correct Common Name set to the server hostname, but it also contained a Subject Alternative Name set to an email address.

As mentioned in https://groups.google.com/a/chromium.org/forum/#!topic/security-dev/IGT2fLJrAeo, Go now ignores the Common Name if is a SAN is found.

Upvotes: 5

Related Questions