mirror of https://github.com/bjdgyc/anylink.git
251 lines
6.0 KiB
Go
251 lines
6.0 KiB
Go
// +build openssl,!js
|
|
|
|
package e2e
|
|
|
|
import (
|
|
"crypto/x509"
|
|
"encoding/pem"
|
|
"errors"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"net"
|
|
"os"
|
|
"os/exec"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/pion/dtls/v2"
|
|
)
|
|
|
|
func serverOpenSSL(c *comm) {
|
|
go func() {
|
|
c.serverMutex.Lock()
|
|
defer c.serverMutex.Unlock()
|
|
|
|
cfg := c.serverConfig
|
|
|
|
// create openssl arguments
|
|
args := []string{
|
|
"s_server",
|
|
"-dtls1_2",
|
|
"-quiet",
|
|
"-verify_quiet",
|
|
"-verify_return_error",
|
|
fmt.Sprintf("-accept=%d", c.serverPort),
|
|
}
|
|
ciphers := ciphersOpenSSL(cfg)
|
|
if ciphers != "" {
|
|
args = append(args, fmt.Sprintf("-cipher=%s", ciphers))
|
|
}
|
|
|
|
// psk arguments
|
|
if cfg.PSK != nil {
|
|
psk, err := cfg.PSK(nil)
|
|
if err != nil {
|
|
c.errChan <- err
|
|
return
|
|
}
|
|
args = append(args, fmt.Sprintf("-psk=%X", psk))
|
|
if len(cfg.PSKIdentityHint) > 0 {
|
|
args = append(args, fmt.Sprintf("-psk_hint=%s", cfg.PSKIdentityHint))
|
|
}
|
|
}
|
|
|
|
// certs arguments
|
|
if len(cfg.Certificates) > 0 {
|
|
// create temporary cert files
|
|
certPEM, keyPEM, err := writeTempPEM(cfg)
|
|
if err != nil {
|
|
c.errChan <- err
|
|
return
|
|
}
|
|
args = append(args,
|
|
fmt.Sprintf("-cert=%s", certPEM),
|
|
fmt.Sprintf("-key=%s", keyPEM))
|
|
defer func() {
|
|
_ = os.Remove(certPEM)
|
|
_ = os.Remove(keyPEM)
|
|
}()
|
|
} else {
|
|
args = append(args, "-nocert")
|
|
}
|
|
|
|
// launch command
|
|
// #nosec G204
|
|
cmd := exec.CommandContext(c.ctx, "openssl", args...)
|
|
var inner net.Conn
|
|
inner, c.serverConn = net.Pipe()
|
|
cmd.Stdin = inner
|
|
cmd.Stdout = inner
|
|
cmd.Stderr = os.Stderr
|
|
if err := cmd.Start(); err != nil {
|
|
c.errChan <- err
|
|
_ = inner.Close()
|
|
return
|
|
}
|
|
|
|
// Ensure that server has started
|
|
time.Sleep(500 * time.Millisecond)
|
|
|
|
c.serverReady <- struct{}{}
|
|
simpleReadWrite(c.errChan, c.serverChan, c.serverConn, c.messageRecvCount)
|
|
}()
|
|
}
|
|
|
|
func clientOpenSSL(c *comm) {
|
|
select {
|
|
case <-c.serverReady:
|
|
// OK
|
|
case <-time.After(time.Second):
|
|
c.errChan <- errors.New("waiting on serverReady err: timeout")
|
|
}
|
|
|
|
c.clientMutex.Lock()
|
|
defer c.clientMutex.Unlock()
|
|
|
|
cfg := c.clientConfig
|
|
|
|
// create openssl arguments
|
|
args := []string{
|
|
"s_client",
|
|
"-dtls1_2",
|
|
"-quiet",
|
|
"-verify_quiet",
|
|
"-verify_return_error",
|
|
"-servername=localhost",
|
|
fmt.Sprintf("-connect=127.0.0.1:%d", c.serverPort),
|
|
}
|
|
ciphers := ciphersOpenSSL(cfg)
|
|
if ciphers != "" {
|
|
args = append(args, fmt.Sprintf("-cipher=%s", ciphers))
|
|
}
|
|
|
|
// psk arguments
|
|
if cfg.PSK != nil {
|
|
psk, err := cfg.PSK(nil)
|
|
if err != nil {
|
|
c.errChan <- err
|
|
return
|
|
}
|
|
args = append(args, fmt.Sprintf("-psk=%X", psk))
|
|
}
|
|
|
|
// certificate arguments
|
|
if len(cfg.Certificates) > 0 {
|
|
// create temporary cert files
|
|
certPEM, keyPEM, err := writeTempPEM(cfg)
|
|
if err != nil {
|
|
c.errChan <- err
|
|
return
|
|
}
|
|
args = append(args, fmt.Sprintf("-CAfile=%s", certPEM))
|
|
defer func() {
|
|
_ = os.Remove(certPEM)
|
|
_ = os.Remove(keyPEM)
|
|
}()
|
|
}
|
|
|
|
// launch command
|
|
// #nosec G204
|
|
cmd := exec.CommandContext(c.ctx, "openssl", args...)
|
|
var inner net.Conn
|
|
inner, c.clientConn = net.Pipe()
|
|
cmd.Stdin = inner
|
|
cmd.Stdout = inner
|
|
cmd.Stderr = os.Stderr
|
|
if err := cmd.Start(); err != nil {
|
|
c.errChan <- err
|
|
_ = inner.Close()
|
|
return
|
|
}
|
|
|
|
simpleReadWrite(c.errChan, c.clientChan, c.clientConn, c.messageRecvCount)
|
|
}
|
|
|
|
func ciphersOpenSSL(cfg *dtls.Config) string {
|
|
// See https://tls.mbed.org/supported-ssl-ciphersuites
|
|
translate := map[dtls.CipherSuiteID]string{
|
|
dtls.TLS_ECDHE_ECDSA_WITH_AES_128_CCM: "ECDHE-ECDSA-AES128-CCM",
|
|
dtls.TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8: "ECDHE-ECDSA-AES128-CCM8",
|
|
dtls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256: "ECDHE-ECDSA-AES128-GCM-SHA256",
|
|
dtls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256: "ECDHE-RSA-AES128-GCM-SHA256",
|
|
|
|
dtls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA: "ECDHE-ECDSA-AES256-SHA",
|
|
dtls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA: "ECDHE-RSA-AES128-SHA",
|
|
|
|
dtls.TLS_PSK_WITH_AES_128_CCM: "PSK-AES128-CCM",
|
|
dtls.TLS_PSK_WITH_AES_128_CCM_8: "PSK-AES128-CCM8",
|
|
dtls.TLS_PSK_WITH_AES_128_GCM_SHA256: "PSK-AES128-GCM-SHA256",
|
|
}
|
|
|
|
var ciphers []string
|
|
for _, c := range cfg.CipherSuites {
|
|
if text, ok := translate[c]; ok {
|
|
ciphers = append(ciphers, text)
|
|
}
|
|
}
|
|
return strings.Join(ciphers, ";")
|
|
}
|
|
|
|
func writeTempPEM(cfg *dtls.Config) (string, string, error) {
|
|
certOut, err := ioutil.TempFile("", "cert.pem")
|
|
if err != nil {
|
|
return "", "", fmt.Errorf("failed to create temporary file: %w", err)
|
|
}
|
|
keyOut, err := ioutil.TempFile("", "key.pem")
|
|
if err != nil {
|
|
return "", "", fmt.Errorf("failed to create temporary file: %w", err)
|
|
}
|
|
|
|
cert := cfg.Certificates[0]
|
|
derBytes := cert.Certificate[0]
|
|
if err = pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes}); err != nil {
|
|
return "", "", fmt.Errorf("failed to write data to cert.pem: %w", err)
|
|
}
|
|
if err = certOut.Close(); err != nil {
|
|
return "", "", fmt.Errorf("error closing cert.pem: %w", err)
|
|
}
|
|
|
|
priv := cert.PrivateKey
|
|
var privBytes []byte
|
|
privBytes, err = x509.MarshalPKCS8PrivateKey(priv)
|
|
if err != nil {
|
|
return "", "", fmt.Errorf("unable to marshal private key: %w", err)
|
|
}
|
|
if err = pem.Encode(keyOut, &pem.Block{Type: "PRIVATE KEY", Bytes: privBytes}); err != nil {
|
|
return "", "", fmt.Errorf("failed to write data to key.pem: %w", err)
|
|
}
|
|
if err = keyOut.Close(); err != nil {
|
|
return "", "", fmt.Errorf("error closing key.pem: %w", err)
|
|
}
|
|
return certOut.Name(), keyOut.Name(), nil
|
|
}
|
|
|
|
func TestPionOpenSSLE2ESimple(t *testing.T) {
|
|
t.Run("OpenSSLServer", func(t *testing.T) {
|
|
testPionE2ESimple(t, serverOpenSSL, clientPion)
|
|
})
|
|
t.Run("OpenSSLClient", func(t *testing.T) {
|
|
testPionE2ESimple(t, serverPion, clientOpenSSL)
|
|
})
|
|
}
|
|
|
|
func TestPionOpenSSLE2ESimplePSK(t *testing.T) {
|
|
t.Run("OpenSSLServer", func(t *testing.T) {
|
|
testPionE2ESimplePSK(t, serverOpenSSL, clientPion)
|
|
})
|
|
t.Run("OpenSSLClient", func(t *testing.T) {
|
|
testPionE2ESimplePSK(t, serverPion, clientOpenSSL)
|
|
})
|
|
}
|
|
|
|
func TestPionOpenSSLE2EMTUs(t *testing.T) {
|
|
t.Run("OpenSSLServer", func(t *testing.T) {
|
|
testPionE2EMTUs(t, serverOpenSSL, clientPion)
|
|
})
|
|
t.Run("OpenSSLClient", func(t *testing.T) {
|
|
testPionE2EMTUs(t, serverPion, clientOpenSSL)
|
|
})
|
|
}
|