1
0
mirror of https://github.com/golang/go synced 2024-11-17 12:44:49 -07:00

crypto/tls: add ExampleConfig_VerifyPeerCertificate

Setting InsecureSkipVerify and VerifyPeerCertificate is the recommended
way to customize and override certificate validation.

However, there is boilerplate involved and it usually requires first
reimplementing the default validation strategy to then customize it.
Provide an example that does the same thing as the default as a starting
point.

Examples of where we directed users to do something similar are in
issues #35467, #31791, #28754, #21971, and #24151.

Fixes #31792

Change-Id: Id033e9fa3cac9dff1f7be05c72dfb34b4f973fd4
Reviewed-on: https://go-review.googlesource.com/c/go/+/193620
Reviewed-by: Adam Langley <agl@golang.org>
This commit is contained in:
Filippo Valsorda 2019-09-05 14:23:08 -04:00
parent 7148478f1b
commit 29cfb4d3c3

View File

@ -7,6 +7,7 @@ package tls_test
import (
"crypto/tls"
"crypto/x509"
"errors"
"log"
"net/http"
"net/http/httptest"
@ -183,3 +184,55 @@ EKTcWGekdmdDPsHloRNtsiCa697B2O9IFA==
}
log.Fatal(srv.ListenAndServeTLS("", ""))
}
func ExampleConfig_verifyPeerCertificate() {
// VerifyPeerCertificate can be used to replace and customize certificate
// verification. This example shows a VerifyPeerCertificate implementation
// that will be approximately equivalent to what crypto/tls does normally.
config := &tls.Config{
// Set InsecureSkipVerify to skip the default validation we are
// replacing. This will not disable VerifyPeerCertificate.
InsecureSkipVerify: true,
// While packages like net/http will implicitly set ServerName, the
// VerifyPeerCertificate callback can't access that value, so it has to be set
// explicitly here or in VerifyPeerCertificate on the client side. If in
// an http.Transport DialTLS callback, this can be obtained by passing
// the addr argument to net.SplitHostPort.
ServerName: "example.com",
// On the server side, set ClientAuth to require client certificates (or
// VerifyPeerCertificate will run anyway and panic accessing certs[0])
// but not verify them with the default verifier.
// ClientAuth: tls.RequireAnyClientCert,
}
config.VerifyPeerCertificate = func(certificates [][]byte, _ [][]*x509.Certificate) error {
certs := make([]*x509.Certificate, len(certificates))
for i, asn1Data := range certificates {
cert, err := x509.ParseCertificate(asn1Data)
if err != nil {
return errors.New("tls: failed to parse certificate from server: " + err.Error())
}
certs[i] = cert
}
opts := x509.VerifyOptions{
Roots: config.RootCAs, // On the server side, use config.ClientCAs.
DNSName: config.ServerName,
Intermediates: x509.NewCertPool(),
// On the server side, set KeyUsages to ExtKeyUsageClientAuth. The
// default value is appropriate for clients side verification.
// KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
}
for _, cert := range certs[1:] {
opts.Intermediates.AddCert(cert)
}
_, err := certs[0].Verify(opts)
return err
}
// Note that when InsecureSkipVerify and VerifyPeerCertificate are in use,
// ConnectionState.VerifiedChains will be nil.
}