TLS Dial -- no timeout?

3,724 views
Skip to first unread message

Rich

unread,
Jul 5, 2012, 10:05:44 AM7/5/12
to golan...@googlegroups.com
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 www.somedomain.com. 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
                }
        }
}

Andrew Gerrand

unread,
Jul 5, 2012, 1:17:06 PM7/5/12
to Rich, golan...@googlegroups.com
You need to use tls.Client instead of tls.Dial, and use
net.DialTimeout to make the connection manually:

http://golang.org/pkg/net/#DialTimeout

You'll want to crib the code from the tls.Dial function to do this:

http://golang.org/src/pkg/crypto/tls/tls.go?s=2501:2563#L74

Andrew

Rich

unread,
Jul 5, 2012, 6:05:05 PM7/5/12
to golan...@googlegroups.com, Rich
Andrew,

Thanks!!  Works perfect now, if anyone wants the code let me know.

Rich


On Thursday, July 5, 2012 1:17:06 PM UTC-4, Andrew Gerrand wrote:
You need to use tls.Client instead of tls.Dial, and use
net.DialTimeout to make the connection manually:

http://golang.org/pkg/net/#DialTimeout

You'll want to crib the code from the tls.Dial function to do this:

http://golang.org/src/pkg/crypto/tls/tls.go?s=2501:2563#L74

Andrew

Maxim Khitrov

unread,
Aug 3, 2012, 12:13:34 PM8/3/12
to bh...@llnw.com, golan...@googlegroups.com, Rich
Something along these lines should work:

conn, err := net.DialTimeout("tcp", addr, timeout)
if err == nil {
tlsConn := tls.Client(conn, config)
err = tlsConn.Handshake()
}

The handshake step is optional, but I like to make it explicit. It
will be performed automatically on first Read/Write.

- Max

On Fri, Aug 3, 2012 at 10:37 AM, <bh...@llnw.com> wrote:
> If you still have that code lurking I'd be quite interested.

Rich

unread,
Aug 4, 2012, 12:38:27 PM8/4/12
to golan...@googlegroups.com, Rich, bh...@llnw.com
I posted it here:

When run it looks something like this:
] $ ./sslcheck -d www.google.com
Client connected to: 74.125.137.99:443
Cert Checks OK
Server key information:
OU: []
Org: [Google Inc]
City: [Mountain View]
State: [California]
Country: [US]
SSL Certificate Valid:
From: 2011-10-26 00:00:00 +0000 UTC
To: 2013-09-30 23:59:59 +0000 UTC
Valid Certificate DNS:
Issued by:
Thawte SGC CA
[]
[Thawte Consulting (Pty) Ltd.]

On Friday, August 3, 2012 10:37:42 AM UTC-4, (unknown) wrote:
If you still have that code lurking I'd be quite interested.

On Thursday, July 5, 2012 3:05:05 PM UTC-7, Rich wrote:
On Thursday, July 5, 2012 3:05:05 PM UTC-7, Rich wrote:
Reply all
Reply to author
Forward
0 new messages