Skip to content

Instantly share code, notes, and snippets.

@BhautikChudasama
Created July 20, 2024 11:57
Show Gist options
  • Select an option

  • Save BhautikChudasama/fb264c6f6e683aa09563493fe1e6048a to your computer and use it in GitHub Desktop.

Select an option

Save BhautikChudasama/fb264c6f6e683aa09563493fe1e6048a to your computer and use it in GitHub Desktop.
mTLS and get connection information at server side with RPC
package main
import (
"crypto/tls"
"crypto/x509"
"log"
"net/rpc"
"os"
)
type Args struct {
A, B int
}
func main() {
// Load client's certificate and private key
cert, err := tls.LoadX509KeyPair("/Users/bhautik/workspace/src/ca-cert/certs/client.a.crt", "/Users/bhautik/workspace/src/ca-cert/certs/client.a.key")
if err != nil {
log.Fatal(err)
}
// Load CA certificate
caCert, err := os.ReadFile("/Users/bhautik/workspace/src/ca-cert/certs/ca.crt")
if err != nil {
log.Fatal(err)
}
caCertPool := x509.NewCertPool()
caCertPool.AppendCertsFromPEM(caCert)
// Create TLS configuration
tlsConfig := &tls.Config{
RootCAs: caCertPool,
Certificates: []tls.Certificate{cert},
}
// Connect to server
conn, err := tls.Dial("tcp", "localhost:12345", tlsConfig)
if err != nil {
log.Fatal(err)
}
defer conn.Close()
// Log TLS connection state
state := conn.ConnectionState()
log.Println("Client-side connection state:")
for i, cert := range state.PeerCertificates {
log.Printf("Peer Certificate %d: %s", i+1, cert.Subject)
}
// Create new RPC client
client := rpc.NewClient(conn)
// Perform RPC call
args := Args{A: 7, B: 8}
var reply int
err = client.Call("Arith.Multiply", args, &reply)
if err != nil {
log.Fatal("arith error:", err)
}
log.Printf("Arith: %d*%d=%d", args.A, args.B, reply)
}
package provider_server
import (
"crypto/tls"
"crypto/x509"
"fmt"
"log"
"net"
"net/rpc"
"os"
"..."
"gopkg.in/yaml.v3"
)
type ProviderServer struct {
Config config.ProviderServerConfig
Logger sdklogging.Logger
}
func NewProviderServer(configFilePath string) (*ProviderServer, error) {
return &ProviderServer{}, err
}
type Arith struct {
conn net.Conn
}
func (t *Arith) Multiply(args *Args, reply *int) error {
state, bool := GetTLSState(t.conn)
if !bool {
log.Printf("Connection is not a TLS connection")
return nil
}
for _, v := range state.PeerCertificates {
fmt.Printf("Client certificate: %v\n", v.Subject)
}
*reply = args.A * args.B
return nil
}
type Args struct {
A, B int
}
type ConnWrapper struct {
net.Conn
TLSState tls.ConnectionState
}
func WrapConn(conn net.Conn, tlsState tls.ConnectionState) net.Conn {
return &ConnWrapper{
Conn: conn,
TLSState: tlsState,
}
}
func GetTLSState(conn net.Conn) (tls.ConnectionState, bool) {
if wrapper, ok := conn.(*ConnWrapper); ok {
return wrapper.TLSState, true
}
return tls.ConnectionState{}, false
}
func (ps *ProviderServer) StartRPCServer() error {
cert, err := tls.LoadX509KeyPair("/Users/bhautik/workspace/src/ca-cert/certs/server.crt", "/Users/bhautik/workspace/src/ca-cert/certs/server.key")
if err != nil {
log.Fatal(err)
}
// Load CA certificate
caCert, err := os.ReadFile("/Users/bhautik/workspace/src/ca-cert/certs/ca.crt")
if err != nil {
log.Fatal(err)
}
caCertPool := x509.NewCertPool()
caCertPool.AppendCertsFromPEM(caCert)
tlsConfig := &tls.Config{
Certificates: []tls.Certificate{cert},
ClientCAs: caCertPool,
ClientAuth: tls.RequireAndVerifyClientCert,
VerifyPeerCertificate: func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
// Write logic to verify the client certificate
return nil
},
}
listener, err := tls.Listen("tcp", ":12345", tlsConfig)
if err != nil {
log.Fatal("Listen error:", err)
}
defer listener.Close()
for {
conn, err := listener.Accept()
if err != nil {
log.Printf("Accept error: %v", err)
continue
}
tlsConn, ok := conn.(*tls.Conn)
if !ok {
log.Printf("Connection is not a TLS connection")
conn.Close()
continue
}
if err := tlsConn.Handshake(); err != nil {
continue
}
state := tlsConn.ConnectionState()
wrappedConn := WrapConn(tlsConn, state)
go func() {
arith := &Arith{conn: wrappedConn}
rpc.Register(arith)
rpc.ServeConn(wrappedConn)
}()
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment