Add support for certificate fingerprint pinning
This commit is contained in:
parent
ce4e23e5d8
commit
151e7cf586
|
@ -1,7 +1,11 @@
|
|||
package tlstunnel
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"crypto/subtle"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/url"
|
||||
|
@ -130,6 +134,49 @@ func parseBackend(backend *Backend, d *scfg.Directive) error {
|
|||
return fmt.Errorf("failed to setup backend %q: unsupported URI scheme", backendURI)
|
||||
}
|
||||
|
||||
for _, child := range d.Children {
|
||||
switch child.Name {
|
||||
case "tls_certfp":
|
||||
if backend.TLSConfig == nil {
|
||||
return fmt.Errorf("tls_certfp requires a tls:// backend address")
|
||||
}
|
||||
|
||||
var algo, wantCertFP string
|
||||
if err := child.ParseParams(&algo, &wantCertFP); err != nil {
|
||||
return err
|
||||
}
|
||||
if algo != "sha-256" {
|
||||
return fmt.Errorf("directive tls_certfp: only sha-256 is supported")
|
||||
}
|
||||
|
||||
wantCertFP = strings.ReplaceAll(wantCertFP, ":", "")
|
||||
wantSum, err := hex.DecodeString(wantCertFP)
|
||||
if err != nil {
|
||||
return fmt.Errorf("directive tls_certfp: invalid fingerprint: %v", err)
|
||||
} else if len(wantSum) != sha256.Size {
|
||||
return fmt.Errorf("directive tls_certfp: invalid fingerprint length")
|
||||
}
|
||||
|
||||
backend.TLSConfig.InsecureSkipVerify = true
|
||||
backend.TLSConfig.VerifyPeerCertificate = func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
|
||||
if len(rawCerts) == 0 {
|
||||
return fmt.Errorf("the server didn't present any TLS certificate")
|
||||
}
|
||||
|
||||
for _, rawCert := range rawCerts {
|
||||
sum := sha256.Sum256(rawCert)
|
||||
if subtle.ConstantTimeCompare(sum[:], wantSum) == 1 {
|
||||
return nil // fingerprints match
|
||||
}
|
||||
}
|
||||
|
||||
sum := sha256.Sum256(rawCerts[0])
|
||||
remoteCertFP := hex.EncodeToString(sum[:])
|
||||
return fmt.Errorf("configured TLS certificate fingerprint doesn't match the server's - %s", remoteCertFP)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -64,6 +64,20 @@ The following directives are supported:
|
|||
The _+proxy_ suffix can be added to the URI scheme to forward
|
||||
connection metadata via the PROXY protocol.
|
||||
|
||||
The backend directive supports the following sub-directives:
|
||||
|
||||
*tls_certfp* sha-256 <fingerprint>
|
||||
Instead of using CAs to check the TLS certificate provided by the
|
||||
backend, check that the certificate matches the provided
|
||||
fingerprint. This can be used to connect to servers with a
|
||||
self-signed certificate, for instance.
|
||||
|
||||
The fingerprint of a certificate can be obtained via *openssl*(1):
|
||||
|
||||
```
|
||||
openssl x509 -fingerprint -sha256 -noout <certificate>
|
||||
```
|
||||
|
||||
*tls* { ... }
|
||||
Customise frontend-specific TLS configuration.
|
||||
|
||||
|
|
Loading…
Reference in New Issue