From 75258cfd3c8a9dadea6cc95dcb6717e3426853af Mon Sep 17 00:00:00 2001 From: Seth Theriault Date: Tue, 21 May 2019 11:57:46 -0400 Subject: [PATCH 1/3] Add support for IMAP STARTTLS --- starttls/imap.go | 67 ++++++++++++++++++++++++++++++++++++++++++++ starttls/starttls.go | 6 +++- 2 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 starttls/imap.go diff --git a/starttls/imap.go b/starttls/imap.go new file mode 100644 index 0000000..3136950 --- /dev/null +++ b/starttls/imap.go @@ -0,0 +1,67 @@ +/*- + * Copyright 2017 Square Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package starttls + +import ( + "bufio" + "crypto/tls" + "fmt" + "net" +) + +func dumpAuthTLSFromIMAP(dialer Dialer, address string, config *tls.Config) (*tls.ConnectionState, error) { + c, err := dialer.Dial("tcp", address) + if err != nil { + return nil, err + } + + conn := c.(*net.TCPConn) + status, err := readIMAP(conn) + if err != nil { + return nil, err + } + if status != "OK" { + return nil, fmt.Errorf("IMAP server responded with %s, was expecting OK", status) + } + + fmt.Fprintf(conn, "1 STARTTLS\r\n") + status, err = readIMAP(conn) + if err != nil { + return nil, err + } + if status != "OK" { + return nil, fmt.Errorf("IMAP server responded with %s, was expecting OK", status) + } + + tlsConn := tls.Client(conn, config) + err = tlsConn.Handshake() + if err != nil { + return nil, err + } + + state := tlsConn.ConnectionState() + return &state, nil +} + +func readIMAP(conn *net.TCPConn) (string, error) { + reader := bufio.NewReader(conn) + response, err := reader.ReadString('\n') + if err != nil { + return "", err + } + return response[2:4], nil +} diff --git a/starttls/starttls.go b/starttls/starttls.go index 9c935ac..df5c7b1 100644 --- a/starttls/starttls.go +++ b/starttls/starttls.go @@ -35,7 +35,7 @@ import ( ) // Protocols are the names of supported protocols -var Protocols []string = []string{"mysql", "postgres", "psql", "smtp", "ldap", "ftp"} +var Protocols []string = []string{"mysql", "postgres", "psql", "smtp", "ldap", "ftp", "imap"} type connectResult struct { state *tls.ConnectionState @@ -234,6 +234,10 @@ func GetConnectionState(startTLSType, connectName, connectTo, identity, clientCe addr := withDefaultPort(connectTo, 21) state, err = dumpAuthTLSFromFTP(dialer, addr, tlsConfig) res <- connectResult{state, err} + case "imap": + addr := withDefaultPort(connectTo, 143) + state, err = dumpAuthTLSFromIMAP(dialer, addr, tlsConfig) + res <- connectResult{state, err} default: res <- connectResult{nil, fmt.Errorf("unknown StartTLS protocol: %s", startTLSType)} } From 25850151d7e71175ad60045ca3d7a7c19db1b66f Mon Sep 17 00:00:00 2001 From: Cedric Staub Date: Tue, 21 May 2019 11:20:24 -0700 Subject: [PATCH 2/3] Rename dumpAuthTLSFromXXX methods --- starttls/ftp.go | 2 +- starttls/imap.go | 2 +- starttls/starttls.go | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/starttls/ftp.go b/starttls/ftp.go index 856730d..fb23acf 100644 --- a/starttls/ftp.go +++ b/starttls/ftp.go @@ -24,7 +24,7 @@ import ( "strconv" ) -func dumpAuthTLSFromFTP(dialer Dialer, address string, config *tls.Config) (*tls.ConnectionState, error) { +func dumpTLSConnStateFromFTP(dialer Dialer, address string, config *tls.Config) (*tls.ConnectionState, error) { c, err := dialer.Dial("tcp", address) if err != nil { return nil, err diff --git a/starttls/imap.go b/starttls/imap.go index 3136950..6f57cd9 100644 --- a/starttls/imap.go +++ b/starttls/imap.go @@ -23,7 +23,7 @@ import ( "net" ) -func dumpAuthTLSFromIMAP(dialer Dialer, address string, config *tls.Config) (*tls.ConnectionState, error) { +func dumpTLSConnStateFromIMAP(dialer Dialer, address string, config *tls.Config) (*tls.ConnectionState, error) { c, err := dialer.Dial("tcp", address) if err != nil { return nil, err diff --git a/starttls/starttls.go b/starttls/starttls.go index df5c7b1..0aa1067 100644 --- a/starttls/starttls.go +++ b/starttls/starttls.go @@ -29,9 +29,9 @@ import ( "github.com/square/certigo/starttls/ldap" "github.com/square/certigo/starttls/mysql" - "github.com/square/certigo/starttls/psql" + pq "github.com/square/certigo/starttls/psql" - "github.com/mwitkow/go-http-dialer" + http_dialer "github.com/mwitkow/go-http-dialer" ) // Protocols are the names of supported protocols @@ -232,11 +232,11 @@ func GetConnectionState(startTLSType, connectName, connectTo, identity, clientCe res <- connectResult{&state, nil} case "ftp": addr := withDefaultPort(connectTo, 21) - state, err = dumpAuthTLSFromFTP(dialer, addr, tlsConfig) + state, err = dumpTLSConnStateFromFTP(dialer, addr, tlsConfig) res <- connectResult{state, err} case "imap": addr := withDefaultPort(connectTo, 143) - state, err = dumpAuthTLSFromIMAP(dialer, addr, tlsConfig) + state, err = dumpTLSConnStateFromIMAP(dialer, addr, tlsConfig) res <- connectResult{state, err} default: res <- connectResult{nil, fmt.Errorf("unknown StartTLS protocol: %s", startTLSType)} From 8a79f547758738f45d4d125601d43f95228ce469 Mon Sep 17 00:00:00 2001 From: Cedric Staub Date: Tue, 21 May 2019 11:21:15 -0700 Subject: [PATCH 3/3] Mention STARTTLS IMAP support in README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1ab1ce3..266eafc 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ Certigo is a utility to examine and validate certificates to help with debugging **Validation and linting**: Not sure if your generated certificate is valid? Certigo can connect to remote servers to display and validate their certificate chains. It can also point out common errors on certififcates, such as using an older X.509 format, signatures with outdated hashes, or keys that are too small. -**Supports STARTTLS Protocols**: Trying to debug SSL/TLS connections on a database or mail server? Certigo supports establishing connections via StartTLS protocols for MySQL, PostgreSQL, SMTP, LDAP, and FTP, making it possible to debug connection issues or scan for expired certificates more easily. +**Supports STARTTLS Protocols**: Trying to debug SSL/TLS connections on a database or mail server? Certigo supports establishing connections via StartTLS protocols for MySQL, PostgreSQL, SMTP, LDAP, IMAP, and FTP, making it possible to debug connection issues or scan for expired certificates more easily. **Scripting support**: All commands in certigo have support for optional JSON output, which can be used in shell scripts to analyze or filter output. Combine certigo with [jq](https://stedolan.github.io/jq) to find all certificates in a bundle that are signed with SHA1-RSA, or filter for CA certificates, or whatever you need!