rsa/pkg/inspect/tls.go

153 lines
3.4 KiB
Go

package inspect
import (
"crypto/tls"
"fmt"
"strconv"
)
// ConnectionState returns a set of information about a TLS ConnectionState.
func ConnectionState(c tls.ConnectionState) []Info {
var info = []Info{
&TLSConnectionState{
Version: c.Version,
CipherSuite: c.CipherSuite,
},
}
for i, cert := range c.PeerCertificates {
loc := "leaf certificate"
if i > 0 {
loc = fmt.Sprintf("intermediate certificate #%d", i)
}
info = append(info, CertificateInfo(loc, cert))
}
return info
}
// TLSSecurity provides an indicative security assessment of a negotiated TLS
// connection.
type TLSSecurity int
const (
TLSSecurityStrong = iota
TLSSecurityWeak
TLSSecurityInsecure
)
func (ts TLSSecurity) String() string {
switch ts {
case TLSSecurityStrong:
return "strong"
case TLSSecurityWeak:
return "weak"
case TLSSecurityInsecure:
return "insecure"
}
return "???"
}
// MarshalJSON returns a quoted string.
func (ts TLSSecurity) MarshalJSON() ([]byte, error) {
return strconv.AppendQuote(nil, ts.String()), nil
}
// MarshalYAML returns a string.
func (ts TLSSecurity) MarshalYAML() (any, error) {
return ts.String(), nil
}
// TLSConnectionState holds structured information about a negotiated TLS
// connection. It does not include the peer's certificate information.
type TLSConnectionState struct {
// Version of TLS protocol used.
Version uint16
// CipherSuite negotiated.
CipherSuite uint16
}
// Type indicates this is a TLS connection type.
func (tcs *TLSConnectionState) Type() Type {
return TypeTLSConnectionState
}
// Location returns the location data stored by TLSConnectionState.
func (tcs *TLSConnectionState) Location() string {
return "TLS handshake"
}
// Info returns structured information about the TLS connection.
func (tcs *TLSConnectionState) Info() []Section {
var security TLSSecurity = TLSSecurityStrong
ciphersuite := tls.CipherSuiteName(tcs.CipherSuite)
switch tcs.CipherSuite {
case tls.TLS_RSA_WITH_RC4_128_SHA,
tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA,
tls.TLS_RSA_WITH_AES_128_CBC_SHA,
tls.TLS_RSA_WITH_AES_256_CBC_SHA,
tls.TLS_RSA_WITH_AES_128_CBC_SHA256,
tls.TLS_RSA_WITH_AES_128_GCM_SHA256,
tls.TLS_RSA_WITH_AES_256_GCM_SHA384:
// using plain RSA for key exchange isn't good
security = TLSSecurityInsecure
case tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA,
tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA:
// broken/bad symmetric ciphers
security = TLSSecurityInsecure
case tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256:
// CBC now considered weaker
security = TLSSecurityWeak
default:
// allow Go's opinion to augment our own
for _, bad := range tls.InsecureCipherSuites() {
if tcs.CipherSuite == bad.ID {
security = TLSSecurityInsecure
break
}
}
}
var version string
switch tcs.Version {
case tls.VersionTLS10:
version = "TLSv1.0"
security = TLSSecurityInsecure
case tls.VersionTLS11:
version = "TLSv1.1"
security = TLSSecurityInsecure
case tls.VersionTLS12:
version = "TLSv1.2"
case tls.VersionTLS13:
version = "TLSv1.3"
}
return []Section{
Section{
Title: "TLS protocol negotatiated",
Fields: []Field{
Field{
Key: "Version",
Value: version,
},
Field{
Key: "Cipher suite",
Value: ciphersuite,
},
Field{
Key: "Security",
Value: security,
},
},
},
}
}