diff --git a/cmd/tlshandshake/tlshandshake.go b/cmd/tlshandshake/tlshandshake.go new file mode 100644 index 0000000..ddf045a --- /dev/null +++ b/cmd/tlshandshake/tlshandshake.go @@ -0,0 +1,69 @@ +package main + +import ( + "errors" + "flag" + "os" + "strings" + + hs "github.com/henrydcase/tlshandshake" + trs "github.com/henrydcase/trs" +) + +func getIDByName(m map[uint16]string, name string) (uint16, error) { + for key, value := range m { + if value == name { + return key, nil + } + } + return 0, errors.New("Unknown value") +} + +// Usage client args host:port +func main() { + var tls_version, named_groups, named_ciphers string + + flag.StringVar(&tls_version, "tls_version", "1.3", "TLS version to use") + flag.StringVar(&named_groups, "groups", "X25519:P-256:P-384:P-521", "NamedGroups IDs to use") + flag.StringVar(&named_ciphers, "ciphers", "TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384", "Named cipher IDs to use") + flag.Parse() + if flag.NArg() != 1 { + flag.Usage() + os.Exit(1) + } + + client := hs.NewClient() + client.Addr = flag.Arg(0) + if !strings.Contains(client.Addr, ":") { + client.Addr += ":443" + } + + // Set requested DH groups + client.TLS.CurvePreferences = []trs.CurveID{} + for _, ng := range strings.Split(named_groups, ":") { + id, err := getIDByName(hs.NamedGroupsToName, ng) + if err != nil { + panic("Wrong group name provided") + } + client.TLS.CurvePreferences = append(client.TLS.CurvePreferences, trs.CurveID(id)) + } + + // Perform TLS handshake with each each requested CipherSuite + tlsID, err := getIDByName(hs.TlsVersionToName, tls_version) + if err != nil { + panic("Unknown TLS version") + } + + cn := strings.Split(named_ciphers, ":") + if len(cn) == 0 { + panic("Cipher can't be null") + } + + id, err := getIDByName(hs.CipherSuiteIdToName, cn[0]) + if err != nil { + panic("Wrong cipher name provided") + } + client.SetMinMaxTLS(tlsID) + client.TLS.CipherSuites = []uint16{id} + client.Run() +} diff --git a/lib.go b/lib.go new file mode 100644 index 0000000..043f0b5 --- /dev/null +++ b/lib.go @@ -0,0 +1,71 @@ +package tlshandshake + +import ( + "fmt" + + trs "github.com/henrydcase/trs" +) + +var TlsVersionToName = map[uint16]string{ + trs.VersionTLS10: "1.0", + trs.VersionTLS11: "1.1", + trs.VersionTLS12: "1.2", + trs.VersionTLS13: "1.3", +} + +var CipherSuiteIdToName = map[uint16]string{ + trs.TLS_RSA_WITH_AES_128_CBC_SHA: "TLS_RSA_WITH_AES_128_CBC_SHA", + trs.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256: "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", + trs.TLS_AES_128_GCM_SHA256: "TLS_AES_128_GCM_SHA256", + trs.TLS_AES_256_GCM_SHA384: "TLS_AES_256_GCM_SHA384", + trs.TLS_CHACHA20_POLY1305_SHA256: "TLS_CHACHA20_POLY1305_SHA256", +} + +var NamedGroupsToName = map[uint16]string{ + uint16(trs.HybridSIDHp503Curve25519): "X25519-SIDHp503", + uint16(trs.HybridSIKEp503Curve25519): "X25519-SIKEp503", + uint16(trs.X25519): "X25519", + uint16(trs.CurveP256): "P-256", + uint16(trs.CurveP384): "P-384", + uint16(trs.CurveP521): "P-521", +} + +var failed uint + +type Client struct { + TLS trs.Config + Addr string +} + +func NewClient() *Client { + var c Client + c.TLS.InsecureSkipVerify = true + return &c +} + +func (c *Client) Run() { + fmt.Printf("TLS %s with %s\n", TlsVersionToName[c.TLS.MinVersion], CipherSuiteIdToName[c.TLS.CipherSuites[0]]) + + con, err := trs.Dial("tcp", c.Addr, &c.TLS) + if err != nil { + fmt.Printf("handshake failed: %v\n\n", err) + failed++ + return + } + defer con.Close() + + fmt.Printf("[TLS: %s]\n", TlsVersionToName[con.ConnectionState().Version]) + fmt.Println("OK\n") +} + +func (c *Client) Clone() *Client { + var clone Client + clone.TLS = *c.TLS.Clone() + clone.Addr = c.Addr + return &clone +} + +func (c *Client) SetMinMaxTLS(ver uint16) { + c.TLS.MinVersion = ver + c.TLS.MaxVersion = ver +}