Permalink
Cannot retrieve contributors at this time
Name already in use
A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
howsmyssl/client_info.go
Go to fileThis commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
159 lines (145 sloc)
5.07 KB
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"fmt" | |
"strings" | |
tls "github.com/jmhodges/howsmyssl/tls110" | |
) | |
type rating string | |
const ( | |
okay rating = "Probably Okay" | |
improvable rating = "Improvable" | |
bad rating = "Bad" | |
) | |
type clientInfo struct { | |
GivenCipherSuites []string `json:"given_cipher_suites"` | |
EphemeralKeysSupported bool `json:"ephemeral_keys_supported"` // good if true | |
SessionTicketsSupported bool `json:"session_ticket_supported"` // good if true | |
TLSCompressionSupported bool `json:"tls_compression_supported"` // bad if true | |
UnknownCipherSuiteSupported bool `json:"unknown_cipher_suite_supported"` // bad if true | |
BEASTVuln bool `json:"beast_vuln"` // bad if true | |
AbleToDetectNMinusOneSplitting bool `json:"able_to_detect_n_minus_one_splitting"` // neutral | |
InsecureCipherSuites map[string][]string `json:"insecure_cipher_suites"` | |
TLSVersion string `json:"tls_version"` | |
Rating rating `json:"rating"` | |
} | |
const ( | |
versionTLS13 uint16 = 0x0304 | |
versionTLS13Draft18 = 0x7f00 | 18 | |
versionTLS13Draft21 = 0x7f00 | 21 | |
versionTLS13Draft22 = 0x7f00 | 22 | |
versionTLS13Draft23 = 0x7f00 | 23 | |
versionTLS13Draft24 = 0x7f00 | 24 | |
versionTLS13Draft25 = 0x7f00 | 25 | |
versionTLS13Draft26 = 0x7f00 | 26 | |
versionTLS13Draft27 = 0x7f00 | 27 | |
versionTLS13Draft28 = 0x7f00 | 28 | |
versionTLS13Draft29 = 0x7f00 | 29 | |
versionTLS13Draft30 = 0x7f00 | 30 | |
versionTLS13Draft31 = 0x7f00 | 31 | |
versionTLS13Draft32 = 0x7f00 | 32 | |
versionTLS13Draft33 = 0x7f00 | 33 | |
) | |
var actualSupportedVersions = map[uint16]string{ | |
tls.VersionSSL30: "SSL 3.0", | |
tls.VersionTLS10: "TLS 1.0", | |
tls.VersionTLS11: "TLS 1.1", | |
tls.VersionTLS12: "TLS 1.2", | |
versionTLS13: "TLS 1.3", // TODO(#119): use crypto/tls's constant when it has it | |
versionTLS13Draft18: "TLS 1.3", | |
versionTLS13Draft21: "TLS 1.3", | |
versionTLS13Draft22: "TLS 1.3", | |
versionTLS13Draft23: "TLS 1.3", | |
versionTLS13Draft24: "TLS 1.3", | |
versionTLS13Draft25: "TLS 1.3", | |
versionTLS13Draft26: "TLS 1.3", | |
versionTLS13Draft27: "TLS 1.3", | |
versionTLS13Draft28: "TLS 1.3", | |
versionTLS13Draft29: "TLS 1.3", | |
versionTLS13Draft30: "TLS 1.3", | |
versionTLS13Draft31: "TLS 1.3", | |
versionTLS13Draft32: "TLS 1.3", | |
versionTLS13Draft33: "TLS 1.3", | |
} | |
func pullClientInfo(c *conn) *clientInfo { | |
d := &clientInfo{InsecureCipherSuites: make(map[string][]string)} | |
st := c.ConnectionState() | |
if !st.HandshakeComplete { | |
panic("given a TLS conn that has not completed its handshake") | |
} | |
var sweet32Seen []string | |
for _, ci := range st.ClientCipherSuites { | |
s, found := allCipherSuites[ci] | |
if found { | |
if strings.Contains(s, "DHE_") { | |
d.EphemeralKeysSupported = true | |
} | |
if cbcSuites[ci] && st.Version <= tls.VersionTLS10 { | |
d.BEASTVuln = !st.NMinusOneRecordSplittingDetected | |
d.AbleToDetectNMinusOneSplitting = st.AbleToDetectNMinusOneSplitting | |
} | |
if fewBitCipherSuites[s] { | |
d.InsecureCipherSuites[s] = append(d.InsecureCipherSuites[s], fewBitReason) | |
} | |
if nullCipherSuites[s] { | |
d.InsecureCipherSuites[s] = append(d.InsecureCipherSuites[s], nullReason) | |
} | |
if nullAuthCipherSuites[s] { | |
d.InsecureCipherSuites[s] = append(d.InsecureCipherSuites[s], nullAuthReason) | |
} | |
if rc4CipherSuites[s] { | |
d.InsecureCipherSuites[s] = append(d.InsecureCipherSuites[s], rc4Reason) | |
} | |
if sweet32CipherSuites[s] { | |
sweet32Seen = append(sweet32Seen, s) | |
} else if len(sweet32Seen) != 0 && !metaCipherSuites[ci] && !tls13Suites[ci] { | |
for _, seen := range sweet32Seen { | |
d.InsecureCipherSuites[seen] = append(d.InsecureCipherSuites[seen], sweet32Reason) | |
} | |
sweet32Seen = []string{} | |
} | |
} else { | |
w, found := weirdNSSSuites[ci] | |
if !found { | |
d.UnknownCipherSuiteSupported = true | |
s = fmt.Sprintf("Some unknown cipher suite: %#04x", ci) | |
} else { | |
s = w | |
d.InsecureCipherSuites[s] = append(d.InsecureCipherSuites[s], weirdNSSReason) | |
} | |
} | |
d.GivenCipherSuites = append(d.GivenCipherSuites, s) | |
} | |
d.SessionTicketsSupported = st.SessionTicketsSupported | |
for _, cm := range st.CompressionMethods { | |
if cm != 0x0 { | |
d.TLSCompressionSupported = true | |
break | |
} | |
} | |
vers := st.Version | |
d.TLSVersion = actualSupportedVersions[vers] | |
// Check TLS 1.3's supported_versions extension for the actual TLS version | |
// if it was passed in. | |
for _, v := range st.SupportedVersions { | |
maybeStr, found := actualSupportedVersions[v] | |
if found && v > vers { | |
vers = v | |
d.TLSVersion = maybeStr | |
} | |
} | |
if d.TLSVersion == "" { | |
d.TLSVersion = "an unknown version of SSL/TLS" | |
} | |
d.Rating = okay | |
if !d.EphemeralKeysSupported || vers == tls.VersionTLS11 { | |
d.Rating = improvable | |
} | |
if d.TLSCompressionSupported || | |
d.UnknownCipherSuiteSupported || | |
d.BEASTVuln || | |
len(d.InsecureCipherSuites) != 0 || | |
vers <= tls.VersionTLS10 { | |
d.Rating = bad | |
} | |
return d | |
} |