159 lines
3.5 KiB
Go
159 lines
3.5 KiB
Go
package inspect
|
|
|
|
import (
|
|
"crypto/tls"
|
|
"fmt"
|
|
)
|
|
|
|
// 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
|
|
}
|
|
|
|
// PrivateKeyInfo returns structured information about the given RSA private key.
|
|
/*
|
|
func PrivateKeyInfo(loc string, key *rsa.PrivateKey) *PrivateKey {
|
|
pl := make([]int, len(key.Primes))
|
|
for i, n := range key.Primes {
|
|
pl[i] = n.BitLen()
|
|
}
|
|
|
|
return &PrivateKey{
|
|
Loc: loc,
|
|
Primes: len(key.Primes),
|
|
PrimeLens: pl,
|
|
Public: PublicKeyInfo(loc, &key.PublicKey),
|
|
}
|
|
}
|
|
*/
|
|
|
|
// 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 "???"
|
|
}
|
|
|
|
// 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 private key.
|
|
func (tcs *TLSConnectionState) Type() Type {
|
|
return TypeTLSConnectionState
|
|
}
|
|
|
|
// Location returns the location data stored by PrivateKeyInfo.
|
|
func (tcs *TLSConnectionState) Location() string {
|
|
return "TLS handshake"
|
|
}
|
|
|
|
// Info returns structured information about the prvate key.
|
|
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,
|
|
},
|
|
},
|
|
},
|
|
}
|
|
}
|