In my company, if you've got four servers behind a load balancer, one ssl key on the load balancer for the URL doesn't work. You'd need to get ssl keys for each individual server even if they serve the same URL. The problem with that is how do you check each server since the key is generated to a URL who's dns resolves at the load balancer not the server it's self? I recent I wrote a program in go that allows a user to check ssl keys that doesn't depend on DNS, but user input, so a user calls the program: ./sslcheck -i 10.1.1.2 -d
. It connects to 10.1.1.2 over port 443, looks at the cert, if it matches the domain name specified by the user, it passes.
So that's the background of my program, but the problem I am having is when the ip address isn't reachable from the system the user ran the program from. If 10.1.1.2 is not reachable, the program will just sit there and wait. Any way I can introduce a 30 or 60 second timeout? The portion of the code looks like this:
package main
import (
"crypto/tls"
"flag"
"fmt"
"os"
"path/filepath"
)
var runAs = filepath.Base(os.Args[0])
// Usage is what is run if the right parameters are not met upon startup.
func Usage() {
// To embed the bot user and password comment the line above and uncomment the line below
fmt.Printf("Usage: %v -i <ip address> -p <port> -d <domain name>\n", runAs)
flag.PrintDefaults()
}
func main() {
var ipAddress, domainName, port string
// define flags passed at runtime, and assign them to the variables defined above
flag.StringVar(&ipAddress, "i", "", "IP Address")
flag.StringVar(&domainName, "d", "", "Domain Name")
flag.StringVar(&port, "p", "443", "Port Number")
flag.Parse()
if domainName == "" {
Usage()
os.Exit(1)
}
// If no ipAddress was specified, set ipAddress to domainName
if ipAddress == "" {
ipAddress = domainName
}
// Run tls.Config so we can check the domainName against the
// ssl certificate
config := tls.Config{ServerName: domainName}
// Get the ssl cert from the server, if it errors then the cert is
// invalid
conn, err := tls.Dial("tcp", ipAddress+":"+port, &config)
if err != nil {
fmt.Printf("Cert Failed: \n\t%s\n", err)
os.Exit(1)
}
// when the program ends, close the connection. In Go you don't have to
// worry about the appropriate time to close the connections, Go figures
// that out for you with the defer command.
defer conn.Close()
fmt.Printf("Client connected to: %v\n", conn.RemoteAddr())
// If we made it this far, cert is ok
state := conn.ConnectionState()
fmt.Printf("Cert Checks OK\n")
i := 0
// this parses all the keys ssl, root, intermediate. We only need to see the SSL
for _, v := range state.PeerCertificates {
if i == 0 {
sslFrom := v.NotBefore
sslTo := v.NotAfter
fmt.Println("Server key information:")
fmt.Printf("\tCN:\t%v\n\tOU:\t%v\n\tOrg:\t%v\n", v.Subject.CommonName, v.Subject.OrganizationalUnit, v.Subject.Organization)
fmt.Printf("\tCity:\t%v\n\tState:\t%v\n\tCountry:%v\n", v.Subject.Locality, v.Subject.Province, v.Subject.Country)
fmt.Printf("SSL Certificate Valid:\n\tFrom:%v\n\tTo: %v\n", sslFrom, sslTo)
fmt.Printf("Valid Certificate DNS:\n")
if len(v.DNSNames) >= 1 {
for dns := range v.DNSNames {
fmt.Printf("\t%v\n", v.DNSNames[dns])
}
} else {
fmt.Printf("\t%v\n", v.Subject.CommonName)
}
i++
} else if i == 1 {
fmt.Printf("Issued by:\n\t%v\n\t%v\n\t%v\n", v.Subject.CommonName, v.Subject.OrganizationalUnit, v.Subject.Organization)
i++
} else {
break
}
}
}