163 lines
3.4 KiB
Go
163 lines
3.4 KiB
Go
package inspect
|
|
|
|
import (
|
|
"context"
|
|
"crypto/tls"
|
|
"errors"
|
|
"net"
|
|
"net/url"
|
|
"os"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/mattn/go-isatty"
|
|
"github.com/spf13/cobra"
|
|
"src.lwithers.me.uk/go/rsa/pkg/inspect"
|
|
)
|
|
|
|
var (
|
|
outputFormat string = "text"
|
|
display func(src string, info []inspect.Info)
|
|
)
|
|
|
|
// Register the "keygen" subcommand.
|
|
func Register(root *cobra.Command) {
|
|
cmd := &cobra.Command{
|
|
Use: "inspect",
|
|
Short: "Inspect files and TLS servers",
|
|
RunE: Inspect,
|
|
Args: cobra.MinimumNArgs(1),
|
|
}
|
|
|
|
if isatty.IsTerminal(1) {
|
|
outputFormat = "coloured"
|
|
}
|
|
|
|
cmd.Flags().StringVarP(&outputFormat, "output", "o", outputFormat,
|
|
"Output format (coloured, text, json, yaml)")
|
|
|
|
root.AddCommand(cmd)
|
|
}
|
|
|
|
// Keygen will generate a new RSA private key and save it to a file.
|
|
func Inspect(cmd *cobra.Command, args []string) error {
|
|
switch outputFormat {
|
|
case "coloured":
|
|
display = displayColoured
|
|
case "text":
|
|
display = displayText
|
|
case "json":
|
|
display = displayJSON
|
|
case "yaml":
|
|
display = displayYAML
|
|
default:
|
|
return errors.New("invalid --output format (try: coloured, text, json or yaml)")
|
|
}
|
|
|
|
for _, arg := range args {
|
|
switch {
|
|
case arg == "-":
|
|
inspectStdin()
|
|
|
|
case strings.HasPrefix(arg, "https://"):
|
|
inspectHTTPS(arg)
|
|
|
|
case strings.IndexByte(arg, ':') != 0:
|
|
_, _, err := net.SplitHostPort(arg)
|
|
if err == nil {
|
|
inspectHost(arg)
|
|
break
|
|
}
|
|
fallthrough
|
|
|
|
default:
|
|
inspectFile(arg)
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func inspectStdin() {
|
|
// TODO
|
|
}
|
|
|
|
func inspectHTTPS(addr string) {
|
|
u, err := url.Parse(addr)
|
|
if err != nil {
|
|
// TODO
|
|
}
|
|
|
|
inspectHost(u.Host)
|
|
// TODO: need to add default port
|
|
}
|
|
|
|
func inspectHost(addr string) {
|
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
|
defer cancel()
|
|
|
|
// TODO: context dial
|
|
|
|
conn, err := tls.Dial("tcp", addr, &tls.Config{
|
|
// we want to skip verification so we can inspect invalid certs too
|
|
InsecureSkipVerify: true,
|
|
|
|
// we only enable RSA ciphersuites, but we do allow old ones, again
|
|
// so that we can report about bad / invalid servers
|
|
CipherSuites: []uint16{
|
|
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,
|
|
tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA,
|
|
tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
|
|
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,
|
|
tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
|
|
tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
|
|
tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
|
|
tls.TLS_AES_128_GCM_SHA256,
|
|
tls.TLS_AES_256_GCM_SHA384,
|
|
tls.TLS_CHACHA20_POLY1305_SHA256,
|
|
},
|
|
|
|
// we enable TLSv1.0 so that we can complain about it
|
|
MinVersion: tls.VersionTLS10,
|
|
})
|
|
if err != nil {
|
|
// TODO
|
|
}
|
|
|
|
if err := conn.HandshakeContext(ctx); err != nil {
|
|
// TODO
|
|
}
|
|
|
|
display(addr, inspect.ConnectionState(conn.ConnectionState()))
|
|
}
|
|
|
|
func inspectFile(filename string) {
|
|
raw, err := os.ReadFile(filename)
|
|
if err != nil {
|
|
// TODO
|
|
}
|
|
|
|
info := inspect.LoadPEM(raw)
|
|
if len(info) == 0 {
|
|
// TODO
|
|
}
|
|
|
|
display(filename, info)
|
|
}
|
|
|
|
func displayText(src string, info []inspect.Info) {
|
|
}
|
|
|
|
func displayJSON(src string, info []inspect.Info) {
|
|
}
|
|
|
|
func displayYAML(src string, info []inspect.Info) {
|
|
}
|