rsa/cmd/inspect/inspect.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) {
}