Skip to content

crypto/tls: add VerifyPeerCertificate to tls.Config #16363

Closed
@jboelter

Description

@jboelter

It would be useful to have a callback in tls.Config called after the TLS handshake to allow the callee to perform additional or alternate certificate verification on the peer. This would enable custom cert checking and/or explicit certificate pinning/whitelisting (e.g. by cert hash).

I propose calling VerifyPeerCertificate (if !nil) during the respective client and server handshakes (doFullHandshake and processPeerCertsFromClient) after the peer certificates have been received.

The func is introduced to tls.Config

    // VerifyPeerCertificate returns an error if the peer should not be
    // trusted. It will be called after the initial handshake and before
    // any other verification checks on the cert or chain are performed.
    // This provides the callee an opportunity to augment the certificate
    // verification.
    //
    // If VerifyPeerCertificate is not nil and returns an error,
    // then the handshake will fail.
    VerifyPeerCertificate func(peer []*x509.Certificate) error

This works with both http and http2. It appears that tls.Config is cloned from the initial transport for TLSNextProto -- is this intentional or an artifact of the current impl?

    c := &http.Client{
        Transport: &http.Transport{
            Proxy: http.ProxyFromEnvironment,
            Dial: (&net.Dialer{
                Timeout:   60 * time.Second,
                KeepAlive: 60 * time.Second,
            }).Dial,
            TLSHandshakeTimeout:   10 * time.Second,
            ExpectContinueTimeout: 1 * time.Second,
            TLSClientConfig: &tls.Config{
                // inject our callback to check the peer here
                NextProtos:            []string{"h2"},
                VerifyPeerCertificate: verifyPeerCertificate,
            },
            TLSNextProto: map[string]func(authority string, c *tls.Conn) http.RoundTripper{
                "h2": func(authority string, c *tls.Conn) http.RoundTripper {
                    return http.DefaultTransport
                },
            },
        },
    }

I have a changset ready if this is a reasonable approach.

Fixes #9126
Fixes #9451

Metadata

Metadata

Assignees

No one assigned

    Labels

    FrozenDueToAgeNeedsFixThe path to resolution is known, but the work has not been done.

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions