// PrintActionStatus print message with action execution status func PrintActionStatus(status int) { switch status { case 0: fmtc.Println("{g}OK{!}") case 1: fmtc.Println("{r}ERROR{!}") } }
// 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 }
// showServerMessage show message from SSL Labs API func showServerMessage() { serverMessage := strings.Join(api.Info.Messages, " ") wrappedMessage := fmtutil.Wrap(serverMessage, "", 80) var coloredMessage string for _, line := range strings.Split(wrappedMessage, "\n") { coloredMessage += "{s-}" + line + "{!}\n" } fmtc.NewLine() fmtc.Println(coloredMessage) }
// Separator print separator to output func Separator(tiny bool, args ...string) { sep := SeparatorColorTag + _SEPARATOR + "{!}" if len(args) != 0 { name := args[0] sep = SeparatorColorTag + "-- {!}" + SeparatorTitleColorTag + name + "{!} " + SeparatorColorTag + _SEPARATOR[:(84-len(name))] + "{!}" } if !tiny { sep = "\n" + sep + "\n" } fmtc.Println(sep) }
// 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])) } } }
// Render print usage info to console func (info *Info) Render() { usageMessage := "\n{*}Usage:{!} " + info.name if len(info.commands) != 0 { usageMessage += " " + CommandsColorTag + "{command}{!}" } if len(info.options) != 0 { usageMessage += " " + OptionsColorTag + "{options}{!}" } if info.args != "" { usageMessage += " " + info.args } fmtc.Println(usageMessage) if info.spoiler != "" { fmtc.NewLine() fmtc.Println(info.spoiler) } if len(info.commands) != 0 { renderOptions(info.commands, CommandsColorTag) } if len(info.options) != 0 { renderOptions(info.options, OptionsColorTag) } if len(info.examples) != 0 { renderExamples(info) } fmtc.NewLine() }
// 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) } } } }
// 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) } } }
// 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 }
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() } }
// 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)) } }
// 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") } }