cert+test: IsOutdated check for TLS files if IPs or DNS changed
This commit creates a new utility method IsOutdated that can be used to check whether a TLS certificate mathces the extra IPs and domains given in the lnd config.
This commit is contained in:
parent
d316107749
commit
83dcf95f92
@ -100,6 +100,83 @@ func dnsNames(tlsExtraDomains []string) (string, []string) {
|
||||
return host, dnsNames
|
||||
}
|
||||
|
||||
// IsOutdated returns whether the given certificate is outdated w.r.t. the IPs
|
||||
// and domains given. The certificate is considered up to date if it was
|
||||
// created with _exactly_ the IPs and domains given.
|
||||
func IsOutdated(cert *x509.Certificate, tlsExtraIPs,
|
||||
tlsExtraDomains []string) (bool, error) {
|
||||
|
||||
// Parse the slice of IP strings.
|
||||
ips, err := ipAddresses(tlsExtraIPs)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
// To not consider the certificate outdated if it has duplicate IPs or
|
||||
// if only the order has changed, we create two maps from the slice of
|
||||
// IPs to compare.
|
||||
ips1 := make(map[string]net.IP)
|
||||
for _, ip := range ips {
|
||||
ips1[ip.String()] = ip
|
||||
}
|
||||
|
||||
ips2 := make(map[string]net.IP)
|
||||
for _, ip := range cert.IPAddresses {
|
||||
ips2[ip.String()] = ip
|
||||
}
|
||||
|
||||
// If the certificate has a different number of IP addresses, it is
|
||||
// definitely out of date.
|
||||
if len(ips1) != len(ips2) {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// Go through each IP address, and check that they are equal. We expect
|
||||
// both the string representation and the exact IP to match.
|
||||
for s, ip1 := range ips1 {
|
||||
// Assert the IP string is found in both sets.
|
||||
ip2, ok := ips2[s]
|
||||
if !ok {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// And that the IPs are considered equal.
|
||||
if !ip1.Equal(ip2) {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
|
||||
// Get the full list of DNS names to use.
|
||||
_, dnsNames := dnsNames(tlsExtraDomains)
|
||||
|
||||
// We do the same kind of deduplication for the DNS names.
|
||||
dns1 := make(map[string]struct{})
|
||||
for _, n := range cert.DNSNames {
|
||||
dns1[n] = struct{}{}
|
||||
}
|
||||
|
||||
dns2 := make(map[string]struct{})
|
||||
for _, n := range dnsNames {
|
||||
dns2[n] = struct{}{}
|
||||
}
|
||||
|
||||
// If the number of domains are different, it is out of date.
|
||||
if len(dns1) != len(dns2) {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// Similarly, check that each DNS name matches what is found in the
|
||||
// certificate.
|
||||
for k := range dns1 {
|
||||
if _, ok := dns2[k]; !ok {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
|
||||
// Certificate was up-to-date.
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// GenCertPair generates a key/cert pair to the paths provided. The
|
||||
// auto-generated certificates should *not* be used in production for public
|
||||
// access as they're self-signed and don't necessarily contain all of the
|
||||
|
135
cert/selfsigned_test.go
Normal file
135
cert/selfsigned_test.go
Normal file
@ -0,0 +1,135 @@
|
||||
package cert_test
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"testing"
|
||||
|
||||
"github.com/lightningnetwork/lnd/cert"
|
||||
)
|
||||
|
||||
var (
|
||||
extraIPs = []string{"1.1.1.1", "123.123.123.1", "199.189.12.12"}
|
||||
extraDomains = []string{"home", "and", "away"}
|
||||
)
|
||||
|
||||
// TestIsOutdatedCert checks that we'll consider the TLS certificate outdated
|
||||
// if the ip addresses or dns names don't match.
|
||||
func TestIsOutdatedCert(t *testing.T) {
|
||||
tempDir, err := ioutil.TempDir("", "certtest")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
certPath := tempDir + "/tls.cert"
|
||||
keyPath := tempDir + "/tls.key"
|
||||
|
||||
// Generate TLS files with two extra IPs and domains.
|
||||
err = cert.GenCertPair(
|
||||
"lnd autogenerated cert", certPath, keyPath, extraIPs[:2],
|
||||
extraDomains[:2], cert.DefaultAutogenValidity,
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// We'll attempt to check up-to-date status for all variants of 1-3
|
||||
// number of IPs and domains.
|
||||
for numIPs := 1; numIPs <= len(extraIPs); numIPs++ {
|
||||
for numDomains := 1; numDomains <= len(extraDomains); numDomains++ {
|
||||
_, parsedCert, err := cert.LoadCert(
|
||||
certPath, keyPath,
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Using the test case's number of IPs and domains, get
|
||||
// the outdated status of the certificate we created
|
||||
// above.
|
||||
outdated, err := cert.IsOutdated(
|
||||
parsedCert, extraIPs[:numIPs],
|
||||
extraDomains[:numDomains],
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// We expect it to be considered outdated if the IPs or
|
||||
// domains don't match exactly what we created.
|
||||
expected := numIPs != 2 || numDomains != 2
|
||||
if outdated != expected {
|
||||
t.Fatalf("expected certificate to be "+
|
||||
"outdated=%v, got=%v", expected,
|
||||
outdated)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestIsOutdatedPermutation tests that the order of listed IPs or DNS names,
|
||||
// nor dulicates in the lists, matter for whether we consider the certificate
|
||||
// outdated.
|
||||
func TestIsOutdatedPermutation(t *testing.T) {
|
||||
tempDir, err := ioutil.TempDir("", "certtest")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
certPath := tempDir + "/tls.cert"
|
||||
keyPath := tempDir + "/tls.key"
|
||||
|
||||
// Generate TLS files from the IPs and domains.
|
||||
err = cert.GenCertPair(
|
||||
"lnd autogenerated cert", certPath, keyPath, extraIPs[:],
|
||||
extraDomains[:], cert.DefaultAutogenValidity,
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
_, parsedCert, err := cert.LoadCert(certPath, keyPath)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// If we have duplicate IPs or DNS names listed, that shouldn't matter.
|
||||
dupIPs := make([]string, len(extraIPs)*2)
|
||||
for i := range dupIPs {
|
||||
dupIPs[i] = extraIPs[i/2]
|
||||
}
|
||||
|
||||
dupDNS := make([]string, len(extraDomains)*2)
|
||||
for i := range dupDNS {
|
||||
dupDNS[i] = extraDomains[i/2]
|
||||
}
|
||||
|
||||
outdated, err := cert.IsOutdated(parsedCert, dupIPs, dupDNS)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if outdated {
|
||||
t.Fatalf("did not expect duplicate IPs or DNS names be " +
|
||||
"considered outdated")
|
||||
}
|
||||
|
||||
// Similarly, the order of the lists shouldn't matter.
|
||||
revIPs := make([]string, len(extraIPs))
|
||||
for i := range revIPs {
|
||||
revIPs[i] = extraIPs[len(extraIPs)-1-i]
|
||||
}
|
||||
|
||||
revDNS := make([]string, len(extraDomains))
|
||||
for i := range revDNS {
|
||||
revDNS[i] = extraDomains[len(extraDomains)-1-i]
|
||||
}
|
||||
|
||||
outdated, err = cert.IsOutdated(parsedCert, revIPs, revDNS)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if outdated {
|
||||
t.Fatalf("did not expect reversed IPs or DNS names be " +
|
||||
"considered outdated")
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user