Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion http/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,9 @@ func roundTrip(req *Request) (*Response, error) {
if missingPort {
host = host + ":443"
}
conn, err = tls.Dial("tcp", host, nil)
// TINYGO: defaultTLSConfig is nil everywhere but darwin, where it
// TINYGO: carries the trust roots crypto/x509 cannot find for itself.
conn, err = tls.Dial("tcp", host, defaultTLSConfig())
}
if err != nil {
req.closeBody()
Expand Down
58 changes: 58 additions & 0 deletions http/tlsconfig_darwin.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
//go:build darwin

// TINYGO: darwin trust roots for the HTTPS client.

package http

import (
"crypto/tls"
"crypto/x509"
"os"
"sync"
)

// certFileEnv is the environment variable that crypto/x509 reads on unix for
// an alternative root bundle.
const certFileEnv = "SSL_CERT_FILE"

// darwinCertFile is the PEM bundle of macOS. crypto/x509 does not read it on
// darwin, because it uses the system verifier, so the client must read it.
const darwinCertFile = "/etc/ssl/cert.pem"

var darwinRoots struct {
once sync.Once
pool *x509.CertPool
}

// defaultTLSConfig returns the config that the client dials HTTPS with.
//
// On darwin crypto/x509 verifies a certificate with the platform verifier and
// not with a root pool, and crypto/x509/internal/macos in TinyGo is a stub, so
// a nil RootCAs makes every verification fail. A non-nil pool sends x509 to its
// pure Go path, which works. The roots come from $SSL_CERT_FILE, or from
// /etc/ssl/cert.pem.
//
// If no file can be read, the config has no RootCAs, so the result is an
// ordinary verification error and not a check that is silently skipped.
func defaultTLSConfig() *tls.Config {
darwinRoots.once.Do(loadDarwinRoots)
if darwinRoots.pool == nil {
return nil
}
return &tls.Config{RootCAs: darwinRoots.pool}
}

func loadDarwinRoots() {
path := os.Getenv(certFileEnv)
if path == "" {
path = darwinCertFile
}
pem, err := os.ReadFile(path)
if err != nil {
return
}
pool := x509.NewCertPool()
if pool.AppendCertsFromPEM(pem) {
darwinRoots.pool = pool
}
}
14 changes: 14 additions & 0 deletions http/tlsconfig_other.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
//go:build !darwin

// TINYGO: trust roots for the HTTPS client, everywhere but darwin.

package http

import "crypto/tls"

// defaultTLSConfig returns the config that the client dials HTTPS with. Off
// darwin crypto/x509 reads the system roots from the usual certificate files,
// so a nil config is correct.
func defaultTLSConfig() *tls.Config {
return nil
}