This repository has been archived by the owner on Mar 29, 2021. It is now read-only.
forked from jmhodges/howsmyssl
-
Notifications
You must be signed in to change notification settings - Fork 0
/
client_info.go
119 lines (108 loc) · 3.7 KB
/
client_info.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
package main
import (
"fmt"
"strings"
tls "github.com/jmhodges/howsmyssl/tls18"
)
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"`
}
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)
}
} 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)
}
}
if sweet32CipherSuites[s] {
sweet32Seen = append(sweet32Seen, s)
} else if len(sweet32Seen) != 0 {
for _, seen := range sweet32Seen {
d.InsecureCipherSuites[seen] = append(d.InsecureCipherSuites[seen], sweet32Reason)
}
sweet32Seen = []string{}
}
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
switch vers {
case tls.VersionSSL30:
d.TLSVersion = "SSL 3.0"
case tls.VersionTLS10:
d.TLSVersion = "TLS 1.0"
case tls.VersionTLS11:
d.TLSVersion = "TLS 1.1"
case tls.VersionTLS12:
d.TLSVersion = "TLS 1.2"
case 0x0304: // TODO(#119): use crypto/tls's constant when it has it
d.TLSVersion = "TLS 1.3"
default:
d.TLSVersion = "an unknown version of SSL/TLS"
}
d.Rating = okay
if !d.EphemeralKeysSupported || !d.SessionTicketsSupported || 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
}