Print connection information

This commit is contained in:
Henry Case 2019-05-12 19:06:55 +01:00
parent ea34fe6e16
commit 4837945b4d
4 changed files with 214 additions and 43 deletions

View File

@ -7,7 +7,85 @@
Example: Example:
``` ```
./tlshandshake www.fbi.com:443 -cipher X25519:P256:CECPQ2 > go run cmd/tlshandshake/tlshandshake.go -tls_min 1.2 -tls_max 1.3 -groups X25519-SIDHp503 pqcrypto.uk
| TLS-Session:
-----------------------------------------------------------------
Protocol : 1.3
Cipher : TLS_AES_128_GCM_SHA256
Negotiated Group : X25519-SIDHp503
Connection ID : d0129f4dea986b72
SCTs : []
Connection resumed : FALSE
EMS used : FALSE
Stapled OCSP response : 308201350a0100a082012e3082012a06092b0601...
| Connection:
-----------------------------------------------------------------
Local address : 10.0.1.242:51536
Remote address : 198.41.214.162:443
| Server Certificates:
-----------------------------------------------------------------
Depth : 0
Issuer : CN=DigiCert ECC Extended Validation Server CA,OU=www.digicert.com,O=DigiCert Inc,C=US
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 13836083707412516537413894398330316720 (0xa68bb984a507399f4716e809a44a7b0)
Signature Algorithm: ECDSA-SHA256
Issuer: C=US,O=DigiCert Inc,OU=www.digicert.com,CN=DigiCert ECC Extended Validation Server CA
Validity
Not Before: Oct 30 00:00:00 2018 UTC
Not After : Nov 3 12:00:00 2020 UTC
Subject: UnknownOID=2.5.4.15,UnknownOID=1.3.6.1.4.1.311.60.2.1.3,UnknownOID=1.3.6.1.4.1.311.60.2.1.2,UnknownOID=2.5.4.5,C=US,ST=California,UnknownOID=2.5.4.7,O=Cloudflare, Inc.,CN=cloudflare.com
Subject Public Key Info:
Public Key Algorithm: ECDSA
Public-Key: (256 bit)
X:
ce:d7:61:49:49:fd:4b:35:8b:1b:86:bc:a3:c5:bc:
d8:20:6e:31:17:2d:92:8a:b7:34:f4:db:11:70:4e:
49:16
Y:
61:fc:ae:fa:7f:ba:6f:0c:05:53:74:c6:79:7f:81:
12:8a:f7:e2:5e:6c:f5:fa:10:69:6b:67:d9:d5:96:
51:b0
Curve: P-256
X509v3 extensions:
X509v3 Authority Key Identifier:
keyid:F8:25:D9:A6:39:C7:C3:81:87:25:3E:30:54:91:18:21:40:9B:17:9D
X509v3 Subject Key Identifier:
DE:7F:7F:E6:7C:ED:ED:61:43:60:47:67:5D:86:2F:84:FD:A6:78:AD
X509v3 Subject Alternative Name:
DNS:cloudflare.com, DNS:www.cloudflare.com
X509v3 Key Usage: critical
Digital Signature
X509v3 Extended Key Usage:
TLS Web Server Authentication, TLS Web Client Authentication
X509v3 CRL Distribution Points:
Full Name:
URI:http://crl3.digicert.com/DigiCertECCExtendedValidationServerCA.crl, URI:http://crl4.digicert.com/DigiCertECCExtendedValidationServerCA.crl
X509v3 Certificate Policies:
Policy: 2.16.840.1.114412.2.1
Policy: 2.23.140.1.1
Authority Information Access:
OCSP - URI:http://ocsp.digicert.com
CA Issuers - URI:http://cacerts.digicert.com/DigiCertECCExtendedValidationServerCA.crt
X509v3 Basic Constraints: critical
CA:FALSE
Unknown extension 1.3.6.1.4.1.11129.2.4.2
Signature Algorithm: ECDSA-SHA256
30:65:02:30:1e:1b:3d:10:9a:50:23:2e:e6:86:11:13:46:a8:
1d:e8:63:f8:2f:60:96:43:49:0a:49:30:73:55:f8:25:63:1d:
46:59:da:a9:4b:98:68:99:3d:50:a8:c4:fc:52:0f:e3:02:31:
00:d2:64:cc:ad:f8:92:b6:6b:fe:b7:a9:4e:8c:06:3b:fb:d3:
08:9f:d9:04:10:80:b9:52:97:0a:14:24:a4:5a:8a:d7:27:3c:
1e:86:cb:b7:a8:be:c3:c0:98:fa:4a:91:ae
``` ```
# Installation # Installation

View File

@ -3,13 +3,27 @@ package main
import ( import (
"errors" "errors"
"flag" "flag"
"fmt"
"os" "os"
"path"
"strings" "strings"
hs "github.com/henrydcase/tlshandshake" hs "github.com/henrydcase/tlshandshake"
trs "github.com/henrydcase/trs" "github.com/henrydcase/trs"
) )
var tls_min, tls_max, named_groups, named_ciphers string
var dst_port string
// Parse flags
func init() {
flag.StringVar(&tls_min, "tls_min", "1.0", "TLS version to use - minimal")
flag.StringVar(&tls_max, "tls_max", "1.3", "TLS version to use - maximal")
flag.StringVar(&named_groups, "groups", "", "ECDH group name to use for KEX")
flag.StringVar(&named_ciphers, "ciphers", "", "Named cipher IDs to use")
flag.StringVar(&dst_port, "port", "443", "Destination port number")
}
func getIDByName(m map[uint16]string, name string) (uint16, error) { func getIDByName(m map[uint16]string, name string) (uint16, error) {
for key, value := range m { for key, value := range m {
if value == name { if value == name {
@ -19,51 +33,68 @@ func getIDByName(m map[uint16]string, name string) (uint16, error) {
return 0, errors.New("Unknown value") return 0, errors.New("Unknown value")
} }
func usage() {
fmt.Fprintf(os.Stderr, "usage: %s [options] server:port\n", path.Base(os.Args[0]))
fmt.Fprintf(os.Stderr, "Flags:\n")
flag.PrintDefaults()
os.Exit(2)
}
// Usage client args host:port // Usage client args host:port
func main() { func main() {
var tls_version, named_groups, named_ciphers string
flag.StringVar(&tls_version, "tls_version", "1.3", "TLS version to use") // parse flags
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() flag.Parse()
if flag.NArg() != 1 { if flag.NArg() != 1 {
flag.Usage() usage()
os.Exit(1)
} }
client := hs.NewClient() client := hs.NewClient()
client.Addr = flag.Arg(0) client.Addr = flag.Arg(0)
if !strings.Contains(client.Addr, ":") { if !strings.Contains(client.Addr, ":") {
client.Addr += ":443" client.Addr += ":" + dst_port
} }
// Set requested DH groups // Set requested DH groups
client.TLS.CurvePreferences = []trs.CurveID{} client.TLS.CurvePreferences = []trs.CurveID{}
for _, ng := range strings.Split(named_groups, ":") { if len(named_groups) != 0 {
id, err := getIDByName(hs.NamedGroupsToName, ng) for _, ng := range strings.Split(named_groups, ":") {
if err != nil { id, err := getIDByName(hs.NamedGroupsToName, ng)
panic("Wrong group name provided") if err != nil {
panic("Wrong group name provided")
}
client.TLS.CurvePreferences = append(client.TLS.CurvePreferences, trs.CurveID(id))
} }
client.TLS.CurvePreferences = append(client.TLS.CurvePreferences, trs.CurveID(id))
} }
// Perform TLS handshake with each each requested CipherSuite // TLS min
tlsID, err := getIDByName(hs.TlsVersionToName, tls_version) tlsID, err := getIDByName(hs.TlsVersionToName, tls_min)
if err != nil { if err != nil {
panic("Unknown TLS version") panic("Unknown TLS version")
} }
client.TLS.MinVersion = tlsID
// TLS max
tlsID, err = getIDByName(hs.TlsVersionToName, tls_max)
if err != nil {
panic("Unknown TLS version")
}
client.TLS.MaxVersion = tlsID
cn := strings.Split(named_ciphers, ":") cn := strings.Split(named_ciphers, ":")
if len(cn) == 0 { if len(cn) == 0 {
panic("Cipher can't be null") panic("Cipher can't be null")
} }
id, err := getIDByName(hs.CipherSuiteIdToName, cn[0]) if len(named_ciphers) != 0 {
if err != nil { id, err := getIDByName(hs.CipherSuiteIdToName, cn[0])
panic("Wrong cipher name provided") if err != nil {
panic("Wrong cipher name provided")
}
client.TLS.CipherSuites = []uint16{id}
} }
client.SetMinMaxTLS(tlsID)
client.TLS.CipherSuites = []uint16{id} client.TLS.InsecureSkipVerify = true
// Let's go
client.Run() client.Run()
} }

53
lib.go
View File

@ -2,10 +2,16 @@ package tlshandshake
import ( import (
"fmt" "fmt"
"os"
trs "github.com/henrydcase/trs" "github.com/henrydcase/trs"
) )
type Client struct {
TLS trs.Config
Addr string
}
var TlsVersionToName = map[uint16]string{ var TlsVersionToName = map[uint16]string{
trs.VersionTLS10: "1.0", trs.VersionTLS10: "1.0",
trs.VersionTLS11: "1.1", trs.VersionTLS11: "1.1",
@ -14,11 +20,31 @@ var TlsVersionToName = map[uint16]string{
} }
var CipherSuiteIdToName = map[uint16]string{ 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_128_GCM_SHA256: "TLS_AES_128_GCM_SHA256",
trs.TLS_AES_256_GCM_SHA384: "TLS_AES_256_GCM_SHA384", trs.TLS_AES_256_GCM_SHA384: "TLS_AES_256_GCM_SHA384",
trs.TLS_CHACHA20_POLY1305_SHA256: "TLS_CHACHA20_POLY1305_SHA256", trs.TLS_CHACHA20_POLY1305_SHA256: "TLS_CHACHA20_POLY1305_SHA256",
trs.TLS_RSA_WITH_RC4_128_SHA: "TLS_RSA_WITH_RC4_128_SHA",
trs.TLS_RSA_WITH_3DES_EDE_CBC_SHA: "TLS_RSA_WITH_3DES_EDE_CBC_SHA",
trs.TLS_RSA_WITH_AES_128_CBC_SHA: "TLS_RSA_WITH_AES_128_CBC_SHA",
trs.TLS_RSA_WITH_AES_256_CBC_SHA: "TLS_RSA_WITH_AES_256_CBC_SHA",
trs.TLS_RSA_WITH_AES_128_CBC_SHA256: "TLS_RSA_WITH_AES_128_CBC_SHA256",
trs.TLS_RSA_WITH_AES_128_GCM_SHA256: "TLS_RSA_WITH_AES_128_GCM_SHA256",
trs.TLS_RSA_WITH_AES_256_GCM_SHA384: "TLS_RSA_WITH_AES_256_GCM_SHA384",
trs.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA: "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA",
trs.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA: "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA",
trs.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA: "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA",
trs.TLS_ECDHE_RSA_WITH_RC4_128_SHA: "TLS_ECDHE_RSA_WITH_RC4_128_SHA",
trs.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA: "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA",
trs.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA: "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA",
trs.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA: "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA",
trs.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256: "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256",
trs.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256: "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256",
trs.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256: "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
trs.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256: "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
trs.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384: "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
trs.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384: "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
trs.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305: "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305",
trs.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305: "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305",
} }
var NamedGroupsToName = map[uint16]string{ var NamedGroupsToName = map[uint16]string{
@ -30,13 +56,6 @@ var NamedGroupsToName = map[uint16]string{
uint16(trs.CurveP521): "P-521", uint16(trs.CurveP521): "P-521",
} }
var failed uint
type Client struct {
TLS trs.Config
Addr string
}
func NewClient() *Client { func NewClient() *Client {
var c Client var c Client
c.TLS.InsecureSkipVerify = true c.TLS.InsecureSkipVerify = true
@ -44,18 +63,13 @@ func NewClient() *Client {
} }
func (c *Client) Run() { 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) con, err := trs.Dial("tcp", c.Addr, &c.TLS)
if err != nil { if err != nil {
fmt.Printf("handshake failed: %v\n\n", err) fmt.Printf("handshake failed: %v\n\n", err)
failed++ os.Exit(1)
return
} }
defer con.Close() defer con.Close()
printTlsState(con)
fmt.Printf("[TLS: %s]\n", TlsVersionToName[con.ConnectionState().Version])
fmt.Println("OK\n")
} }
func (c *Client) Clone() *Client { func (c *Client) Clone() *Client {
@ -64,8 +78,3 @@ func (c *Client) Clone() *Client {
clone.Addr = c.Addr clone.Addr = c.Addr
return &clone return &clone
} }
func (c *Client) SetMinMaxTLS(ver uint16) {
c.TLS.MinVersion = ver
c.TLS.MaxVersion = ver
}

53
utils.go Normal file
View File

@ -0,0 +1,53 @@
package tlshandshake
import (
"encoding/hex"
"fmt"
"github.com/grantae/certinfo"
trs "github.com/henrydcase/trs"
)
var tf = map[bool]string{
true: "TRUE",
false: "FALSE",
}
func toHex(b []byte) string {
str := make([]byte, hex.EncodedLen(len(b)))
hex.Encode(str, b[:])
return string(str)
}
func printTlsState(con *trs.Conn) {
state := con.ConnectionState()
fmt.Println("| TLS-Session:")
fmt.Println("-----------------------------------------------------------------")
fmt.Printf("\tProtocol\t\t: %s\n", TlsVersionToName[state.Version])
fmt.Printf("\tCipher\t\t\t: %s\n", CipherSuiteIdToName[state.CipherSuite])
fmt.Printf("\tNegotiated Group\t: %s\n", NamedGroupsToName[uint16(state.Group)])
fmt.Printf("\tConnection ID\t\t: %s\n", toHex(state.ConnectionID))
fmt.Printf("\tSCTs\t\t\t: %s\n", state.SignedCertificateTimestamps)
fmt.Printf("\tConnection resumed\t: %s\n", tf[state.DidResume])
//fmt.Printf("\tNext protocol\t\t: %s\n", state.NegotiatedProtocol)
fmt.Printf("\tEMS used\t\t: %s\n", tf[con.UsedEMS()])
fmt.Printf("\tStapled OCSP response\t: %s\n", toHex(state.OCSPResponse))
fmt.Println("\n| Connection:")
fmt.Println("-----------------------------------------------------------------")
fmt.Printf("\tLocal address\t\t: %s\n", con.LocalAddr())
fmt.Printf("\tRemote address\t\t: %s\n", con.RemoteAddr())
fmt.Println("\n| Server Certificates:")
fmt.Println("-----------------------------------------------------------------")
for i, cert := range state.PeerCertificates {
fmt.Printf("Depth : %d\n", i)
fmt.Printf("Issuer : %s\n", cert.Issuer)
res, err := certinfo.CertificateText(cert)
if err != nil {
panic("Error parsing received server certificate")
}
fmt.Println(res)
}
}