Simple test to show TLS over UDS
To run:
go test -v -timeout 1s
The third test hangs (ClientUsesTLS
) at the moment. The output does look like the client has encrypted the data as it got sent to the listner.
module gist | |
go 1.21.9 | |
require github.com/stretchr/testify v1.9.0 | |
require ( | |
github.com/davecgh/go-spew v1.1.1 // indirect | |
github.com/pmezard/go-difflib v1.0.0 // indirect | |
gopkg.in/yaml.v3 v3.0.1 // indirect | |
) |
package main | |
import ( | |
"crypto/tls" | |
"crypto/x509" | |
"net" | |
) | |
func main() { | |
// Code | |
} | |
func getUDS(socketPath string) (net.Listener, error) { | |
return net.Listen("unix", socketPath) | |
} | |
func getUDSClient(socketPath string) (net.Conn, error) { | |
return net.Dial("unix", socketPath) | |
} | |
func getUDSWithTLS(socketPath string) (net.Listener, error) { | |
cert, err := tls.X509KeyPair(LocalhostCert, LocalhostKey) | |
if err != nil { | |
return nil, err | |
} | |
config := tls.Config{Certificates: []tls.Certificate{cert}} | |
// return tls.Listen("unix", socketPath, &config) | |
l, err := getUDS(socketPath) | |
if err != nil { | |
return nil, err | |
} | |
return tls.NewListener(l, &config), nil | |
} | |
func getUDSWithTLSClient(socketPath string) (net.Conn, error) { | |
cert, err := tls.X509KeyPair(LocalhostCert, LocalhostKey) | |
if err != nil { | |
return nil, err | |
} | |
rootCA, err := x509.ParseCertificate(cert.Certificate[0]) | |
if err != nil { | |
return nil, err | |
} | |
certpool := x509.NewCertPool() | |
certpool.AddCert(rootCA) | |
config := tls.Config{RootCAs: certpool, InsecureSkipVerify: true} | |
con, err := getUDSClient(socketPath) | |
if err != nil { | |
return nil, err | |
} | |
return tls.Client(con, &config), nil | |
} |
package main | |
import ( | |
"net" | |
"path/filepath" | |
"sync" | |
"testing" | |
"github.com/stretchr/testify/require" | |
) | |
func TestUDSCLientsAndServer(t *testing.T) { | |
tests := []struct { | |
name string | |
getClient func(socketPath string) (net.Conn, error) | |
getListener func(socketPath string) (net.Listener, error) | |
}{ | |
{ | |
name: "UDSwithTLS", | |
getClient: getUDSWithTLSClient, | |
getListener: getUDSWithTLS, | |
}, | |
{ | |
name: "UDS", | |
getClient: getUDSClient, | |
getListener: getUDS, | |
}, | |
{ | |
name: "ClientUsesTLS", | |
getClient: getUDSWithTLSClient, | |
getListener: getUDS, | |
}, | |
} | |
for _, tt := range tests { | |
t.Run(tt.name, func(t *testing.T) { | |
tmpSocket := filepath.Join(t.TempDir(), "test.sock") | |
t.Log("socket:", tmpSocket) | |
l, err := tt.getListener(tmpSocket) | |
require.NoError(t, err) | |
result := make(chan string) | |
go func() { | |
conn, err := l.Accept() | |
require.NoError(t, err) | |
defer conn.Close() | |
buf := make([]byte, 512) | |
nr, err := conn.Read(buf) | |
require.NoError(t, err) | |
out := string(buf[0:nr]) | |
t.Log("out was:", out) | |
result <- string(out) | |
}() | |
c, err := tt.getClient(tmpSocket) | |
require.NoError(t, err) | |
defer c.Close() | |
var wg sync.WaitGroup | |
wg.Add(1) | |
go func() { | |
_, err := c.Write([]byte("hi\n")) | |
require.NoError(t, err) | |
wg.Done() | |
}() | |
wg.Wait() | |
actual := <-result | |
require.Equal(t, "hi\n", actual) | |
}) | |
} | |
} |
package main | |
import "strings" | |
// LocalhostCert is a PEM-encoded TLS cert with SAN IPs | |
// "127.0.0.1" and "[::1]", expiring at Jan 29 16:00:00 2084 GMT. | |
// generated from src/crypto/tls: | |
// go run generate_cert.go --rsa-bits 2048 --host 127.0.0.1,::1,example.com --ca --start-date "Jan 1 00:00:00 1970" --duration=1000000h | |
var LocalhostCert = []byte(`-----BEGIN CERTIFICATE----- | |
MIIDOTCCAiGgAwIBAgIQSRJrEpBGFc7tNb1fb5pKFzANBgkqhkiG9w0BAQsFADAS | |
MRAwDgYDVQQKEwdBY21lIENvMCAXDTcwMDEwMTAwMDAwMFoYDzIwODQwMTI5MTYw | |
MDAwWjASMRAwDgYDVQQKEwdBY21lIENvMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A | |
MIIBCgKCAQEA6Gba5tHV1dAKouAaXO3/ebDUU4rvwCUg/CNaJ2PT5xLD4N1Vcb8r | |
bFSW2HXKq+MPfVdwIKR/1DczEoAGf/JWQTW7EgzlXrCd3rlajEX2D73faWJekD0U | |
aUgz5vtrTXZ90BQL7WvRICd7FlEZ6FPOcPlumiyNmzUqtwGhO+9ad1W5BqJaRI6P | |
YfouNkwR6Na4TzSj5BrqUfP0FwDizKSJ0XXmh8g8G9mtwxOSN3Ru1QFc61Xyeluk | |
POGKBV/q6RBNklTNe0gI8usUMlYyoC7ytppNMW7X2vodAelSu25jgx2anj9fDVZu | |
h7AXF5+4nJS4AAt0n1lNY7nGSsdZas8PbQIDAQABo4GIMIGFMA4GA1UdDwEB/wQE | |
AwICpDATBgNVHSUEDDAKBggrBgEFBQcDATAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud | |
DgQWBBStsdjh3/JCXXYlQryOrL4Sh7BW5TAuBgNVHREEJzAlggtleGFtcGxlLmNv | |
bYcEfwAAAYcQAAAAAAAAAAAAAAAAAAAAATANBgkqhkiG9w0BAQsFAAOCAQEAxWGI | |
5NhpF3nwwy/4yB4i/CwwSpLrWUa70NyhvprUBC50PxiXav1TeDzwzLx/o5HyNwsv | |
cxv3HdkLW59i/0SlJSrNnWdfZ19oTcS+6PtLoVyISgtyN6DpkKpdG1cOkW3Cy2P2 | |
+tK/tKHRP1Y/Ra0RiDpOAmqn0gCOFGz8+lqDIor/T7MTpibL3IxqWfPrvfVRHL3B | |
grw/ZQTTIVjjh4JBSW3WyWgNo/ikC1lrVxzl4iPUGptxT36Cr7Zk2Bsg0XqwbOvK | |
5d+NTDREkSnUbie4GeutujmX3Dsx88UiV6UY/4lHJa6I5leHUNOHahRbpbWeOfs/ | |
WkBKOclmOV2xlTVuPw== | |
-----END CERTIFICATE-----`) | |
// LocalhostKey is the private key for LocalhostCert. | |
var LocalhostKey = []byte(testingKey(`-----BEGIN RSA TESTING KEY----- | |
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDoZtrm0dXV0Aqi | |
4Bpc7f95sNRTiu/AJSD8I1onY9PnEsPg3VVxvytsVJbYdcqr4w99V3AgpH/UNzMS | |
gAZ/8lZBNbsSDOVesJ3euVqMRfYPvd9pYl6QPRRpSDPm+2tNdn3QFAvta9EgJ3sW | |
URnoU85w+W6aLI2bNSq3AaE771p3VbkGolpEjo9h+i42TBHo1rhPNKPkGupR8/QX | |
AOLMpInRdeaHyDwb2a3DE5I3dG7VAVzrVfJ6W6Q84YoFX+rpEE2SVM17SAjy6xQy | |
VjKgLvK2mk0xbtfa+h0B6VK7bmODHZqeP18NVm6HsBcXn7iclLgAC3SfWU1jucZK | |
x1lqzw9tAgMBAAECggEABWzxS1Y2wckblnXY57Z+sl6YdmLV+gxj2r8Qib7g4ZIk | |
lIlWR1OJNfw7kU4eryib4fc6nOh6O4AWZyYqAK6tqNQSS/eVG0LQTLTTEldHyVJL | |
dvBe+MsUQOj4nTndZW+QvFzbcm2D8lY5n2nBSxU5ypVoKZ1EqQzytFcLZpTN7d89 | |
EPj0qDyrV4NZlWAwL1AygCwnlwhMQjXEalVF1ylXwU3QzyZ/6MgvF6d3SSUlh+sq | |
XefuyigXw484cQQgbzopv6niMOmGP3of+yV4JQqUSb3IDmmT68XjGd2Dkxl4iPki | |
6ZwXf3CCi+c+i/zVEcufgZ3SLf8D99kUGE7v7fZ6AQKBgQD1ZX3RAla9hIhxCf+O | |
3D+I1j2LMrdjAh0ZKKqwMR4JnHX3mjQI6LwqIctPWTU8wYFECSh9klEclSdCa64s | |
uI/GNpcqPXejd0cAAdqHEEeG5sHMDt0oFSurL4lyud0GtZvwlzLuwEweuDtvT9cJ | |
Wfvl86uyO36IW8JdvUprYDctrQKBgQDycZ697qutBieZlGkHpnYWUAeImVA878sJ | |
w44NuXHvMxBPz+lbJGAg8Cn8fcxNAPqHIraK+kx3po8cZGQywKHUWsxi23ozHoxo | |
+bGqeQb9U661TnfdDspIXia+xilZt3mm5BPzOUuRqlh4Y9SOBpSWRmEhyw76w4ZP | |
OPxjWYAgwQKBgA/FehSYxeJgRjSdo+MWnK66tjHgDJE8bYpUZsP0JC4R9DL5oiaA | |
brd2fI6Y+SbyeNBallObt8LSgzdtnEAbjIH8uDJqyOmknNePRvAvR6mP4xyuR+Bv | |
m+Lgp0DMWTw5J9CKpydZDItc49T/mJ5tPhdFVd+am0NAQnmr1MCZ6nHxAoGABS3Y | |
LkaC9FdFUUqSU8+Chkd/YbOkuyiENdkvl6t2e52jo5DVc1T7mLiIrRQi4SI8N9bN | |
/3oJWCT+uaSLX2ouCtNFunblzWHBrhxnZzTeqVq4SLc8aESAnbslKL4i8/+vYZlN | |
s8xtiNcSvL+lMsOBORSXzpj/4Ot8WwTkn1qyGgECgYBKNTypzAHeLE6yVadFp3nQ | |
Ckq9yzvP/ib05rvgbvrne00YeOxqJ9gtTrzgh7koqJyX1L4NwdkEza4ilDWpucn0 | |
xiUZS4SoaJq6ZvcBYS62Yr1t8n09iG47YL8ibgtmH3L+svaotvpVxVK+d7BLevA/ | |
ZboOWVe3icTy64BT3OQhmg== | |
-----END RSA TESTING KEY-----`)) | |
func testingKey(s string) string { return strings.ReplaceAll(s, "TESTING KEY", "PRIVATE KEY") } |