// Copyright (c) 2021 VMware, Inc. or its affiliates. All Rights Reserved.
// Copyright (c) 2012-2021, Sean Treadway, SoundCloud Ltd.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package amqp091

import (
	"crypto/tls"
	"crypto/x509"
	"errors"
	"fmt"
	"net"
	"testing"
	"time"
)

func tlsServerConfig(t *testing.T) *tls.Config {
	t.Helper()

	cfg := new(tls.Config)

	cfg.ClientCAs = x509.NewCertPool()
	cfg.ClientCAs.AppendCertsFromPEM([]byte(caCert))

	cert, err := tls.X509KeyPair([]byte(serverCert), []byte(serverKey))
	if err != nil {
		t.Fatalf("TLS server config error: %+v", err)
	}

	cfg.Certificates = append(cfg.Certificates, cert)
	cfg.ClientAuth = tls.RequireAndVerifyClientCert

	return cfg
}

func tlsClientConfig(t *testing.T) *tls.Config {
	t.Helper()

	cfg := new(tls.Config)
	cfg.RootCAs = x509.NewCertPool()
	cfg.RootCAs.AppendCertsFromPEM([]byte(caCert))

	cert, err := tls.X509KeyPair([]byte(clientCert), []byte(clientKey))
	if err != nil {
		t.Fatalf("TLS client config error: %+v", err)
	}

	cfg.Certificates = append(cfg.Certificates, cert)

	return cfg
}

type tlsServer struct {
	net.Listener
	URL      string
	Config   *tls.Config
	Sessions chan *server
}

// Captures the header for each accepted connection
func (s *tlsServer) Serve(t *testing.T) {
	t.Helper()

	for {
		c, err := s.Accept()
		if err != nil {
			return
		}
		s.Sessions <- newServer(t, c, c)
	}
}

func startTLSServer(t *testing.T, cfg *tls.Config) tlsServer {
	t.Helper()

	l, err := tls.Listen("tcp", "127.0.0.1:0", cfg)
	if err != nil {
		t.Fatalf("TLS server Listen error: %+v", err)
	}

	s := tlsServer{
		Listener: l,
		Config:   cfg,
		URL:      fmt.Sprintf("amqps://%s/", l.Addr().String()),
		Sessions: make(chan *server),
	}
	go s.Serve(t)

	return s
}

func TestTlsConfigFromUriPushdownServerNameIndication(t *testing.T) {
	uri := "amqps://user:pass@example.com:5671?server_name_indication=another-hostname.com"
	parsedUri, err := ParseURI(uri)
	if err != nil {
		t.Fatalf("expected to parse URI successfully, got error: %s", err)
	}

	tlsConf, err := tlsConfigFromURI(parsedUri)
	if err != nil {
		t.Fatalf("expected tlsConfigFromURI to succeed, got error: %s", err)
	}

	const expectedServerName = "another-hostname.com"
	if tlsConf.ServerName != expectedServerName {
		t.Fatalf("expected tlsConf server name to equal Uri servername: want %s, got %s", expectedServerName, tlsConf.ServerName)
	}
}

// Tests opening a connection of a TLS enabled socket server
func TestTLSHandshake(t *testing.T) {
	srv := startTLSServer(t, tlsServerConfig(t))
	defer srv.Close()

	success := make(chan bool)
	errs := make(chan error, 3)

	go func() {
		select {
		case <-time.After(5 * time.Second):
			errs <- errors.New("server timeout waiting for TLS handshake from client")
		case session := <-srv.Sessions:
			session.connectionOpen()
			session.connectionClose()
			session.S.Close()
		}
	}()

	go func() {
		c, err := DialTLS(srv.URL, tlsClientConfig(t))
		if err != nil {
			errs <- fmt.Errorf("expected to open a TLS connection, got err: %v", err)
			return
		}
		defer c.Close()

		if st := c.ConnectionState(); !st.HandshakeComplete {
			errs <- fmt.Errorf("expected to complete a TLS handshake, TLS connection state: %+v", st)
		}

		success <- true
	}()

	select {
	case err := <-errs:
		t.Fatalf("TLS server saw error: %+v", err)
	case <-success:
		return
	}
}

const caCert = `
-----BEGIN CERTIFICATE-----
MIIC0TCCAbmgAwIBAgIUW418AvO6YD2WD5X/coo9geXvauEwDQYJKoZIhvcNAQEL
BQAwEzERMA8GA1UEAwwITXlUZXN0Q0EwHhcNMjIwNDA0MDMxNjIxWhcNMzIwNDAx
MDMxNjIxWjATMREwDwYDVQQDDAhNeVRlc3RDQTCCASIwDQYJKoZIhvcNAQEBBQAD
ggEPADCCAQoCggEBAOU1K7mS1z7U9mdDaxpmaj/JwDjtIquqGv1IE4hi9RU/jkse
2GYUuOf5Viu7LMaKCS4I5qwyXT/yPUviw5b1bjEviNURCmQScvXKJg9/P31JlZPc
RBV6Hnrku7nZeJcDfiAo8YDA3QPdr1uhTjjnIo4x2SYJfKDgBvsLfxXETUkFsECQ
uuBLl3VL8jeU8y9wAg0y4gmcOZUyKPlcr9dsmDKftzkas+Zd4JR6e327U+VvVxv4
hDMQGxx/yirKxMwH2+pwkYOWwOTb1FGi8iVjdAwgjlKsLqUR9eSN2AXW/v41E79h
Sb9uEGeIfscGOrgVfVtVRZWNPDzM1/DpYSpsP2ECAwEAAaMdMBswDAYDVR0TBAUw
AwEB/zALBgNVHQ8EBAMCAQYwDQYJKoZIhvcNAQELBQADggEBAJWlbsQqPQPX/lOF
CUnta6OHpt6OlPnN1lUhvbNQVpt0KdmuHQKwSyGiq6fVDt//2RcxPwCYO9AKUZZn
/T48+4haGFEKLRVQrDX7/CQoGbHwWbbgcNpJiQ3XPhGvUrLy6VoahAYK81D23XT0
b4TobCYY+8ny5qhyQgBZ7Jme2jDk0MXt8yjZFGcyA0fRy54ql1AxIXdx5/yvq2CI
nLGEZQLsYhz/r+4gooIkLOIFD2JKoW9p56T52XiRxmz0tAs4WFW38Z6VrzB48Lpq
dBH0sqzECTVQmX8er1taHa+Tg29tuXyqNkBn0tB9qq7G24SDaQFqpW7+J1kNnAY2
KEcj4Ic=
-----END CERTIFICATE-----
`

const serverCert = `
-----BEGIN CERTIFICATE-----
MIIC8zCCAdugAwIBAgIBATANBgkqhkiG9w0BAQsFADATMREwDwYDVQQDDAhNeVRl
c3RDQTAeFw0yMjA0MDQwMzE2MjFaFw0zMjA0MDEwMzE2MjFaMCUxEjAQBgNVBAMM
CTEyNy4wLjAuMTEPMA0GA1UECgwGc2VydmVyMIIBIjANBgkqhkiG9w0BAQEFAAOC
AQ8AMIIBCgKCAQEArH6lT2bGHiGLaWh+eXLXeAcbXq2bGDyeS1zsRGT/+D6YBzFo
7FAUMbN8iJtjWNBlRRdVyiUJn5TUYHrXdCeoAs5JrdzNefax+3toDu6I+nJG4dO3
nbZ9zo8q7uBZtCi/Oph28CtwQxMjNuf3pHlSSKZG5/br4w6HhgSnuLBxyxpr3CrU
2kdHZGIGjX4sEGJ/aDCKIUem/jEXp5i1n13+p5QmPfZc6KX2+sUmN6todqlZpsEV
WZAYLXshHJvViLMTrCJQ3KfqoF7o4PrwQJoQ3jlNct2ZF68H0Iz/bT/VQfPS+4CL
t71xHhU/mYn+kIt1w0APhCMMkYPOhijmGlDAbwIDAQABo0AwPjAJBgNVHRMEAjAA
MAsGA1UdDwQEAwIFIDATBgNVHSUEDDAKBggrBgEFBQcDATAPBgNVHREECDAGhwR/
AAABMA0GCSqGSIb3DQEBCwUAA4IBAQA8dM07fsOfxU7oVWQN3Aey0g8/wc2eL0ZY
oxxvKJqZjOSamNEiwb+lTTmUGg78wiIpFK4ChpPbMpURcRVrxTJuWRg4qagFWn18
RGNqNVnucFSOPe3e+zZqnjWc22PDbBt4B3agdpJsHq4hpdOdJreAh/7MMrWyFMZI
PZ5WFjThFpeQw+vArYUq6BMD3H86G++gfWlSv0yPxWG+Q44+tfZSyiiM6k0+p3nw
1k0eBIA+BibcZ+dQu0m2Vq7XKxfOeN67LY8aElGNSRmH/YAyo5mSrrvzbbZKpr4/
cn4f79jDcBEtbMeCav0eHXzSwWWpteZvdLOm6rxnHd3jngRPqRj+
-----END CERTIFICATE-----
`

const serverKey = `
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEArH6lT2bGHiGLaWh+eXLXeAcbXq2bGDyeS1zsRGT/+D6YBzFo
7FAUMbN8iJtjWNBlRRdVyiUJn5TUYHrXdCeoAs5JrdzNefax+3toDu6I+nJG4dO3
nbZ9zo8q7uBZtCi/Oph28CtwQxMjNuf3pHlSSKZG5/br4w6HhgSnuLBxyxpr3CrU
2kdHZGIGjX4sEGJ/aDCKIUem/jEXp5i1n13+p5QmPfZc6KX2+sUmN6todqlZpsEV
WZAYLXshHJvViLMTrCJQ3KfqoF7o4PrwQJoQ3jlNct2ZF68H0Iz/bT/VQfPS+4CL
t71xHhU/mYn+kIt1w0APhCMMkYPOhijmGlDAbwIDAQABAoIBAQCFfEw5MfNHBfZ4
z+Bv46tSu00262oGS4LEF1jPZMmhNe84QchMd3vpKljI7lbnN/3mhbRiBl94Gxhu
wSFSRg4CfdkOrrxkEcCSOGHCjF18UksAH3MMnVimLKywxvUkMhQqKCqCmVr6zSiH
KOO/aBOBHQvqHm9U+r1tvNR+XCzzWmz0OavKquXhdTbLyHWeR7rS4mn53Up0hQIe
la8PzWpw+mcNz00UbeeK84tUro4+wGV6aFHh23F+RqpXqW8VNnBS0zVtqYc7x7a8
WGcxlLt1hWeiFgEJUuui2i1YxyHDb3IyhGckVG+lSzTpgjl9Pisl7jjlVBRAkiWw
fRJfWuyBAoGBAOERpoRSpXCBum3T7ZwcD3pWHgNY1za9zqsgZayumlhqvxmia77o
HvXyroj+8DTUZ+NiKn0HnF8Hni/2fhAWs9XPlELM9BENQP5kcJzcBSalUOa23C6V
Iba30BB8I1v8AhYLdCFdpio+aQnd1S4VH4sTRoQjsspOSesxDWa1snJ/AoGBAMQz
VadEoBR8ZHsZjks7JaU2G1h2tdU3hfynD8DPq0SFnbS3NhVphmYAdfbOrea9ilmQ
AyO/TJD6xmK7IELWYNtS4DCqAaQKxfOsS8wF97lJ1/XKDNQND8PfbVwzLF8NcbMT
G15Vq9dkJpiGBe0YYxdjtPtwM+FSriK37YIyidoRAoGAQqGBFKeLBvXBBYa6T38X
LfaUyBTjEfe7WXor36WJWCeyD5rAHzKFB/ciqLgg0OMZJn4HaiB4sMGGmVh2FblC
4Eel8ujOUMYFucpudGHGvJwwiT0VjkzkQD3GwTqfFTpUO8aESOR6rwLvAdbEp/Hk
9r1sIO6Ynb/zrkdFWmTsQW0CgYBvXrhjH2hC2K1s1v/XonZnBoSVPaVPp5nN5cLi
br9IQRRZLZpsox7gLajIdV9vV+39kurFUuSSc1dDWfchGXGXbb7GwOn3hQoCnK3V
3RlWOx10bsHDaLqnM99u87lfJ1GAFft2G+lUdYwXDhS1Fh/Beh6Uj4dTgsxH9uHC
AxAPEQKBgCkOBQBfPg4mZdYKAaNoRvNhJr1XdruQnFsBCdvCm2x8DAkNGme7Ax8H
QYB+jH1eC/uInPUnW3kh7KPqgdGVNbYeZGT1FwuwoJEubR6+rBiRm3HsjBJlR+Tv
RK8SwjKS0ZkCb8eujkyBakXdF2tAY9Du8HODID+CuuxhGD1YsF2q
-----END RSA PRIVATE KEY-----
`

const clientCert = `
-----BEGIN CERTIFICATE-----
MIIC4jCCAcqgAwIBAgIBAjANBgkqhkiG9w0BAQsFADATMREwDwYDVQQDDAhNeVRl
c3RDQTAeFw0yMjA0MDQwMzE2MjFaFw0zMjA0MDEwMzE2MjFaMCUxEjAQBgNVBAMM
CTEyNy4wLjAuMTEPMA0GA1UECgwGY2xpZW50MIIBIjANBgkqhkiG9w0BAQEFAAOC
AQ8AMIIBCgKCAQEAtL3BQX/ubTjO+m4WMDe7OiPquHkyE/G8zHNoFXH/pjcf0iYq
lBWD8+bmoPxzOy2RtRawZIR5ZtHkPH8YZues3nwnnUPYQfUGlqlSc4TOyO7vn0Eq
ufJZCVF3+DWTHaV41K20/cpLuCs308KKVt7XosDmj4iwc1t7NcjS8TFI4/SpBIYg
TzII+RzFXhT3FFXuo5ZkOoti0IyUXxALX/Ba+ubR9vrJC4BS7VtoSQQ/uRr5x9MB
/yZWUDTcOOJNjh1mKe+9vEFAjCgRFOwaZzph38Av/L2e4uPTsjTX6MsMQZK1nl5h
03HoQZ3FRJLVKTHVszihIODgNQ5ReM3YBxrqiwIDAQABoy8wLTAJBgNVHRMEAjAA
MAsGA1UdDwQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAjANBgkqhkiG9w0BAQsF
AAOCAQEAxMJjHzZ6BiSwzieH+Ujz70fU+qa4xdoY8tt32gnBJt9d+dsgjaAIeGZR
veAA3Ak0aM+1zoCGc2792oEv7gOz946brbkJLNC5e43ZlDFHYbj1OYcMtxL4CCyW
2QImY/CgoXfVkth1SSRl+wGEwMlS8XuriczwU4Sl/faJHE+mwwJNlNBNKjv1GoUb
0T3lnfuUNoXzH1SstR/6+/eD0CNvTsTvkC9eXJULt2V93jTFNGlM6KcVvF5E7BDm
iSYtaQ8vtPF64LKM+dF3ymzJDoT6EyYU6t1X5RPQ6fQTRbCvZ74NsWoqWzA4VB20
rgNKRkWBHGxKqNMrF1YQvm2hWxw6pA==
-----END CERTIFICATE-----
`

const clientKey = `
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAtL3BQX/ubTjO+m4WMDe7OiPquHkyE/G8zHNoFXH/pjcf0iYq
lBWD8+bmoPxzOy2RtRawZIR5ZtHkPH8YZues3nwnnUPYQfUGlqlSc4TOyO7vn0Eq
ufJZCVF3+DWTHaV41K20/cpLuCs308KKVt7XosDmj4iwc1t7NcjS8TFI4/SpBIYg
TzII+RzFXhT3FFXuo5ZkOoti0IyUXxALX/Ba+ubR9vrJC4BS7VtoSQQ/uRr5x9MB
/yZWUDTcOOJNjh1mKe+9vEFAjCgRFOwaZzph38Av/L2e4uPTsjTX6MsMQZK1nl5h
03HoQZ3FRJLVKTHVszihIODgNQ5ReM3YBxrqiwIDAQABAoIBAQCmfc2R2pj1P8lZ
4yLJU+1CB2fmeq3otVvnMcAFUTfgExNa8BF0y8T7Xg3A6gvzzWxVVgsy7N0wG9SU
7ba6xFr3r4KGWcLSLzXcfykWhJY/fep51vvWwinGbaeHm0JjotQFheYdisXpZtZM
WP46O5iDshIw0gdInFKJHu9BgtbUNDRAAI9xsmDcITSXf7ZblH5CCLJ6QLFn1Olg
O11k6ABYmIxKSXfLylFDzUxfnGhXkrv8/sQwj3B7XxBYVoAF24uw2ufZ+qIlcxUy
m/T/IU1lOLNmfWwDk2+t7zslOpXAEZtrni7u2GF54wIbMr/Z0unGC1B0AUXDwp8y
MNODQdcBAoGBAOe+p5neqgoUL8kBlRvp/dp5kIsVPNBN7+vbVYVzeIEBNixfYe9S
0dixQHiJr29sWn/4yC2KkPQewyDVBf7iNXlcXfkjbEjU0cZaMJao4sKki/N/GF64
IpC8HRM1BSvaSnrJZtZ6aWljpvWRa8bGRdQWb397ufChNpstYEALMMZLAoGBAMeo
hGZJcWIEtl1oJIHsKFKf7jwftFidzyy2ShVLX52n3HkbCYMdwg5DIjQ6Vj9GMy8E
AvrcQduhLw4otdPL+X270xX8WKbxRAvlDnGfmOX1+z/lJy2OLi/HpZeUyM6Oe/Uy
ijaGTKOqRSi9xpJOdDR17e/fcYKzvPejNxZcDMTBAoGAeH/VLBfweI8oja8J9lrE
CX7eXsNrPLDZyNziaiKxjPqxTX9HMCbzQGZiLIsDMr+3iwU0KSH830LDmWXK2U6M
GY+iuXHm0zP949Jvo1crmaPvtWvnoxDBwFpgD+Woy7WUtqXUmD9MYmVToiq8TL45
/t6vmS0fcPSSrTt56bMn6GMCgYEAvRDLL8FkaRllR9aSm6VyGavxAWZUdYYa5ZBJ
XxjdFoIauWPtAghv9umDvklv2sMzPNZjrAJfKwfbc2EBrep9+56dKTipCo11jn39
y4MCWuEwZzUsgGsfOYepO31dGpy6rVqKn09Vy7Y1f3sWSv2X9QWnp3rEFqz1yNr6
E2ZfgQECgYA943tAbNFmAZW3WdS82cpM+HXOkKuYkPfFsBq/eoKoi1p0WLtueQZ3
cC39vheaWdRJPI/dKjhgifY6pBcVLzGIf9gD6VKVbIrcx6U3uMULEQb3GqvdIOtU
d5WpU0bwFMa+vYfrlAjngXlDW/tGqK8ietb6n+xW15M1w4mrEFcAng==
-----END RSA PRIVATE KEY-----
`
