github.com/Cloud-Foundations/Dominator@v0.3.4/lib/srpc/load.go (about) 1 package srpc 2 3 import ( 4 "crypto/tls" 5 "crypto/x509" 6 "fmt" 7 "os" 8 "path" 9 "sort" 10 "strings" 11 "time" 12 13 "github.com/Cloud-Foundations/Dominator/lib/format" 14 "github.com/Cloud-Foundations/Dominator/lib/x509util" 15 ) 16 17 func loadCertificates(directory string) ([]tls.Certificate, error) { 18 dir, err := os.Open(directory) 19 if err != nil { 20 return nil, err 21 } 22 names, err := dir.Readdirnames(0) 23 defer dir.Close() 24 if err != nil { 25 return nil, err 26 } 27 certs := make([]tls.Certificate, 0, len(names)/2) 28 now := time.Now() 29 for _, keyName := range names { 30 if !strings.HasSuffix(keyName, ".key") { 31 continue 32 } 33 certName := keyName[:len(keyName)-3] + "cert" 34 cert, err := tls.LoadX509KeyPair( 35 path.Join(directory, certName), 36 path.Join(directory, keyName)) 37 if err != nil { 38 return nil, fmt.Errorf("unable to load keypair: %s", err) 39 } 40 x509Cert, err := x509.ParseCertificate(cert.Certificate[0]) 41 if err != nil { 42 return nil, err 43 } 44 if notYet := x509Cert.NotBefore.Sub(now); notYet > 0 { 45 return nil, fmt.Errorf("%s will not be valid for %s", 46 certName, format.Duration(notYet)) 47 } 48 if expired := now.Sub(x509Cert.NotAfter); expired > 0 { 49 return nil, fmt.Errorf("%s expired %s ago", 50 certName, format.Duration(expired)) 51 } 52 cert.Leaf = x509Cert 53 certs = append(certs, cert) 54 } 55 if len(certs) < 1 { 56 return nil, nil 57 } 58 // The first entries are tried first when doing the TLS handshake, so sort 59 // the list of certificates to prefer "better" ones. 60 // First pass: sort list so that certificates with the longest remaining 61 // lifetime are listed first. 62 sort.Slice(certs, func(leftIndex, rightIndex int) bool { 63 return certs[leftIndex].Leaf.NotAfter.After( 64 certs[rightIndex].Leaf.NotAfter) 65 }) 66 // Second pass: sort list so that certificates with the most permitted 67 // methods are listed first. 68 sort.SliceStable(certs, func(leftIndex, rightIndex int) bool { 69 leftMethods, _ := x509util.GetPermittedMethods(certs[leftIndex].Leaf) 70 rightMethods, _ := x509util.GetPermittedMethods(certs[rightIndex].Leaf) 71 if _, leftIsAdmin := leftMethods["*.*"]; leftIsAdmin { 72 if _, rightIsAdmin := rightMethods["*.*"]; !rightIsAdmin { 73 return true 74 } 75 } 76 return len(leftMethods) > len(rightMethods) 77 }) 78 return certs, nil 79 }