Hello. Is there some way to configure Server TLS so that when it is verifying a client certificate it can call out to my own function when the client certificate is not found in the server’s tls.Config ClientCAs x509.CertPool?
Sorry, I don’t follow how that helps? I want to be able to have the server side use a function to validate the client certificate - I don’t see how to get hold of the client certifcate from *tls.ClientHelloInfo?
(the client hasn’t even sent its client certificate at the point where processCert gets called has it?)
If you implement the VerifyPeerCertificate method in tlsConf, that would only receive the certificate data when there is actually a client certificate sent, but not for any other.
On the other hand, processCert is called every time a new TLS handshake request has been received, thus making you able to block invalid requests at the very first level of the TLS handshake process.
But anyway if you need the first one, here’s an example of this:
package main
import (
"crypto/tls"
"crypto/x509"
"errors"
"log"
"net/http"
"time"
)
var tlsConf = &tls.Config{VerifyPeerCertificate: validateCert}
func main() {
srv := &http.Server{TLSConfig: tlsConf}
cert, err := tls.LoadX509KeyPair("cert", "privkey") // In case of multiple certificate imports
if err != nil {
log.Panic(err.Error())
}
tlsConf.Certificates = append(tlsConf.Certificates, cert)
err = srv.ListenAndServeTLS("", "") // Can specify certs here directly, too
if err != nil {
log.Fatal(err)
}
}
func validateCert(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
if verifiedChains == nil {
return errors.New("client didn't send any certificates")
}
for _, chain := range verifiedChains {
for _, cert := range chain {
// implement any sort of validations on the cert
if time.Now().After(cert.NotAfter) { // an example certificate expiration check
return errors.New("certificate expired")
}
}
}
return nil
}
By setting ClientAuth to tls.RequireAnyClientCert, you’re actually giving the hint to any(malicious) client that you require a client certificate, which may not be desirable depending on your application’s security requirements.
But doing it through GetCertificate method, you can silently check whether the certificate is the one you expected.