diff --git a/ssl-inspector.go b/ssl-inspector.go index ee49610..b2d791c 100644 --- a/ssl-inspector.go +++ b/ssl-inspector.go @@ -22,7 +22,6 @@ import ( "errors" "flag" "fmt" - "net/http" "net/url" "os" "runtime" @@ -55,7 +54,6 @@ func main() { } else { log.SetLevel(log.InfoLevel) } - // log.SetFormatter(&util.LogFormatter{Module: "SCANNER"}) flag.Usage = usage flag.Parse() @@ -69,6 +67,8 @@ func main() { if err != nil { println("Supplied endpoint is not well formed") os.Exit(1) + } else { + println("Validated - conducting test against: " + *validatedEndpoint) } // Load System Root CAs @@ -77,7 +77,7 @@ func main() { // rootCAs = x509.NewCertPool() // } - valid, messages, err := checkSSL(fmt.Sprintf("https://%s", *validatedEndpoint)) + valid, messages, err := checkSSL(*validatedEndpoint) if err != nil { println(fmt.Sprintf("Error performing checks: %v", err)) os.Exit(1) @@ -109,48 +109,37 @@ func checkSSL(endpoint string) (bool, []string, error) { // RootCAs: rootCAs, } - tr := &http.Transport{TLSClientConfig: config} - client := &http.Client{Transport: tr} + _, err := tls.Dial("tcp", endpoint, config) - req, err := http.NewRequest(http.MethodGet, endpoint, nil) if err != nil { - return false, messages, err - } + var certValidationError *tls.CertificateVerificationError + if errors.As(err, &certValidationError) { + //println("tls.CertificateVerificationError") + handled := false + if hostnameError, ok := certValidationError.Err.(x509.HostnameError); ok { + messages = append(messages, fmt.Sprintf("Certifcate for %s is not valid for %s", hostnameError.Certificate.Subject, endpoint)) + handled = true + } - _, err = client.Do(req) + if certInvalidError, ok := certValidationError.Err.(x509.CertificateInvalidError); ok { + messages = append(messages, fmt.Sprintf("Certifcate for %s is invalid because: %s", certInvalidError.Cert.Subject, getInvalidReason(int(certInvalidError.Reason)))) + handled = true + } - if err != nil { - var certValidationError *tls.CertificateVerificationError - var netUrlError *url.Error - if errors.As(err, &netUrlError) { - //println("url.Error") - if errors.As(netUrlError.Err, &certValidationError) { - //println("tls.CertificateVerificationError") - handled := false - if hostnameError, ok := certValidationError.Err.(x509.HostnameError); ok { - messages = append(messages, fmt.Sprintf("Certifcate for %s is not valid for %s", hostnameError.Certificate.Subject, endpoint)) - handled = true - } - - if certInvalidError, ok := certValidationError.Err.(x509.CertificateInvalidError); ok { - messages = append(messages, fmt.Sprintf("Certifcate for %s is invalid because: %s", certInvalidError.Cert.Subject, getInvalidReason(int(certInvalidError.Reason)))) - handled = true - } - - if unknownAuthorityError, ok := certValidationError.Err.(x509.UnknownAuthorityError); ok { - messages = append(messages, fmt.Sprintf(`Certifcate for %s is not trusted. This could be because: + if unknownAuthorityError, ok := certValidationError.Err.(x509.UnknownAuthorityError); ok { + messages = append(messages, fmt.Sprintf(`Certifcate for %s is not trusted. This could be because: 1. It is self-signed 2. It is signed by an unknown authority 3. The CA that signed this certificate is not a invalid Certificate Authority It was signed by: %s`, unknownAuthorityError.Cert.Subject, unknownAuthorityError.Cert.Issuer.CommonName)) - handled = true - } + handled = true + } - if !handled { - messages = append(messages, fmt.Sprintf("Certifcate for %s is invalid because: %s", endpoint, certValidationError.Error())) - } + if !handled { + messages = append(messages, fmt.Sprintf("Certifcate for %s is invalid because: %s", endpoint, certValidationError.Error())) } + // } } else { println("Failed making request") println(err.Error) diff --git a/ssl-inspector_test.go b/ssl-inspector_test.go index b5826c4..5f8dc56 100644 --- a/ssl-inspector_test.go +++ b/ssl-inspector_test.go @@ -25,42 +25,46 @@ import ( func TestCheckSSL(t *testing.T) { t.Run("validAndTrustedByOS", func(t *testing.T) { - valid, messages, err := checkSSL("https://badssl.com") + valid, messages, err := checkSSL("badssl.com:443") assert.NoError(t, err) assert.Equal(t, 0, len(messages)) assert.True(t, valid) }) t.Run("expiredAndTrustedByOS", func(t *testing.T) { - valid, messages, err := checkSSL("https://expired.badssl.com") + valid, messages, err := checkSSL("expired.badssl.com:443") assert.NoError(t, err) assert.Equal(t, 1, len(messages)) + assert.Equal(t, "Certifcate for CN=*.badssl.com,OU=Domain Control Validated+OU=PositiveSSL Wildcard is invalid because: Certificate expired", messages[0]) assert.False(t, valid) }) t.Run("expiredAndTrustedByOSWithPort", func(t *testing.T) { - valid, messages, err := checkSSL("https://expired.badssl.com:443") + valid, messages, err := checkSSL("expired.badssl.com:443") assert.NoError(t, err) assert.Equal(t, 1, len(messages)) + assert.Equal(t, "Certifcate for CN=*.badssl.com,OU=Domain Control Validated+OU=PositiveSSL Wildcard is invalid because: Certificate expired", messages[0]) assert.False(t, valid) }) t.Run("wrongHostAndTrustedByOS", func(t *testing.T) { - valid, messages, err := checkSSL("https://wrong.host.badssl.com") + valid, messages, err := checkSSL("wrong.host.badssl.com:443") assert.NoError(t, err) assert.Equal(t, 1, len(messages)) + assert.Equal(t, "Certifcate for CN=*.badssl.com is not valid for wrong.host.badssl.com:443", messages[0]) assert.False(t, valid) }) t.Run("unknownAuthorityAndTrustedByOS", func(t *testing.T) { - valid, messages, err := checkSSL("https://self-signed.badssl.com") + valid, messages, err := checkSSL("self-signed.badssl.com:443") assert.NoError(t, err) assert.Equal(t, 1, len(messages)) + assert.Equal(t, "Certifcate for CN=*.badssl.com,O=BadSSL,L=San Francisco,ST=California,C=US is not trusted. This could be because:\n\t1. It is self-signed\n\t2. It is signed by an unknown authority\n\t3. The CA that signed this certificate is not a invalid Certificate Authority\n\t\n\tIt was signed by: *.badssl.com", messages[0]) assert.False(t, valid) }) t.Run("untrustedRootAndTrustedByOS", func(t *testing.T) { - valid, messages, err := checkSSL("https://untrusted-root.badssl.com") + valid, messages, err := checkSSL("untrusted-root.badssl.com:443") assert.NoError(t, err) assert.Equal(t, 1, len(messages)) assert.False(t, valid) @@ -69,23 +73,24 @@ func TestCheckSSL(t *testing.T) { if runtime.GOOS == "darwin" { // Looks like Windows and Linux do not do realtime CRL checks t.Run("revokedAndTrustedByOS", func(t *testing.T) { - valid, messages, err := checkSSL("https://revoked.badssl.com") + valid, messages, err := checkSSL("revoked.badssl.com:443") assert.NoError(t, err) assert.Equal(t, 1, len(messages)) + assert.Equal(t, "Certifcate for revoked.badssl.com:443 is invalid because: tls: failed to verify certificate: x509: “revoked.badssl.com” certificate is revoked", messages[0]) assert.False(t, valid) }) } } -// func TestSingleCert(t *testing.T) { -// valid, messages, err := checkSSL("https://revoked.badssl.com") -// assert.NoError(t, err) -// assert.Equal(t, 1, len(messages)) -// for _, m := range messages { -// println(m) -// } -// assert.False(t, valid) -// } +func TestSingleCert(t *testing.T) { + valid, messages, err := checkSSL("expired.badssl.com:443") + assert.NoError(t, err) + assert.Equal(t, 1, len(messages)) + for _, m := range messages { + println(m) + } + assert.False(t, valid) +} func TestParseEndpoints(t *testing.T) { t.Run("httpsNoPortSpecified", func(t *testing.T) { @@ -111,4 +116,10 @@ func TestParseEndpoints(t *testing.T) { assert.NoError(t, err) assert.Equal(t, "badssl.com:555", *domain) }) + + t.Run("ldapsPortSpecified", func(t *testing.T) { + domain, err := validateEndpoint("ldaps://revoked.badssl.com:443") + assert.NoError(t, err) + assert.Equal(t, "revoked.badssl.com:443", *domain) + }) }