// renderOptions render options func renderOptions(options []option, colorTag string) { var ( curGroup string opt option maxSize int ) maxSize = getMaxOptionSize(options) for _, opt = range options { if curGroup != opt.group { printGroupHeader(opt.group) curGroup = opt.group } fmtc.Printf(" "+colorTag+"%s{!}", opt.name) if len(opt.args) != 0 { fmtc.Printf(" " + renderArgs(opt.args)) } fmtc.Printf(getBreadcrumbs(opt, maxSize)) fmtc.Printf(opt.desc) fmtc.NewLine() } }
// printDetailedEndpointInfo fetch and print detailed info for one endpoint func printDetailedEndpointInfo(ap *sslscan.AnalyzeProgress, ip string) { info, err := ap.DetailedInfo(ip) if err != nil { fmtc.Printf("\n{r}Can't fetch detailed info for %s{!}\n\n", ip) return } if strings.ToUpper(info.StatusMessage) != "READY" { fmtc.Printf("\n{r}%s{!}\n\n", info.StatusMessage) return } details := info.Details fmtc.NewLine() printCertificateInfo(details) printCertificationPathsInfo(details) printProtocolsInfo(details) suiteIndex := printCipherSuitesInfo(details) printHandshakeSimulationInfo(details, suiteIndex) printProtocolDetailsInfo(details) printMiscellaneousInfo(info) fmtutil.Separator(true) fmtc.NewLine() }
// Render print version info to console func (about *About) Render() { switch { case about.Build != "": fmtc.Printf( "\n{*c}%s {c}%s{!}{s}%s{!} {s-}(%s){!} - %s\n\n", about.App, about.Version, about.Release, about.Build, about.Desc, ) default: fmtc.Printf( "\n{*c}%s {c}%s{!}{s}%s{!} - %s\n\n", about.App, about.Version, about.Release, about.Desc, ) } if about.Owner != "" { if about.Year == 0 { fmtc.Printf("{s-}Copyright (C) %s{!}\n", about.Owner) } else { fmtc.Printf( "{s-}Copyright (C) %d-%d %s{!}\n", about.Year, time.Now().Year(), about.Owner, ) } } if about.License != "" { fmtc.Printf("{s-}%s{!}\n", about.License) } fmtc.NewLine() }
// renderTemplate read template and render to file func renderTemplate(doc *Document) { projectDir := env.Get().GetS("GOPATH") templateFile := path.Join( projectDir, "src/github.com/essentialkaos/shdoc/templates", arg.GetS(ARG_TEMPLATE)+".tpl", ) if !fsutil.CheckPerms("FRS", templateFile) { printError("Can't read template %s - file is not exist or empty", templateFile) os.Exit(1) } outputFile := arg.GetS(ARG_OUTPUT) if fsutil.IsExist(outputFile) { os.Remove(outputFile) } fd, err := os.OpenFile(outputFile, os.O_CREATE|os.O_WRONLY, 0644) if err != nil { printError(err.Error()) os.Exit(1) } defer fd.Close() tpl, err := ioutil.ReadFile(templateFile) if err != nil { printError(err.Error()) os.Exit(1) } t := template.New("Template") t, err = t.Parse(string(tpl[:])) err = t.Execute(fd, doc) if err != nil { printError(err.Error()) os.Exit(1) } fmtutil.Separator(false, doc.Title) fmtc.Printf(" {*}Constants:{!} %d\n", len(doc.Constants)) fmtc.Printf(" {*}Variables:{!} %d\n", len(doc.Variables)) fmtc.Printf(" {*}Methods:{!} %d\n", len(doc.Methods)) fmtc.NewLine() fmtc.Printf( " {*}Output:{!} %s {s-}(%s){!}\n", outputFile, fmtutil.PrettySize(fsutil.GetSize(outputFile)), ) fmtutil.Separator(false) }
// Init starts initialization rutine func Init() { args, errs := arg.Parse(argMap) if len(errs) != 0 { fmtc.Println("{r}Arguments parsing errors:{!}") for _, err := range errs { fmtc.Printf(" {r}%v{!}\n", err) } os.Exit(1) } if arg.GetB(ARG_NO_COLOR) { fmtc.DisableColors = true } if arg.GetB(ARG_VER) { showAbout() return } if arg.GetB(ARG_HELP) || len(args) == 0 { showUsage() return } runtime.GOMAXPROCS(2) process(args) }
func readUserInput(title string, nonEmpty bool, private bool) (string, error) { if title != "" { fmtc.Printf("{c}%s{!}\n", title) } var ( input string err error ) for { input, err = linenoise.Line(Prompt) if err != nil { return "", err } if nonEmpty && strings.TrimSpace(input) == "" { PrintWarnMessage("\nYou must enter non empty value\n") continue } if private && input != "" { if MaskSymbolColorTag == "" { fmt.Println(getPrivateHider(input)) } else { fmtc.Println(MaskSymbolColorTag + getPrivateHider(input) + "{!}") } } break } return input, err }
// renderExamples render examples func renderExamples(info *Info) { printGroupHeader("Examples") total := len(info.examples) for index, example := range info.examples { fmtc.Printf(" %s %s\n", info.name, example.cmd) if example.desc != "" { fmtc.Printf(" {s-}%s{!}\n", example.desc) } if index < total-1 { fmtc.NewLine() } } }
// simpleRender print all document info to console func simpleRender(doc *Document) { if doc.HasAbout() { fmtutil.Separator(false, "ABOUT") for _, l := range doc.About { fmtc.Printf(" %s\n", l) } } if doc.HasConstants() { fmtutil.Separator(false, "CONSTANTS") totalConstants := len(doc.Constants) for i, c := range doc.Constants { renderConstant(c) if i < totalConstants-1 { fmtc.NewLine() } } } if doc.HasVariables() { fmtutil.Separator(false, "GLOBAL VARIABLES") totalVariables := len(doc.Variables) for i, v := range doc.Variables { renderVariable(v) if i < totalVariables-1 { fmtc.NewLine() } } } if doc.HasMethods() { fmtutil.Separator(false, "METHODS") totalMethods := len(doc.Methods) for i, m := range doc.Methods { renderMethod(m, false) if i < totalMethods-1 { fmtc.NewLine() fmtc.NewLine() } } } fmtutil.Separator(false) }
// printCipherSuitesInfo print info about supported cipher suites func printCipherSuitesInfo(details *sslscan.EndpointDetails) map[int]int { printCategoryHeader("Cipher Suites") suiteIndex := make(map[int]int) for index, suite := range details.Suites.List { suiteIndex[suite.ID] = index tag := "" insecure := strings.Contains(suite.Name, "_RC4_") switch { case suite.Q != nil: tag = "{y}(WEAK){!}" case suite.DHStrength != 0 && suite.DHStrength < 2048: tag = "{y}(WEAK){!}" } if insecure { fmtc.Printf(" {r}%-42s{!} {s}|{!} {r}%d (INSECURE){!} ", suite.Name, suite.CipherStrength) } else { fmtc.Printf(" %-42s {s}|{!} %d ", suite.Name, suite.CipherStrength) } switch { case suite.DHStrength != 0: fmtc.Printf("{s-}(DH %d bits){!} "+tag+"\n", suite.DHStrength) case suite.ECDHBits != 0: fmtc.Printf("{s-}(ECDH %d bits ~ %d bits RSA){!} "+tag+"\n", suite.ECDHBits, suite.ECDHStrength) default: fmtc.Println(tag) } } return suiteIndex }
// printProtocolsInfo print info about supported protocols func printProtocolsInfo(details *sslscan.EndpointDetails) { printCategoryHeader("Protocols") supportedProtocols := getProtocols(details.Protocols) for _, protocol := range protocolList { fmtc.Printf(" %-24s {s}|{!} ", protocol) switch { case protocol == "TLS 1.2": if supportedProtocols[protocol] { fmtc.Println("{g}Yes{!}") } else { fmtc.Println("{y}No{!}") } case protocol == "SSL 3.0" && supportedProtocols[protocol]: fmtc.Printf("{r}%s{!}\n", getBool(supportedProtocols[protocol])) case protocol == "SSL 2.0" && supportedProtocols[protocol]: fmtc.Printf("{r}%s{!}\n", getBool(supportedProtocols[protocol])) default: fmtc.Printf("%s\n", getBool(supportedProtocols[protocol])) } } }
// printDetailedInfo fetch and print detailed info for all endpoints func printDetailedInfo(ap *sslscan.AnalyzeProgress, info *sslscan.AnalyzeInfo) { showHeaders := len(info.Endpoints) > 1 if showHeaders { fmtc.NewLine() } for index, endpoint := range info.Endpoints { if showHeaders { fmtc.Printf("\n{c} %s #%d (%s){!}\n\n", info.Host, index+1, endpoint.IPAdress) } printDetailedEndpointInfo(ap, endpoint.IPAdress) } }
// printMiscellaneousInfo print miscellaneous info about endpoint func printMiscellaneousInfo(info *sslscan.EndpointInfo) { printCategoryHeader("Miscellaneous") details := info.Details testDate := time.Unix(info.Details.HostStartTime/1000, 0) // --- fmtc.Printf( " %-24s {s}|{!} %s {s-}(%s ago){!}\n", "Test date", timeutil.Format(testDate, "%Y/%m/%d %H:%M:%S"), timeutil.PrettyDuration(time.Since(testDate)), ) // --- fmtc.Printf(" %-24s {s}|{!} %s\n", "Test duration", timeutil.PrettyDuration(info.Duration/1000)) fmtc.Printf(" %-24s {s}|{!} %d\n", "HTTP status code", details.HTTPStatusCode) // --- if details.HTTPForwarding != "" { if strings.Contains(details.HTTPForwarding, "http://") { fmtc.Printf(" %-24s {s}|{!} {y}%s (PLAINTEXT){!}\n", "HTTP forwarding", details.HTTPForwarding) } else { fmtc.Printf(" %-24s {s}|{!} %s\n", "HTTP forwarding", details.HTTPForwarding) } } // --- if details.ServerSignature != "" { fmtc.Printf(" %-24s {s}|{!} %s\n", "HTTP server signature", details.ServerSignature) } // --- if info.ServerName != "" { fmtc.Printf(" %-24s {s}|{!} %s\n", "Server hostname", info.ServerName) } }
func main() { args, errs := arg.Parse(argMap) if len(errs) != 0 { fmtc.Println("Arguments parsing errors:") for _, err := range errs { fmtc.Printf(" %s\n", err.Error()) } os.Exit(1) } if arg.GetB(ARG_NO_COLOR) { fmtc.DisableColors = true } if arg.GetB(ARG_VER) { showAbout() return } if arg.GetB(ARG_HELP) || len(args) == 0 { showUsage() return } switch len(args) { case 1: process(args[0], "") case 2: process(args[0], args[1]) default: showUsage() } }
// renderMethod print method info to console func renderMethod(m *Method, showExamples bool) { fmtc.Printf("{s-}%4d:{!} {b*}%s{!} {s}-{!} %s\n", m.Line, m.Name, m.UnitedDesc()) if len(m.Arguments) != 0 { fmtc.NewLine() for _, a := range m.Arguments { switch { case a.IsOptional: fmtc.Printf(" {s-}%2s.{!} %s "+getVarTypeDesc(a.Type)+" {s-}[Optional]{!}\n", a.Index, a.Desc) case a.IsWildcard: fmtc.Printf(" {s-}%2s.{!} %s\n", a.Index, a.Desc) default: fmtc.Printf(" {s-}%2s.{!} %s "+getVarTypeDesc(a.Type)+"\n", a.Index, a.Desc) } } } if m.ResultCode { fmtc.NewLine() fmtc.Printf(" {*}Code:{!} 0 - ok, 1 - not ok\n") } if m.ResultEcho != nil { fmtc.NewLine() fmtc.Printf(" {*}Echo:{!} %s "+getVarTypeDesc(m.ResultEcho.Type)+"\n", strings.Join(m.ResultEcho.Desc, " ")) } if m.Example != nil && showExamples { fmtc.NewLine() fmtc.Println(" {*}Example:{!}") fmtc.NewLine() for _, l := range m.Example { fmtc.Printf(" %s\n", l) } } }
// printHandshakeSimulationInfo print info about handshakes simulations func printHandshakeSimulationInfo(details *sslscan.EndpointDetails, suiteIndex map[int]int) { printCategoryHeader("Handshake Simulation") for _, sim := range details.SIMS.Results { if sim.ErrorCode != 0 { fmtc.Printf(" %-24s {s}|{!} {r}Fail{!}\n", sim.Client.Name+" "+sim.Client.Version) continue } tag := "{s-}No FS{!}" suite := details.Suites.List[suiteIndex[sim.SuiteID]] if strings.Contains(suite.Name, "DHE_") { tag = "{g} FS{!}" } if sim.Client.IsReference { fmtc.Printf(" %-38s {s}|{!} ", sim.Client.Name+" "+sim.Client.Version+" "+fmtc.Sprintf("{g}R")) } else { fmtc.Printf(" %-24s {s}|{!} ", sim.Client.Name+" "+sim.Client.Version) } switch protocolIDs[sim.ProtocolID] { case "TLS 1.2": fmtc.Printf("{g}%-7s{!} %-42s "+tag+" %d\n", protocolIDs[sim.ProtocolID], suite.Name, suite.CipherStrength, ) case "SSL 2.0", "SSL 3.0": fmtc.Printf("{r}%-7s{!} %-42s "+tag+" %d\n", protocolIDs[sim.ProtocolID], suite.Name, suite.CipherStrength, ) default: fmtc.Printf("%-7s %-42s "+tag+" %d\n", protocolIDs[sim.ProtocolID], suite.Name, suite.CipherStrength, ) } } }
// check check some host func check(host string) string { var err error var info *sslscan.AnalyzeInfo showServerMessage() params := sslscan.AnalyzeParams{ Public: arg.GetB(ARG_PUBLIC), StartNew: arg.GetB(ARG_AVOID_CACHE), FromCache: !arg.GetB(ARG_AVOID_CACHE), IgnoreMismatch: arg.GetB(ARG_IGNORE_MISMATCH), } fmtc.Printf("{*}%s{!} → ", host) ap, err := api.Analyze(host, params) if err != nil { fmtc.Printf("{r}%v{!}\n", err) return "T" } t := &fmtc.T{} for { info, err = ap.Info() if err != nil { t.Printf("{r}%v{!}\n", err) return "Err" } if info.Status == sslscan.STATUS_ERROR { t.Printf("{r}%s{!}\n", info.StatusMessage) return "Err" } else if info.Status == sslscan.STATUS_READY { break } if len(info.Endpoints) != 0 { message := getStatusInProgress(info.Endpoints) if message != "" { t.Printf("{s}%s...{!}", message) } } if info.Status == sslscan.STATUS_IN_PROGRESS { time.Sleep(6 * time.Second) } else { time.Sleep(2 * time.Second) } } if len(info.Endpoints) == 1 { t.Println(getColoredGrade(info.Endpoints[0].Grade)) } else { t.Println(getColoredGrades(info.Endpoints)) } if arg.GetB(ARG_DETAILED) { printDetailedInfo(ap, info) } lowestGrade, _ := getGrades(info.Endpoints) return lowestGrade }
// process starting request processing func process(args []string) { var ( ok bool err error hosts []string ) api, err = sslscan.NewAPI("SSLCli", VER) if err != nil { if !arg.GetB(ARG_FORMAT) { fmtc.Printf("{r}%v{!}\n", err) } os.Exit(1) } // By default all fine ok = true hosts = args if fsutil.CheckPerms("FR", hosts[0]) { hosts, err = readHostList(hosts[0]) if err != nil && arg.GetB(ARG_FORMAT) { fmtc.Printf("{r}%v{!}\n", err) os.Exit(1) } } var ( grade string checksInfo []*HostCheckInfo checkInfo *HostCheckInfo ) for _, host := range hosts { switch { case arg.GetB(ARG_QUIET): grade, _ = quietCheck(host) case arg.GetB(ARG_FORMAT): grade, checkInfo = quietCheck(host) checksInfo = append(checksInfo, checkInfo) default: grade = check(host) } switch { case arg.GetB(ARG_PERFECT) && grade != "A+": ok = false case grade[:1] != "A": ok = false } } if arg.GetB(ARG_FORMAT) { switch arg.GetS(ARG_FORMAT) { case FORMAT_TEXT: encodeAsText(checksInfo) case FORMAT_JSON: encodeAsJSON(checksInfo) case FORMAT_XML: encodeAsXML(checksInfo) case FORMAT_YAML: encodeAsYAML(checksInfo) default: os.Exit(1) } } if arg.GetB(ARG_NOTIFY) { fmtc.Bell() } if !ok { os.Exit(1) } }
// printGroupHeader print category header func printGroupHeader(name string) { fmtc.Printf("\n{*}%s{!}\n\n", name) }
// printError prints warning message to console func printWarn(f string, a ...interface{}) { fmtc.Printf("{y}"+f+"{!}\n", a...) }
// printError prints error message to console func printError(f string, a ...interface{}) { fmtc.Printf("{r}"+f+"{!}\n", a...) }
// renderMethod print variable info to console func renderVariable(v *Variable) { fmtc.Printf("{s-}%4d:{!} {c*}%s{!} {s}={!} %s "+getVarTypeDesc(v.Type)+"\n", v.Line, v.Name, v.Value) fmtc.Printf(" %s\n", v.UnitedDesc()) }
// renderConstant print constant info to console func renderConstant(c *Variable) { fmtc.Printf("{s-}%4d:{!} {m*}%s{!} {s}={!} %s "+getVarTypeDesc(c.Type)+"\n", c.Line, c.Name, c.Value) fmtc.Printf(" %s\n", c.UnitedDesc()) }
// printCertificationPathsInfo print info about certificates in chain func printCertificationPathsInfo(details *sslscan.EndpointDetails) { printCategoryHeader("Certification Paths") fmtc.Printf(" %-24s {s}|{!} %d\n", "Certificates provided", len(details.Chain.Certs)) fmtc.Printf(" %-24s {s}|{!} ", "Chain issues") if details.Chain.Issues == 0 { fmtc.Println("None") } else { fmtc.Printf("{y}%s{!}\n", getChainIssuesDesc(details.Chain.Issues)) } if len(details.Chain.Certs) > 1 { fmtutil.Separator(true) lastCertIndex := len(details.Chain.Certs) - 2 for index, cert := range details.Chain.Certs[1:] { validUntilDate := time.Unix(cert.NotAfter/1000, 0) fmtc.Printf(" %-24s {s}|{!} %s\n", "Subject", cert.Label) fmtc.Printf(" %-24s {s}|{!} %s\n", "Valid until", timeutil.Format(validUntilDate, "%Y/%m/%d %H:%M:%S")) fmtc.Printf(" %-24s {s}|{!} ", "Key") if cert.KeyAlg == "RSA" && cert.KeyStrength < 2048 { fmtc.Printf("{y}%s %d bits (WEAK){!}\n", cert.KeyAlg, cert.KeySize) } else { fmtc.Printf("%s %d bits\n", cert.KeyAlg, cert.KeySize) } fmtc.Printf(" %-24s {s}|{!} %s\n", "Issuer", cert.IssuerLabel) fmtc.Printf(" %-24s {s}|{!} ", "Signature algorithm") if weakAlgorithms[cert.SigAlg] { fmtc.Printf("{y}%s (WEAK){!}\n", cert.SigAlg) } else { fmtc.Printf("%s\n", cert.SigAlg) } if index < lastCertIndex { fmtutil.Separator(true) } } } }
// printCertificateInfo print basic info about server key and certificate func printCertificateInfo(details *sslscan.EndpointDetails) { printCategoryHeader("Server Key and Certificate") validFromDate := time.Unix(details.Cert.NotBefore/1000, 0) validUntilDate := time.Unix(details.Cert.NotAfter/1000, 0) // --- fmtc.Printf(" %-24s {s}|{!} %s\n", "Common names", strings.Join(details.Cert.CommonNames, " ")) if len(details.Cert.AltNames) > 0 { if len(details.Cert.AltNames) > 5 { fmtc.Printf( " %-24s {s}|{!} %s {s-}(+%d more){!}\n", "Alternative names", strings.Join(details.Cert.AltNames[:4], " "), len(details.Cert.AltNames)-4, ) } else { fmtc.Printf(" %-24s {s}|{!} %s\n", "Alternative names", strings.Join(details.Cert.AltNames, " ")) } } // --- fmtc.Printf(" %-24s {s}|{!} %s\n", "Valid from", timeutil.Format(validFromDate, "%Y/%m/%d %H:%M:%S")) // --- fmtc.Printf(" %-24s {s}|{!} ", "Valid until") if time.Now().Unix() >= validUntilDate.Unix() { fmtc.Printf("{r}%s (EXPIRED){!}\n", timeutil.Format(validUntilDate, "%Y/%m/%d %H:%M:%S")) } else { fmtc.Printf("%s\n", timeutil.Format(validUntilDate, "%Y/%m/%d %H:%M:%S")) } // --- fmtc.Printf(" %-24s {s}|{!} %s %d bits\n", "Key", details.Key.Alg, details.Key.Size) fmtc.Printf(" %-24s {s}|{!} %s\n", "Weak Key (Debian)", getBool(details.Key.DebianFlaw)) // --- fmtc.Printf(" %-24s {s}|{!} ", "Issuer") if details.Cert.Issues&64 == 64 { fmtc.Printf("%s {s-}(Self-signed){!}\n", details.Cert.IssuerLabel) } else { fmtc.Printf("%s\n", details.Cert.IssuerLabel) } // --- fmtc.Printf(" %-24s {s}|{!} ", "Signature algorithm") if weakAlgorithms[details.Cert.SigAlg] { fmtc.Printf("{y}%s (WEAK){!}\n", details.Cert.SigAlg) } else { fmtc.Printf("%s\n", details.Cert.SigAlg) } // --- fmtc.Printf(" %-24s {s}|{!} ", "Extended Validation") if details.Cert.ValidationType == "E" { fmtc.Println("{g}Yes{!}") } else { fmtc.Println("No") } // --- fmtc.Printf(" %-24s {s}|{!} ", "Certificate Transparency") if details.Cert.SCT { fmtc.Println("{g}Yes{!}") } else { fmtc.Println("No") } // --- if details.Cert.RevocationInfo != 0 { fmtc.Printf(" %-24s {s}|{!} %s\n", "Revocation information", getRevocationInfo(details.Cert.RevocationInfo)) } // --- fmtc.Printf(" %-24s {s}|{!} ", "Revocation status") if details.Cert.RevocationStatus&1 == 1 { fmtc.Printf("{r}%s{!}\n", getRevocationStatus(details.Cert.RevocationStatus)) } else { fmtc.Printf("%s\n", getRevocationStatus(details.Cert.RevocationStatus)) } // --- fmtc.Printf(" %-24s {s}|{!} ", "Trusted") if details.Cert.Issues == 0 { fmtc.Println("{g}Yes{!}") } else { fmtc.Printf("{r}No (%s){!}\n", getCertIssuesDesc(details.Cert.Issues)) } }
// printCategoryHeader print category name and separators func printCategoryHeader(name string) { fmtutil.Separator(true) fmtc.Printf(" ▾ {*}%s{!}\n", strings.ToUpper(name)) fmtutil.Separator(true) }
// PrintActionMessage print message about action currently in progress func PrintActionMessage(message string) { fmtc.Printf("{*}%s:{!} ", message) }
// printProtocolDetailsInfo print endpoint protocol details func printProtocolDetailsInfo(details *sslscan.EndpointDetails) { printCategoryHeader("Protocol Details") // --- fmtc.Printf(" %-40s {s}|{!} ", "Secure Renegotiation") if details.RenegSupport&1 == 1 { fmtc.Println("{y}Not supported{!}") } else { fmtc.Println("{g}Supported{!}") } // --- fmtc.Printf(" %-40s {s}|{!} ", "Secure Client-Initiated Renegotiation") if details.RenegSupport&4 == 4 { fmtc.Println("{y}Supported (DoS DANGER){!}") } else { fmtc.Println("No") } // --- fmtc.Printf(" %-40s {s}|{!} ", "Insecure Client-Initiated Renegotiation") if details.RenegSupport&1 == 1 { fmtc.Println("{r}Supported (INSECURE){!}") } else { fmtc.Println("No") } // --- fmtc.Printf(" %-40s {s}|{!} ", "POODLE (SSLv3)") if details.Poodle { fmtc.Println("{r}Vulnerable (INSECURE){!}") } else { fmtc.Println("No") } // --- fmtc.Printf(" %-40s {s}|{!} ", "POODLE (TLS)") if details.PoodleTLS == 2 { fmtc.Println("{r}Vulnerable (INSECURE){!}") } else { fmtc.Println("No") } // --- fmtc.Printf(" %-40s {s}|{!} ", "DROWN") if details.DrownVulnerable { fmtc.Println("{r}Vulnerable{!}") } else { fmtc.Println("No") } // --- if details.Logjam { fmtc.Printf(" %-40s {s}|{!} {r}Vulnerable{!}\n", "Logjam") } // --- if details.Freak { fmtc.Printf(" %-40s {s}|{!} {r}Vulnerable{!}\n", "Freak") } // --- fmtc.Printf(" %-40s {s}|{!} ", "Downgrade attack prevention") if !details.FallbackSCSV { fmtc.Println("{y}No, TLS_FALLBACK_SCSV not supported{!}") } else { fmtc.Println("{g}Yes, TLS_FALLBACK_SCSV supported{!}") } // --- fmtc.Printf(" %-40s {s}|{!} ", "SSL/TLS compression") if details.CompressionMethods != 0 { fmtc.Println("{r}Vulnerable (INSECURE){!}") } else { fmtc.Println("No") } // --- fmtc.Printf(" %-40s {s}|{!} ", "RC4") if details.SupportsRC4 { fmtc.Println("{r}Yes (INSECURE){!}") } else { fmtc.Println("No") } // --- fmtc.Printf(" %-40s {s}|{!} %s\n", "Heartbeat (extension)", getBool(details.Heartbeat)) // --- fmtc.Printf(" %-40s {s}|{!} ", "Heartbleed (vulnerability)") if details.Heartbleed { fmtc.Println("{r}Vulnerable (INSECURE){!}") } else { fmtc.Println("No") } // --- fmtc.Printf(" %-40s {s}|{!} ", "OpenSSL CCS vuln.") switch details.OpenSslCCS { case -1: fmtc.Println("{y}Test failed{!}") case 0: fmtc.Println("{y}Unknown{!}") case 1: fmtc.Println("No") case 2: fmtc.Println("{y}Possibly vulnerable, but not exploitable{!}") case 3: fmtc.Println("{r}Vulnerable and exploitable{!}") } // --- fmtc.Printf(" %-40s {s}|{!} ", "OpenSSL Padding Oracle vuln.") switch details.OpenSSLLuckyMinus20 { case -1: fmtc.Println("{y}Test failed{!}") case 0: fmtc.Println("{y}Unknown{!}") case 1: fmtc.Println("No") case 2: fmtc.Println("{r}Vulnerable and insecure{!}") } // --- fmtc.Printf(" %-40s {s}|{!} ", "Forward Secrecy") switch { case details.ForwardSecrecy == 0: fmtc.Println("{y}No (WEAK){!}") case details.ForwardSecrecy&1 == 1: fmtc.Println("{y}With some browsers{!}") case details.ForwardSecrecy&2 == 2: fmtc.Println("With modern browsers") case details.ForwardSecrecy&4 == 4: fmtc.Println("{g}Yes (with most browsers) (ROBUST){!}") } // --- fmtc.Printf(" %-40s {s}|{!} ", "Application-Layer Protocol Negotiation") if strings.Contains(details.NPNProtocols, "h2") { fmtc.Println("Yes") } else { fmtc.Println("No") } // --- fmtc.Printf(" %-40s {s}|{!} ", "Next Protocol Negotiation") if details.SupportsNPN { fmtc.Printf("Yes {s-}(%s){!}\n", details.NPNProtocols) } else { fmtc.Println("No") } // --- fmtc.Printf(" %-40s {s}|{!} ", "Session resumption (caching)") switch details.SessionResumption { case 0: fmtc.Println("{y}No (Session resumption is not enabled){!}") case 1: fmtc.Println("{y}No (IDs assigned but not accepted){!}") case 2: fmtc.Println("Yes") } // --- fmtc.Printf(" %-40s {s}|{!} %s\n", "Session resumption (tickets)", getBool(details.SessionTickets&1 == 1)) // --- fmtc.Printf(" %-40s {s}|{!} ", "OCSP stapling") if details.OCSPStapling { fmtc.Println("{g}Yes{!}") } else { fmtc.Println("No") } // --- fmtc.Printf(" %-40s {s}|{!} ", "Strict Transport Security (HSTS)") if details.HSTSPolicy != nil && details.HSTSPolicy.Status == sslscan.HSTS_STATUS_PRESENT { fmtc.Printf("{g}Yes{!} {s-}(%s){!}\n", details.HSTSPolicy.Header) if len(details.HSTSPreloads) != 0 { fmtc.Printf(" %-40s {s}|{!} ", "HSTS Preloading") fmtc.Println(getHSTSPreloadingMarkers(details.HSTSPreloads)) } } else { fmtc.Println("No") } // --- fmtc.Printf(" %-40s {s}|{!} ", "Public Key Pinning (HPKP)") if details.HPKPPolicy != nil { switch details.HPKPPolicy.Status { case sslscan.HPKP_STATUS_INVALID: fmtc.Println("{r}Invalid{!}") case sslscan.HPKP_STATUS_DISABLED: fmtc.Println("{y}Disabled{!}") case sslscan.HPKP_STATUS_INCOMPLETE: fmtc.Println("{y}Incomplete{!}") case sslscan.HPKP_STATUS_VALID: fmtc.Printf("{g}Yes{!} ") if details.HPKPPolicy.IncludeSubDomains { fmtc.Printf( "{s-}(max-age=%d; includeSubdomains){!}\n", details.HPKPPolicy.MaxAge, ) } else { fmtc.Printf( "{s-}(max-age=%d){!}\n", details.HPKPPolicy.MaxAge, ) } for _, pin := range getPinsFromPolicy(details.HPKPPolicy) { fmtc.Printf(" %-40s {s}|{!} {s-}%s{!}\n", "", pin) } default: fmtc.Println("No") } } else { fmtc.Println("No") } // --- fmtc.Printf(" %-40s {s}|{!} ", "Long handshake intolerance") if details.MiscIntolerance&2 == 2 { fmtc.Println("{y}Yes{!}") } else if details.MiscIntolerance&4 == 4 { fmtc.Println("{y}Yes{!} {s-}(workaround success){!}") } else { fmtc.Println("No") } // --- fmtc.Printf(" %-40s {s}|{!} ", "TLS extension intolerance") if details.MiscIntolerance&1 == 1 { fmtc.Println("{y}Yes{!}") } else { fmtc.Println("No") } // --- fmtc.Printf(" %-40s {s}|{!} ", "TLS version intolerance") if details.ProtocolIntolerance != 0 { fmtc.Printf("{y}%s{!}\n", getProtocolIntolerance(details.ProtocolIntolerance)) } else { fmtc.Println("No") } // --- fmtc.Printf(" %-40s {s}|{!} ", "Uses common DH primes") if details.DHUsesKnownPrimes != 0 { fmtc.Println("{y}Yes (Replace with custom DH parameters if possible){!}") } else { fmtc.Println("No") } // --- fmtc.Printf(" %-40s {s}|{!} ", "DH public server param (Ys) reuse") if details.DHYsReuse { fmtc.Println("{y}Yes{!}") } else { fmtc.Println("No") } }