1
1
Fork 0
mirror of https://git.sr.ht/~emersion/tlstunnel synced 2024-04-28 17:15:01 +02:00

Add support for certificate fingerprint pinning

This commit is contained in:
Simon Ser 2023-01-27 10:55:53 +01:00
parent ce4e23e5d8
commit 151e7cf586
2 changed files with 61 additions and 0 deletions

View File

@ -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
}

View File

@ -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.