Vendor cfssl and cfssljson
This commit is contained in:
36
vendor/github.com/cloudflare/cfssl/scan/BUILD
generated
vendored
Normal file
36
vendor/github.com/cloudflare/cfssl/scan/BUILD
generated
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"broad.go",
|
||||
"connectivity.go",
|
||||
"pki.go",
|
||||
"scan_common.go",
|
||||
"tls_handshake.go",
|
||||
"tls_session.go",
|
||||
],
|
||||
importmap = "k8s.io/kubernetes/vendor/github.com/cloudflare/cfssl/scan",
|
||||
importpath = "github.com/cloudflare/cfssl/scan",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//vendor/github.com/cloudflare/cfssl/bundler:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/helpers:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/log:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/revoke:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
84
vendor/github.com/cloudflare/cfssl/scan/broad.go
generated
vendored
Normal file
84
vendor/github.com/cloudflare/cfssl/scan/broad.go
generated
vendored
Normal file
@@ -0,0 +1,84 @@
|
||||
package scan
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"net"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/cloudflare/cfssl/bundler"
|
||||
)
|
||||
|
||||
// Broad contains scanners for large swaths of TLS hosts on the internet.
|
||||
var Broad = &Family{
|
||||
Description: "Large scale scans of TLS hosts",
|
||||
Scanners: map[string]*Scanner{
|
||||
"IntermediateCAs": {
|
||||
"Scans a CIDR IP range for unknown Intermediate CAs",
|
||||
intermediateCAScan,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func incrementBytes(bytes []byte) {
|
||||
lsb := len(bytes) - 1
|
||||
bytes[lsb]++
|
||||
if bytes[lsb] == 0 {
|
||||
incrementBytes(bytes[:lsb])
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
caBundleFile = "/etc/cfssl/ca-bundle.crt"
|
||||
intBundleFile = "/etc/cfssl/int-bundle.crt"
|
||||
numWorkers = 32
|
||||
timeout = time.Second
|
||||
)
|
||||
|
||||
// intermediateCAScan scans for new intermediate CAs not in the trust store.
|
||||
func intermediateCAScan(addr, hostname string) (grade Grade, output Output, err error) {
|
||||
cidr, port, _ := net.SplitHostPort(addr)
|
||||
_, ipnet, err := net.ParseCIDR(cidr)
|
||||
if err != nil {
|
||||
return Skipped, nil, nil
|
||||
}
|
||||
b, err := bundler.NewBundler(caBundleFile, intBundleFile)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(numWorkers)
|
||||
dialer := &net.Dialer{Timeout: timeout}
|
||||
config := &tls.Config{InsecureSkipVerify: true}
|
||||
addrs := make(chan string)
|
||||
chains := make(chan []*x509.Certificate, numWorkers)
|
||||
go func() {
|
||||
for chain := range chains {
|
||||
b.Bundle(chain, nil, bundler.Force)
|
||||
}
|
||||
}()
|
||||
for i := 0; i < numWorkers; i++ {
|
||||
go func() {
|
||||
for addr := range addrs {
|
||||
conn, err := tls.DialWithDialer(dialer, Network, addr, config)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
conn.Close()
|
||||
if conn.ConnectionState().HandshakeComplete {
|
||||
chains <- conn.ConnectionState().PeerCertificates
|
||||
}
|
||||
}
|
||||
wg.Done()
|
||||
}()
|
||||
}
|
||||
for ip := ipnet.IP.To16(); ipnet.Contains(ip); incrementBytes(ip) {
|
||||
addrs <- net.JoinHostPort(ip.String(), port)
|
||||
}
|
||||
close(addrs)
|
||||
wg.Wait()
|
||||
close(chains)
|
||||
grade = Good
|
||||
return
|
||||
}
|
161
vendor/github.com/cloudflare/cfssl/scan/connectivity.go
generated
vendored
Normal file
161
vendor/github.com/cloudflare/cfssl/scan/connectivity.go
generated
vendored
Normal file
@@ -0,0 +1,161 @@
|
||||
package scan
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
)
|
||||
|
||||
// Connectivity contains scanners testing basic connectivity to the host
|
||||
var Connectivity = &Family{
|
||||
Description: "Scans for basic connectivity with the host through DNS and TCP/TLS dials",
|
||||
Scanners: map[string]*Scanner{
|
||||
"DNSLookup": {
|
||||
"Host can be resolved through DNS",
|
||||
dnsLookupScan,
|
||||
},
|
||||
"CloudFlareStatus": {
|
||||
"Host is on CloudFlare",
|
||||
onCloudFlareScan,
|
||||
},
|
||||
"TCPDial": {
|
||||
"Host accepts TCP connection",
|
||||
tcpDialScan,
|
||||
},
|
||||
"TLSDial": {
|
||||
"Host can perform TLS handshake",
|
||||
tlsDialScan,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// dnsLookupScan tests that DNS resolution of the host returns at least one address
|
||||
func dnsLookupScan(addr, hostname string) (grade Grade, output Output, err error) {
|
||||
addrs, err := net.LookupHost(hostname)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if len(addrs) == 0 {
|
||||
err = errors.New("no addresses found for host")
|
||||
}
|
||||
|
||||
grade, output = Good, addrs
|
||||
return
|
||||
}
|
||||
|
||||
var (
|
||||
cfNets []*net.IPNet
|
||||
cfNetsErr error
|
||||
)
|
||||
|
||||
func initOnCloudFlareScan() ([]*net.IPNet, error) {
|
||||
// Propogate previous errors and don't attempt to re-download.
|
||||
if cfNetsErr != nil {
|
||||
return nil, cfNetsErr
|
||||
}
|
||||
|
||||
// Don't re-download ranges if we already have them.
|
||||
if len(cfNets) > 0 {
|
||||
return cfNets, nil
|
||||
}
|
||||
|
||||
// Download CloudFlare CIDR ranges and parse them.
|
||||
v4resp, err := Client.Get("https://www.cloudflare.com/ips-v4")
|
||||
if err != nil {
|
||||
cfNetsErr = fmt.Errorf("Couldn't download CloudFlare IPs: %v", err)
|
||||
return nil, cfNetsErr
|
||||
}
|
||||
defer v4resp.Body.Close()
|
||||
|
||||
v6resp, err := Client.Get("https://www.cloudflare.com/ips-v6")
|
||||
if err != nil {
|
||||
cfNetsErr = fmt.Errorf("Couldn't download CloudFlare IPs: %v", err)
|
||||
return nil, cfNetsErr
|
||||
}
|
||||
defer v6resp.Body.Close()
|
||||
|
||||
scanner := bufio.NewScanner(io.MultiReader(v4resp.Body, v6resp.Body))
|
||||
for scanner.Scan() {
|
||||
_, ipnet, err := net.ParseCIDR(scanner.Text())
|
||||
if err != nil {
|
||||
cfNetsErr = fmt.Errorf("Couldn't parse CIDR range: %v", err)
|
||||
return nil, cfNetsErr
|
||||
}
|
||||
cfNets = append(cfNets, ipnet)
|
||||
}
|
||||
if err := scanner.Err(); err != nil {
|
||||
cfNetsErr = fmt.Errorf("Couldn't read IP bodies: %v", err)
|
||||
return nil, cfNetsErr
|
||||
}
|
||||
|
||||
return cfNets, nil
|
||||
}
|
||||
|
||||
func onCloudFlareScan(addr, hostname string) (grade Grade, output Output, err error) {
|
||||
var cloudflareNets []*net.IPNet
|
||||
if cloudflareNets, err = initOnCloudFlareScan(); err != nil {
|
||||
grade = Skipped
|
||||
return
|
||||
}
|
||||
|
||||
_, addrs, err := dnsLookupScan(addr, hostname)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
cfStatus := make(map[string]bool)
|
||||
grade = Good
|
||||
for _, addr := range addrs.([]string) {
|
||||
ip := net.ParseIP(addr)
|
||||
for _, cfNet := range cloudflareNets {
|
||||
if cfNet.Contains(ip) {
|
||||
cfStatus[addr] = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !cfStatus[addr] {
|
||||
cfStatus[addr] = false
|
||||
grade = Bad
|
||||
}
|
||||
}
|
||||
|
||||
output = cfStatus
|
||||
return
|
||||
}
|
||||
|
||||
// tcpDialScan tests that the host can be connected to through TCP.
|
||||
func tcpDialScan(addr, hostname string) (grade Grade, output Output, err error) {
|
||||
conn, err := Dialer.Dial(Network, addr)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
conn.Close()
|
||||
grade = Good
|
||||
return
|
||||
}
|
||||
|
||||
// tlsDialScan tests that the host can perform a TLS Handshake
|
||||
// and warns if the server's certificate can't be verified.
|
||||
func tlsDialScan(addr, hostname string) (grade Grade, output Output, err error) {
|
||||
var conn *tls.Conn
|
||||
config := defaultTLSConfig(hostname)
|
||||
|
||||
if conn, err = tls.DialWithDialer(Dialer, Network, addr, config); err != nil {
|
||||
return
|
||||
}
|
||||
conn.Close()
|
||||
|
||||
config.InsecureSkipVerify = false
|
||||
if conn, err = tls.DialWithDialer(Dialer, Network, addr, config); err != nil {
|
||||
grade = Warning
|
||||
return
|
||||
}
|
||||
conn.Close()
|
||||
|
||||
grade = Good
|
||||
return
|
||||
}
|
161
vendor/github.com/cloudflare/cfssl/scan/pki.go
generated
vendored
Normal file
161
vendor/github.com/cloudflare/cfssl/scan/pki.go
generated
vendored
Normal file
@@ -0,0 +1,161 @@
|
||||
package scan
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/cloudflare/cfssl/helpers"
|
||||
"github.com/cloudflare/cfssl/revoke"
|
||||
)
|
||||
|
||||
// PKI contains scanners for the Public Key Infrastructure.
|
||||
var PKI = &Family{
|
||||
Description: "Scans for the Public Key Infrastructure",
|
||||
Scanners: map[string]*Scanner{
|
||||
"ChainExpiration": {
|
||||
"Host's chain hasn't expired and won't expire in the next 30 days",
|
||||
chainExpiration,
|
||||
},
|
||||
"ChainValidation": {
|
||||
"All certificates in host's chain are valid",
|
||||
chainValidation,
|
||||
},
|
||||
"MultipleCerts": {
|
||||
"Host serves same certificate chain across all IPs",
|
||||
multipleCerts,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// getChain is a helper function that retreives the host's certificate chain.
|
||||
func getChain(addr string, config *tls.Config) (chain []*x509.Certificate, err error) {
|
||||
var conn *tls.Conn
|
||||
conn, err = tls.DialWithDialer(Dialer, Network, addr, config)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = conn.Close()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
chain = conn.ConnectionState().PeerCertificates
|
||||
if len(chain) == 0 {
|
||||
err = fmt.Errorf("%s returned empty certificate chain", addr)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
type expiration time.Time
|
||||
|
||||
func (e expiration) String() string {
|
||||
return time.Time(e).Format("Jan 2 15:04:05 2006 MST")
|
||||
}
|
||||
|
||||
func chainExpiration(addr, hostname string) (grade Grade, output Output, err error) {
|
||||
chain, err := getChain(addr, defaultTLSConfig(hostname))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
expirationTime := helpers.ExpiryTime(chain)
|
||||
output = expirationTime
|
||||
|
||||
if time.Now().After(expirationTime) {
|
||||
return
|
||||
}
|
||||
|
||||
// Warn if cert will expire in the next 30 days
|
||||
if time.Now().Add(time.Hour * 24 * 30).After(expirationTime) {
|
||||
grade = Warning
|
||||
return
|
||||
}
|
||||
|
||||
grade = Good
|
||||
return
|
||||
}
|
||||
|
||||
func chainValidation(addr, hostname string) (grade Grade, output Output, err error) {
|
||||
chain, err := getChain(addr, defaultTLSConfig(hostname))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
var warnings []string
|
||||
|
||||
for i := 0; i < len(chain)-1; i++ {
|
||||
cert, parent := chain[i], chain[i+1]
|
||||
|
||||
valid := helpers.ValidExpiry(cert)
|
||||
if !valid {
|
||||
warnings = append(warnings, fmt.Sprintf("Certificate for %s is valid for too long", cert.Subject.CommonName))
|
||||
}
|
||||
|
||||
revoked, ok := revoke.VerifyCertificate(cert)
|
||||
if !ok {
|
||||
warnings = append(warnings, fmt.Sprintf("couldn't check if %s is revoked", cert.Subject.CommonName))
|
||||
}
|
||||
if revoked {
|
||||
err = fmt.Errorf("%s is revoked", cert.Subject.CommonName)
|
||||
return
|
||||
}
|
||||
|
||||
if !parent.IsCA {
|
||||
err = fmt.Errorf("%s is not a CA", parent.Subject.CommonName)
|
||||
return
|
||||
}
|
||||
|
||||
if !bytes.Equal(cert.AuthorityKeyId, parent.SubjectKeyId) {
|
||||
err = fmt.Errorf("%s AuthorityKeyId differs from %s SubjectKeyId", cert.Subject.CommonName, parent.Subject.CommonName)
|
||||
return
|
||||
}
|
||||
|
||||
if err = cert.CheckSignatureFrom(parent); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
switch cert.SignatureAlgorithm {
|
||||
case x509.ECDSAWithSHA1:
|
||||
warnings = append(warnings, fmt.Sprintf("%s is signed by ECDSAWithSHA1", cert.Subject.CommonName))
|
||||
case x509.SHA1WithRSA:
|
||||
warnings = append(warnings, fmt.Sprintf("%s is signed by RSAWithSHA1", cert.Subject.CommonName))
|
||||
}
|
||||
}
|
||||
|
||||
if len(warnings) == 0 {
|
||||
grade = Good
|
||||
} else {
|
||||
grade = Warning
|
||||
output = warnings
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func multipleCerts(addr, hostname string) (grade Grade, output Output, err error) {
|
||||
config := defaultTLSConfig(hostname)
|
||||
|
||||
firstChain, err := getChain(addr, config)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
grade, _, err = multiscan(addr, func(addrport string) (g Grade, o Output, e error) {
|
||||
g = Good
|
||||
chain, e1 := getChain(addrport, config)
|
||||
if e1 != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if !chain[0].Equal(firstChain[0]) {
|
||||
e = fmt.Errorf("%s not equal to %s", chain[0].Subject.CommonName, firstChain[0].Subject.CommonName)
|
||||
g = Bad
|
||||
return
|
||||
}
|
||||
return
|
||||
})
|
||||
return
|
||||
}
|
281
vendor/github.com/cloudflare/cfssl/scan/scan_common.go
generated
vendored
Normal file
281
vendor/github.com/cloudflare/cfssl/scan/scan_common.go
generated
vendored
Normal file
@@ -0,0 +1,281 @@
|
||||
package scan
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"net"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/cloudflare/cfssl/helpers"
|
||||
"github.com/cloudflare/cfssl/log"
|
||||
)
|
||||
|
||||
var (
|
||||
// Network is the default network to use.
|
||||
Network = "tcp"
|
||||
// Dialer is the default dialer to use, with a 1s timeout.
|
||||
Dialer = &net.Dialer{Timeout: time.Second}
|
||||
// Client is the default HTTP Client.
|
||||
Client = &http.Client{Transport: &http.Transport{Dial: Dialer.Dial}}
|
||||
// RootCAs defines the default root certificate authorities to be used for scan.
|
||||
RootCAs *x509.CertPool
|
||||
)
|
||||
|
||||
// Grade gives a subjective rating of the host's success in a scan.
|
||||
type Grade int
|
||||
|
||||
const (
|
||||
// Bad describes a host with serious misconfiguration or vulnerability.
|
||||
Bad Grade = iota
|
||||
// Warning describes a host with non-ideal configuration that maintains support for Warning clients.
|
||||
Warning
|
||||
// Good describes host performing the expected state-of-the-art.
|
||||
Good
|
||||
// Skipped descibes the "grade" of a scan that has been skipped.
|
||||
Skipped
|
||||
)
|
||||
|
||||
// String gives the name of the Grade as a string.
|
||||
func (g Grade) String() string {
|
||||
switch g {
|
||||
case Bad:
|
||||
return "Bad"
|
||||
case Warning:
|
||||
return "Warning"
|
||||
case Good:
|
||||
return "Good"
|
||||
case Skipped:
|
||||
return "Skipped"
|
||||
default:
|
||||
return "Invalid"
|
||||
}
|
||||
}
|
||||
|
||||
// Output is the result of a scan, to be stored for potential use by later Scanners.
|
||||
type Output interface{}
|
||||
|
||||
// multiscan scans all DNS addresses returned for the host, returning the lowest grade
|
||||
// and the concatenation of all the output.
|
||||
func multiscan(host string, scan func(string) (Grade, Output, error)) (grade Grade, output Output, err error) {
|
||||
domain, port, _ := net.SplitHostPort(host)
|
||||
var addrs []string
|
||||
addrs, err = net.LookupHost(domain)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
grade = Good
|
||||
out := make(map[string]Output)
|
||||
|
||||
for _, addr := range addrs {
|
||||
var g Grade
|
||||
var o Output
|
||||
|
||||
g, o, err = scan(net.JoinHostPort(addr, port))
|
||||
if err != nil {
|
||||
grade = Bad
|
||||
return
|
||||
}
|
||||
|
||||
if g < grade {
|
||||
grade = g
|
||||
}
|
||||
|
||||
out[addr] = o
|
||||
}
|
||||
output = out
|
||||
return
|
||||
}
|
||||
|
||||
// Scanner describes a type of scan to perform on a host.
|
||||
type Scanner struct {
|
||||
// Description describes the nature of the scan to be performed.
|
||||
Description string `json:"description"`
|
||||
// scan is the function that scans the given host and provides a Grade and Output.
|
||||
scan func(string, string) (Grade, Output, error)
|
||||
}
|
||||
|
||||
// Scan performs the scan to be performed on the given host and stores its result.
|
||||
func (s *Scanner) Scan(addr, hostname string) (Grade, Output, error) {
|
||||
grade, output, err := s.scan(addr, hostname)
|
||||
if err != nil {
|
||||
log.Debugf("scan: %v", err)
|
||||
return grade, output, err
|
||||
}
|
||||
return grade, output, err
|
||||
}
|
||||
|
||||
// Family defines a set of related scans meant to be run together in sequence.
|
||||
type Family struct {
|
||||
// Description gives a short description of the scans performed scan/scan_common.goon the host.
|
||||
Description string `json:"description"`
|
||||
// Scanners is a list of scanners that are to be run in sequence.
|
||||
Scanners map[string]*Scanner `json:"scanners"`
|
||||
}
|
||||
|
||||
// FamilySet contains a set of Families to run Scans from.
|
||||
type FamilySet map[string]*Family
|
||||
|
||||
// Default contains each scan Family that is defined
|
||||
var Default = FamilySet{
|
||||
"Connectivity": Connectivity,
|
||||
"TLSHandshake": TLSHandshake,
|
||||
"TLSSession": TLSSession,
|
||||
"PKI": PKI,
|
||||
"Broad": Broad,
|
||||
}
|
||||
|
||||
// ScannerResult contains the result for a single scan.
|
||||
type ScannerResult struct {
|
||||
Grade string `json:"grade"`
|
||||
Output Output `json:"output,omitempty"`
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
// FamilyResult contains a scan response for a single Family
|
||||
type FamilyResult map[string]ScannerResult
|
||||
|
||||
// A Result contains a ScannerResult along with it's scanner and family names.
|
||||
type Result struct {
|
||||
Family, Scanner string
|
||||
ScannerResult
|
||||
}
|
||||
|
||||
type context struct {
|
||||
sync.WaitGroup
|
||||
addr, hostname string
|
||||
familyRegexp, scannerRegexp *regexp.Regexp
|
||||
resultChan chan *Result
|
||||
}
|
||||
|
||||
func newContext(addr, hostname string, familyRegexp, scannerRegexp *regexp.Regexp, numFamilies int) *context {
|
||||
ctx := &context{
|
||||
addr: addr,
|
||||
hostname: hostname,
|
||||
familyRegexp: familyRegexp,
|
||||
scannerRegexp: scannerRegexp,
|
||||
resultChan: make(chan *Result),
|
||||
}
|
||||
ctx.Add(numFamilies)
|
||||
|
||||
go func() {
|
||||
ctx.Wait()
|
||||
close(ctx.resultChan)
|
||||
}()
|
||||
|
||||
return ctx
|
||||
}
|
||||
|
||||
type familyContext struct {
|
||||
sync.WaitGroup
|
||||
ctx *context
|
||||
}
|
||||
|
||||
func (ctx *context) newfamilyContext(numScanners int) *familyContext {
|
||||
familyCtx := &familyContext{ctx: ctx}
|
||||
familyCtx.Add(numScanners)
|
||||
|
||||
go func() {
|
||||
familyCtx.Wait()
|
||||
familyCtx.ctx.Done()
|
||||
}()
|
||||
|
||||
return familyCtx
|
||||
}
|
||||
|
||||
func (ctx *context) copyResults(timeout time.Duration) map[string]FamilyResult {
|
||||
results := make(map[string]FamilyResult)
|
||||
for {
|
||||
var result *Result
|
||||
select {
|
||||
case <-time.After(timeout):
|
||||
log.Warningf("Scan timed out after %v", timeout)
|
||||
return results
|
||||
case result = <-ctx.resultChan:
|
||||
if result == nil {
|
||||
return results
|
||||
}
|
||||
}
|
||||
|
||||
if results[result.Family] == nil {
|
||||
results[result.Family] = make(FamilyResult)
|
||||
}
|
||||
results[result.Family][result.Scanner] = result.ScannerResult
|
||||
}
|
||||
}
|
||||
|
||||
func (familyCtx *familyContext) runScanner(familyName, scannerName string, scanner *Scanner) {
|
||||
if familyCtx.ctx.familyRegexp.MatchString(familyName) && familyCtx.ctx.scannerRegexp.MatchString(scannerName) {
|
||||
grade, output, err := scanner.Scan(familyCtx.ctx.addr, familyCtx.ctx.hostname)
|
||||
result := &Result{
|
||||
familyName,
|
||||
scannerName,
|
||||
ScannerResult{
|
||||
Grade: grade.String(),
|
||||
Output: output,
|
||||
},
|
||||
}
|
||||
if err != nil {
|
||||
result.Error = err.Error()
|
||||
}
|
||||
familyCtx.ctx.resultChan <- result
|
||||
}
|
||||
familyCtx.Done()
|
||||
}
|
||||
|
||||
// RunScans iterates over AllScans, running each scan that matches the family
|
||||
// and scanner regular expressions concurrently.
|
||||
func (fs FamilySet) RunScans(host, ip, family, scanner string, timeout time.Duration) (map[string]FamilyResult, error) {
|
||||
hostname, port, err := net.SplitHostPort(host)
|
||||
if err != nil {
|
||||
hostname = host
|
||||
port = "443"
|
||||
}
|
||||
|
||||
var addr string
|
||||
if net.ParseIP(ip) != nil {
|
||||
addr = net.JoinHostPort(ip, port)
|
||||
} else {
|
||||
addr = net.JoinHostPort(hostname, port)
|
||||
}
|
||||
|
||||
familyRegexp, err := regexp.Compile(family)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
scannerRegexp, err := regexp.Compile(scanner)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ctx := newContext(addr, hostname, familyRegexp, scannerRegexp, len(fs))
|
||||
for familyName, family := range fs {
|
||||
familyCtx := ctx.newfamilyContext(len(family.Scanners))
|
||||
for scannerName, scanner := range family.Scanners {
|
||||
go familyCtx.runScanner(familyName, scannerName, scanner)
|
||||
}
|
||||
}
|
||||
|
||||
return ctx.copyResults(timeout), nil
|
||||
}
|
||||
|
||||
// LoadRootCAs loads the default root certificate authorities from file.
|
||||
func LoadRootCAs(caBundleFile string) (err error) {
|
||||
if caBundleFile != "" {
|
||||
log.Debugf("Loading scan RootCAs: %s", caBundleFile)
|
||||
RootCAs, err = helpers.LoadPEMCertPool(caBundleFile)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func defaultTLSConfig(hostname string) *tls.Config {
|
||||
return &tls.Config{
|
||||
ServerName: hostname,
|
||||
RootCAs: RootCAs,
|
||||
InsecureSkipVerify: true,
|
||||
}
|
||||
}
|
427
vendor/github.com/cloudflare/cfssl/scan/tls_handshake.go
generated
vendored
Normal file
427
vendor/github.com/cloudflare/cfssl/scan/tls_handshake.go
generated
vendored
Normal file
@@ -0,0 +1,427 @@
|
||||
package scan
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
|
||||
"github.com/cloudflare/cfssl/helpers"
|
||||
)
|
||||
|
||||
// Sentinel for failures in sayHello. Should always be caught.
|
||||
var errHelloFailed = errors.New("Handshake failed in sayHello")
|
||||
|
||||
// TLSHandshake contains scanners testing host cipher suite negotiation
|
||||
var TLSHandshake = &Family{
|
||||
Description: "Scans for host's SSL/TLS version and cipher suite negotiation",
|
||||
Scanners: map[string]*Scanner{
|
||||
"CipherSuite": {
|
||||
"Determines host's cipher suites accepted and prefered order",
|
||||
cipherSuiteScan,
|
||||
},
|
||||
"SigAlgs": {
|
||||
"Determines host's accepted signature and hash algorithms",
|
||||
sigAlgsScan,
|
||||
},
|
||||
"CertsBySigAlgs": {
|
||||
"Determines host's certificate signature algorithm matching client's accepted signature and hash algorithms",
|
||||
certSigAlgsScan,
|
||||
},
|
||||
"CertsByCiphers": {
|
||||
"Determines host's certificate signature algorithm matching client's accepted ciphers",
|
||||
certSigAlgsScanByCipher,
|
||||
},
|
||||
"ECCurves": {
|
||||
"Determines the host's ec curve support for TLS 1.2",
|
||||
ecCurveScan,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func getCipherIndex(ciphers []uint16, serverCipher uint16) (cipherIndex int, err error) {
|
||||
//func getCipherIndex(ciphers []uint16, serverCipher uint16) (cipherIndex int, err error) {
|
||||
// fmt.Println(serverCipher, ciphers)
|
||||
var cipherID uint16
|
||||
for cipherIndex, cipherID = range ciphers {
|
||||
if serverCipher == cipherID {
|
||||
return
|
||||
}
|
||||
}
|
||||
err = fmt.Errorf("server negotiated ciphersuite we didn't send: %s", tls.CipherSuites[serverCipher])
|
||||
return
|
||||
}
|
||||
|
||||
func getCurveIndex(curves []tls.CurveID, serverCurve tls.CurveID) (curveIndex int, err error) {
|
||||
var curveID tls.CurveID
|
||||
for curveIndex, curveID = range curves {
|
||||
if serverCurve == curveID {
|
||||
return
|
||||
}
|
||||
}
|
||||
err = fmt.Errorf("server negotiated elliptic curve we didn't send: %s", tls.Curves[serverCurve])
|
||||
return
|
||||
}
|
||||
|
||||
func sayHello(addr, hostname string, ciphers []uint16, curves []tls.CurveID, vers uint16, sigAlgs []tls.SignatureAndHash) (cipherIndex, curveIndex int, certs [][]byte, err error) {
|
||||
tcpConn, err := net.Dial(Network, addr)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
config := defaultTLSConfig(hostname)
|
||||
config.MinVersion = vers
|
||||
config.MaxVersion = vers
|
||||
if ciphers == nil {
|
||||
ciphers = allCiphersIDs()
|
||||
}
|
||||
config.CipherSuites = ciphers
|
||||
|
||||
if curves == nil {
|
||||
curves = allCurvesIDs()
|
||||
}
|
||||
config.CurvePreferences = curves
|
||||
|
||||
if sigAlgs == nil {
|
||||
sigAlgs = tls.AllSignatureAndHashAlgorithms
|
||||
}
|
||||
|
||||
conn := tls.Client(tcpConn, config)
|
||||
serverCipher, serverCurveType, serverCurve, serverVersion, certificates, err := conn.SayHello(sigAlgs)
|
||||
certs = certificates
|
||||
conn.Close()
|
||||
if err != nil {
|
||||
err = errHelloFailed
|
||||
return
|
||||
}
|
||||
|
||||
if serverVersion != vers {
|
||||
err = fmt.Errorf("server negotiated protocol version we didn't send: %s", tls.Versions[serverVersion])
|
||||
return
|
||||
}
|
||||
|
||||
cipherIndex, err = getCipherIndex(ciphers, serverCipher)
|
||||
|
||||
if tls.CipherSuites[serverCipher].EllipticCurve {
|
||||
if curves == nil {
|
||||
curves = allCurvesIDs()
|
||||
}
|
||||
if serverCurveType != 3 {
|
||||
err = fmt.Errorf("server negotiated non-named ECDH parameters; we didn't analyze them. Server curve type: %d", serverCurveType)
|
||||
return
|
||||
}
|
||||
curveIndex, err = getCurveIndex(curves, serverCurve)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func allCiphersIDs() []uint16 {
|
||||
ciphers := make([]uint16, 0, len(tls.CipherSuites))
|
||||
for cipherID := range tls.CipherSuites {
|
||||
ciphers = append(ciphers, cipherID)
|
||||
}
|
||||
return ciphers
|
||||
}
|
||||
|
||||
func allECDHECiphersIDs() []uint16 {
|
||||
var ecdheCiphers = map[uint16]tls.CipherSuite{
|
||||
0XC006: {Name: "TLS_ECDHE_ECDSA_WITH_NULL_SHA", ForwardSecret: true, EllipticCurve: true},
|
||||
0XC007: {Name: "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA", ShortName: "ECDHE-ECDSA-RC4-SHA", ForwardSecret: true, EllipticCurve: true},
|
||||
0XC008: {Name: "TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA", ShortName: "ECDHE-ECDSA-DES-CBC3-SHA", ForwardSecret: true, EllipticCurve: true},
|
||||
0XC009: {Name: "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", ShortName: "ECDHE-ECDSA-AES128-SHA", ForwardSecret: true, EllipticCurve: true},
|
||||
0XC00A: {Name: "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", ShortName: "ECDHE-ECDSA-AES256-SHA", ForwardSecret: true, EllipticCurve: true},
|
||||
0XC010: {Name: "TLS_ECDHE_RSA_WITH_NULL_SHA", ForwardSecret: true, EllipticCurve: true},
|
||||
0XC011: {Name: "TLS_ECDHE_RSA_WITH_RC4_128_SHA", ShortName: "ECDHE-RSA-RC4-SHA", ForwardSecret: true, EllipticCurve: true},
|
||||
0XC012: {Name: "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA", ShortName: "ECDHE-RSA-DES-CBC3-SHA", ForwardSecret: true, EllipticCurve: true},
|
||||
0XC013: {Name: "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", ShortName: "ECDHE-RSA-AES128-SHA", ForwardSecret: true, EllipticCurve: true},
|
||||
0XC014: {Name: "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", ShortName: "ECDHE-RSA-AES256-SHA", ForwardSecret: true, EllipticCurve: true},
|
||||
0XC023: {Name: "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", ShortName: "ECDHE-ECDSA-AES128-SHA256", ForwardSecret: true, EllipticCurve: true},
|
||||
0XC024: {Name: "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384", ShortName: "ECDHE-ECDSA-AES256-SHA384", ForwardSecret: true, EllipticCurve: true},
|
||||
0XC027: {Name: "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", ShortName: "ECDHE-RSA-AES128-SHA256", ForwardSecret: true, EllipticCurve: true},
|
||||
0XC028: {Name: "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384", ShortName: "ECDHE-RSA-AES256-SHA384", ForwardSecret: true, EllipticCurve: true},
|
||||
0XC02B: {Name: "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", ShortName: "ECDHE-ECDSA-AES128-GCM-SHA256", ForwardSecret: true, EllipticCurve: true},
|
||||
0XC02C: {Name: "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", ShortName: "ECDHE-ECDSA-AES256-GCM-SHA384", ForwardSecret: true, EllipticCurve: true},
|
||||
0XC02F: {Name: "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", ShortName: "ECDHE-RSA-AES128-GCM-SHA256", ForwardSecret: true, EllipticCurve: true},
|
||||
0XC030: {Name: "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", ShortName: "ECDHE-RSA-AES256-GCM-SHA384", ForwardSecret: true, EllipticCurve: true},
|
||||
0XC048: {Name: "TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256", ForwardSecret: true, EllipticCurve: true},
|
||||
0XC049: {Name: "TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384", ForwardSecret: true, EllipticCurve: true},
|
||||
0XC04C: {Name: "TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256", ForwardSecret: true, EllipticCurve: true},
|
||||
0XC04D: {Name: "TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384", ForwardSecret: true, EllipticCurve: true},
|
||||
0XC05D: {Name: "TLS_ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384", ForwardSecret: true, EllipticCurve: true},
|
||||
0XC060: {Name: "TLS_ECDHE_RSA_WITH_ARIA_128_GCM_SHA256", ForwardSecret: true, EllipticCurve: true},
|
||||
0XC061: {Name: "TLS_ECDHE_RSA_WITH_ARIA_256_GCM_SHA384", ForwardSecret: true, EllipticCurve: true},
|
||||
0XC072: {Name: "TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256", ForwardSecret: true, EllipticCurve: true},
|
||||
0XC073: {Name: "TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384", ForwardSecret: true, EllipticCurve: true},
|
||||
0XC076: {Name: "TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256", ForwardSecret: true, EllipticCurve: true},
|
||||
0XC077: {Name: "TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384", ForwardSecret: true, EllipticCurve: true},
|
||||
0XC086: {Name: "TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256", ForwardSecret: true, EllipticCurve: true},
|
||||
0XC087: {Name: "TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384", ForwardSecret: true, EllipticCurve: true},
|
||||
0XC08A: {Name: "TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256", ForwardSecret: true, EllipticCurve: true},
|
||||
0XC08B: {Name: "TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384", ForwardSecret: true, EllipticCurve: true},
|
||||
0XC08C: {Name: "TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256", EllipticCurve: true},
|
||||
0XC0AC: {Name: "TLS_ECDHE_ECDSA_WITH_AES_128_CCM", ForwardSecret: true, EllipticCurve: true},
|
||||
0XC0AD: {Name: "TLS_ECDHE_ECDSA_WITH_AES_256_CCM", ForwardSecret: true, EllipticCurve: true},
|
||||
0XC0AE: {Name: "TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8", ForwardSecret: true, EllipticCurve: true},
|
||||
0XC0AF: {Name: "TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8", ForwardSecret: true, EllipticCurve: true},
|
||||
// Non-IANA standardized cipher suites:
|
||||
// ChaCha20, Poly1305 cipher suites are defined in
|
||||
// https://tools.ietf.org/html/draft-agl-tls-chacha20poly1305-04
|
||||
0XCC13: {Name: "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256", ForwardSecret: true, EllipticCurve: true},
|
||||
0XCC14: {Name: "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256", ForwardSecret: true, EllipticCurve: true},
|
||||
}
|
||||
|
||||
ciphers := make([]uint16, 0, len(ecdheCiphers))
|
||||
for cipherID := range ecdheCiphers {
|
||||
ciphers = append(ciphers, cipherID)
|
||||
}
|
||||
return ciphers
|
||||
}
|
||||
|
||||
func allCurvesIDs() []tls.CurveID {
|
||||
curves := make([]tls.CurveID, 0, len(tls.Curves))
|
||||
for curveID := range tls.Curves {
|
||||
// No unassigned or explicit curves in the scan, per http://tools.ietf.org/html/rfc4492#section-5.4
|
||||
if curveID == 0 || curveID == 65281 || curveID == 65282 {
|
||||
continue
|
||||
} else {
|
||||
curves = append(curves, curveID)
|
||||
}
|
||||
}
|
||||
return curves
|
||||
}
|
||||
|
||||
type cipherDatum struct {
|
||||
versionID uint16
|
||||
curves []tls.CurveID
|
||||
}
|
||||
|
||||
// cipherVersions contains lists of host's supported cipher suites based on SSL/TLS Version.
|
||||
// If a cipher suite uses ECC, also contains a list of supported curves by SSL/TLS Version.
|
||||
type cipherVersions struct {
|
||||
cipherID uint16
|
||||
data []cipherDatum
|
||||
}
|
||||
|
||||
type cipherVersionList []cipherVersions
|
||||
|
||||
func (cvList cipherVersionList) String() string {
|
||||
cvStrings := make([]string, len(cvList))
|
||||
for i, c := range cvList {
|
||||
versStrings := make([]string, len(c.data))
|
||||
for j, d := range c.data {
|
||||
curveStrings := make([]string, len(d.curves))
|
||||
for k, c := range d.curves {
|
||||
curveStrings[k] = tls.Curves[c]
|
||||
}
|
||||
versStrings[j] = fmt.Sprintf("%s: [ %s ]", tls.Versions[d.versionID], strings.Join(curveStrings, ","))
|
||||
}
|
||||
cvStrings[i] = fmt.Sprintf("%s\t%s", tls.CipherSuites[c.cipherID], strings.Join(versStrings, ","))
|
||||
}
|
||||
return strings.Join(cvStrings, "\n")
|
||||
}
|
||||
|
||||
func (cvList cipherVersionList) MarshalJSON() ([]byte, error) {
|
||||
b := new(bytes.Buffer)
|
||||
cvStrs := make([]string, len(cvList))
|
||||
for i, cv := range cvList {
|
||||
versStrings := make([]string, len(cv.data))
|
||||
for j, d := range cv.data {
|
||||
curveStrings := make([]string, len(d.curves))
|
||||
if len(d.curves) > 0 {
|
||||
for k, c := range d.curves {
|
||||
curveStrings[k] = fmt.Sprintf("\"%s\"", tls.Curves[c])
|
||||
}
|
||||
versStrings[j] = fmt.Sprintf("{\"%s\":[%s]}", tls.Versions[d.versionID], strings.Join(curveStrings, ","))
|
||||
} else {
|
||||
versStrings[j] = fmt.Sprintf("\"%s\"", tls.Versions[d.versionID])
|
||||
}
|
||||
}
|
||||
cvStrs[i] = fmt.Sprintf("{\"%s\":[%s]}", tls.CipherSuites[cv.cipherID].String(), strings.Join(versStrings, ","))
|
||||
}
|
||||
fmt.Fprintf(b, "[%s]", strings.Join(cvStrs, ","))
|
||||
return b.Bytes(), nil
|
||||
}
|
||||
|
||||
func doCurveScan(addr, hostname string, vers, cipherID uint16, ciphers []uint16) (supportedCurves []tls.CurveID, err error) {
|
||||
allCurves := allCurvesIDs()
|
||||
curves := make([]tls.CurveID, len(allCurves))
|
||||
copy(curves, allCurves)
|
||||
for len(curves) > 0 {
|
||||
var curveIndex int
|
||||
_, curveIndex, _, err = sayHello(addr, hostname, []uint16{cipherID}, curves, vers, nil)
|
||||
if err != nil {
|
||||
// This case is expected, because eventually we ask only for curves the server doesn't support
|
||||
if err == errHelloFailed {
|
||||
err = nil
|
||||
break
|
||||
}
|
||||
return
|
||||
}
|
||||
curveID := curves[curveIndex]
|
||||
supportedCurves = append(supportedCurves, curveID)
|
||||
curves = append(curves[:curveIndex], curves[curveIndex+1:]...)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// cipherSuiteScan returns, by TLS Version, the sort list of cipher suites
|
||||
// supported by the host
|
||||
func cipherSuiteScan(addr, hostname string) (grade Grade, output Output, err error) {
|
||||
var cvList cipherVersionList
|
||||
allCiphers := allCiphersIDs()
|
||||
|
||||
var vers uint16
|
||||
for vers = tls.VersionTLS12; vers >= tls.VersionSSL30; vers-- {
|
||||
ciphers := make([]uint16, len(allCiphers))
|
||||
copy(ciphers, allCiphers)
|
||||
for len(ciphers) > 0 {
|
||||
var cipherIndex int
|
||||
cipherIndex, _, _, err = sayHello(addr, hostname, ciphers, nil, vers, nil)
|
||||
if err != nil {
|
||||
if err == errHelloFailed {
|
||||
err = nil
|
||||
break
|
||||
}
|
||||
return
|
||||
}
|
||||
if vers == tls.VersionSSL30 {
|
||||
grade = Warning
|
||||
}
|
||||
cipherID := ciphers[cipherIndex]
|
||||
|
||||
// If this is an EC cipher suite, do a second scan for curve support
|
||||
var supportedCurves []tls.CurveID
|
||||
if tls.CipherSuites[cipherID].EllipticCurve {
|
||||
supportedCurves, err = doCurveScan(addr, hostname, vers, cipherID, ciphers)
|
||||
if len(supportedCurves) == 0 {
|
||||
err = errors.New("couldn't negotiate any curves")
|
||||
}
|
||||
}
|
||||
for i, c := range cvList {
|
||||
if cipherID == c.cipherID {
|
||||
cvList[i].data = append(c.data, cipherDatum{vers, supportedCurves})
|
||||
goto exists
|
||||
}
|
||||
}
|
||||
cvList = append(cvList, cipherVersions{cipherID, []cipherDatum{{vers, supportedCurves}}})
|
||||
exists:
|
||||
ciphers = append(ciphers[:cipherIndex], ciphers[cipherIndex+1:]...)
|
||||
}
|
||||
}
|
||||
|
||||
if len(cvList) == 0 {
|
||||
err = errors.New("couldn't negotiate any cipher suites")
|
||||
return
|
||||
}
|
||||
|
||||
if grade != Warning {
|
||||
grade = Good
|
||||
}
|
||||
|
||||
output = cvList
|
||||
return
|
||||
}
|
||||
|
||||
// sigAlgsScan returns the accepted signature and hash algorithms of the host
|
||||
func sigAlgsScan(addr, hostname string) (grade Grade, output Output, err error) {
|
||||
var supportedSigAlgs []tls.SignatureAndHash
|
||||
for _, sigAlg := range tls.AllSignatureAndHashAlgorithms {
|
||||
_, _, _, e := sayHello(addr, hostname, nil, nil, tls.VersionTLS12, []tls.SignatureAndHash{sigAlg})
|
||||
if e == nil {
|
||||
supportedSigAlgs = append(supportedSigAlgs, sigAlg)
|
||||
}
|
||||
}
|
||||
|
||||
if len(supportedSigAlgs) > 0 {
|
||||
grade = Good
|
||||
output = supportedSigAlgs
|
||||
} else {
|
||||
err = errors.New("no SigAlgs supported")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// certSigAlgScan returns the server certificate with various sigature and hash algorithms in the ClientHello
|
||||
func certSigAlgsScan(addr, hostname string) (grade Grade, output Output, err error) {
|
||||
var certSigAlgs = make(map[string]string)
|
||||
for _, sigAlg := range tls.AllSignatureAndHashAlgorithms {
|
||||
_, _, derCerts, e := sayHello(addr, hostname, nil, nil, tls.VersionTLS12, []tls.SignatureAndHash{sigAlg})
|
||||
if e == nil {
|
||||
if len(derCerts) == 0 {
|
||||
return Bad, nil, errors.New("no certs returned")
|
||||
}
|
||||
certs, _, err := helpers.ParseCertificatesDER(derCerts[0], "")
|
||||
if err != nil {
|
||||
return Bad, nil, err
|
||||
}
|
||||
|
||||
certSigAlgs[sigAlg.String()] = helpers.SignatureString(certs[0].SignatureAlgorithm)
|
||||
//certSigAlgs = append(certSigAlgs, certs[0].SignatureAlgorithm)
|
||||
}
|
||||
}
|
||||
|
||||
if len(certSigAlgs) > 0 {
|
||||
grade = Good
|
||||
output = certSigAlgs
|
||||
} else {
|
||||
err = errors.New("no SigAlgs supported")
|
||||
}
|
||||
return
|
||||
|
||||
}
|
||||
|
||||
// certSigAlgScan returns the server certificate with various ciphers in the ClientHello
|
||||
func certSigAlgsScanByCipher(addr, hostname string) (grade Grade, output Output, err error) {
|
||||
var certSigAlgs = make(map[string]string)
|
||||
for cipherID := range tls.CipherSuites {
|
||||
_, _, derCerts, e := sayHello(addr, hostname, []uint16{cipherID}, nil, tls.VersionTLS12, []tls.SignatureAndHash{})
|
||||
if e == nil {
|
||||
if len(derCerts) == 0 {
|
||||
return Bad, nil, errors.New("no certs returned")
|
||||
}
|
||||
certs, _, err := helpers.ParseCertificatesDER(derCerts[0], "")
|
||||
if err != nil {
|
||||
return Bad, nil, err
|
||||
}
|
||||
|
||||
certSigAlgs[tls.CipherSuites[cipherID].Name] = helpers.SignatureString(certs[0].SignatureAlgorithm)
|
||||
//certSigAlgs = append(certSigAlgs, certs[0].SignatureAlgorithm)
|
||||
}
|
||||
}
|
||||
|
||||
if len(certSigAlgs) > 0 {
|
||||
grade = Good
|
||||
output = certSigAlgs
|
||||
} else {
|
||||
err = errors.New("no cipher supported")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// ecCurveScan returns the elliptic curves supported by the host.
|
||||
func ecCurveScan(addr, hostname string) (grade Grade, output Output, err error) {
|
||||
allCurves := allCurvesIDs()
|
||||
curves := make([]tls.CurveID, len(allCurves))
|
||||
copy(curves, allCurves)
|
||||
var supportedCurves []string
|
||||
for len(curves) > 0 {
|
||||
var curveIndex int
|
||||
_, curveIndex, _, err = sayHello(addr, hostname, allECDHECiphersIDs(), curves, tls.VersionTLS12, nil)
|
||||
if err != nil {
|
||||
// This case is expected, because eventually we ask only for curves the server doesn't support
|
||||
if err == errHelloFailed {
|
||||
err = nil
|
||||
break
|
||||
}
|
||||
return
|
||||
}
|
||||
curveID := curves[curveIndex]
|
||||
supportedCurves = append(supportedCurves, tls.Curves[curveID])
|
||||
curves = append(curves[:curveIndex], curves[curveIndex+1:]...)
|
||||
}
|
||||
output = supportedCurves
|
||||
grade = Good
|
||||
return
|
||||
}
|
42
vendor/github.com/cloudflare/cfssl/scan/tls_session.go
generated
vendored
Normal file
42
vendor/github.com/cloudflare/cfssl/scan/tls_session.go
generated
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
package scan
|
||||
|
||||
import "crypto/tls"
|
||||
|
||||
// TLSSession contains tests of host TLS Session Resumption via
|
||||
// Session Tickets and Session IDs
|
||||
var TLSSession = &Family{
|
||||
Description: "Scans host's implementation of TLS session resumption using session tickets/session IDs",
|
||||
Scanners: map[string]*Scanner{
|
||||
"SessionResume": {
|
||||
"Host is able to resume sessions across all addresses",
|
||||
sessionResumeScan,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// SessionResumeScan tests that host is able to resume sessions across all addresses.
|
||||
func sessionResumeScan(addr, hostname string) (grade Grade, output Output, err error) {
|
||||
config := defaultTLSConfig(hostname)
|
||||
config.ClientSessionCache = tls.NewLRUClientSessionCache(1)
|
||||
|
||||
conn, err := tls.DialWithDialer(Dialer, Network, addr, config)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if err = conn.Close(); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return multiscan(addr, func(addrport string) (g Grade, o Output, e error) {
|
||||
var conn *tls.Conn
|
||||
if conn, e = tls.DialWithDialer(Dialer, Network, addrport, config); e != nil {
|
||||
return
|
||||
}
|
||||
conn.Close()
|
||||
|
||||
if o = conn.ConnectionState().DidResume; o.(bool) {
|
||||
g = Good
|
||||
}
|
||||
return
|
||||
})
|
||||
}
|
Reference in New Issue
Block a user